-
Notifications
You must be signed in to change notification settings - Fork 0
/
soundtouch.min.js
8 lines (8 loc) · 14.3 KB
/
soundtouch.min.js
1
2
3
4
5
6
7
8
/**
* Minified by jsDelivr using Terser v5.15.1.
* Original file: /npm/[email protected]/dist/soundtouch.js
*
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/
class FifoSampleBuffer{constructor(){this._vector=new Float32Array,this._position=0,this._frameCount=0}get vector(){return this._vector}get position(){return this._position}get startIndex(){return 2*this._position}get frameCount(){return this._frameCount}get endIndex(){return 2*(this._position+this._frameCount)}clear(){this.receive(this._frameCount),this.rewind()}put(t){this._frameCount+=t}putSamples(t,e,i=0){const s=2*(e=e||0);i>=0||(i=(t.length-s)/2);const r=2*i;this.ensureCapacity(i+this._frameCount);const o=this.endIndex;this.vector.set(t.subarray(s,s+r),o),this._frameCount+=i}putBuffer(t,e,i=0){e=e||0,i>=0||(i=t.frameCount-e),this.putSamples(t.vector,t.position+e,i)}receive(t){t>=0&&!(t>this._frameCount)||(t=this.frameCount),this._frameCount-=t,this._position+=t}receiveSamples(t,e=0){const i=2*e,s=this.startIndex;t.set(this._vector.subarray(s,s+i)),this.receive(e)}extract(t,e=0,i=0){const s=this.startIndex+2*e,r=2*i;t.set(this._vector.subarray(s,s+r))}ensureCapacity(t=0){const e=parseInt(2*t);if(this._vector.length<e){const t=new Float32Array(e);t.set(this._vector.subarray(this.startIndex,this.endIndex)),this._vector=t,this._position=0}else this.rewind()}ensureAdditionalCapacity(t=0){this.ensureCapacity(this._frameCount+t)}rewind(){this._position>0&&(this._vector.set(this._vector.subarray(this.startIndex,this.endIndex)),this._position=0)}}class AbstractFifoSamplePipe{constructor(t){t?(this._inputBuffer=new FifoSampleBuffer,this._outputBuffer=new FifoSampleBuffer):this._inputBuffer=this._outputBuffer=null}get inputBuffer(){return this._inputBuffer}set inputBuffer(t){this._inputBuffer=t}get outputBuffer(){return this._outputBuffer}set outputBuffer(t){this._outputBuffer=t}clear(){this._inputBuffer.clear(),this._outputBuffer.clear()}}class RateTransposer extends AbstractFifoSamplePipe{constructor(t){super(t),this.reset(),this._rate=1}set rate(t){this._rate=t}reset(){this.slopeCount=0,this.prevSampleL=0,this.prevSampleR=0}clone(){const t=new RateTransposer;return t.rate=this._rate,t}process(){const t=this._inputBuffer.frameCount;this._outputBuffer.ensureAdditionalCapacity(t/this._rate+1);const e=this.transpose(t);this._inputBuffer.receive(),this._outputBuffer.put(e)}transpose(t=0){if(0===t)return 0;const e=this._inputBuffer.vector,i=this._inputBuffer.startIndex,s=this._outputBuffer.vector,r=this._outputBuffer.endIndex;let o=0,h=0;for(;this.slopeCount<1;)s[r+2*h]=(1-this.slopeCount)*this.prevSampleL+this.slopeCount*e[i],s[r+2*h+1]=(1-this.slopeCount)*this.prevSampleR+this.slopeCount*e[i+1],h+=1,this.slopeCount+=this._rate;if(this.slopeCount-=1,1!==t)t:for(;;){for(;this.slopeCount>1;)if(this.slopeCount-=1,o+=1,o>=t-1)break t;const n=i+2*o;s[r+2*h]=(1-this.slopeCount)*e[n]+this.slopeCount*e[n+2],s[r+2*h+1]=(1-this.slopeCount)*e[n+1]+this.slopeCount*e[n+3],h+=1,this.slopeCount+=this._rate}return this.prevSampleL=e[i+2*t-2],this.prevSampleR=e[i+2*t-1],h}}class FilterSupport{constructor(t){this._pipe=t}get pipe(){return this._pipe}get inputBuffer(){return this._pipe.inputBuffer}get outputBuffer(){return this._pipe.outputBuffer}fillInputBuffer(){throw new Error("fillInputBuffer() not overridden")}fillOutputBuffer(t=0){for(;this.outputBuffer.frameCount<t;){const t=16384-this.inputBuffer.frameCount;if(this.fillInputBuffer(t),this.inputBuffer.frameCount<16384)break;this._pipe.process()}}clear(){this._pipe.clear()}}const noop=function(){};class SimpleFilter extends FilterSupport{constructor(t,e,i=noop){super(e),this.callback=i,this.sourceSound=t,this.historyBufferSize=22050,this._sourcePosition=0,this.outputBufferPosition=0,this._position=0}get position(){return this._position}set position(t){if(t>this._position)throw new RangeError("New position may not be greater than current position");const e=this.outputBufferPosition-(this._position-t);if(e<0)throw new RangeError("New position falls outside of history buffer");this.outputBufferPosition=e,this._position=t}get sourcePosition(){return this._sourcePosition}set sourcePosition(t){this.clear(),this._sourcePosition=t}onEnd(){this.callback()}fillInputBuffer(t=0){const e=new Float32Array(2*t),i=this.sourceSound.extract(e,t,this._sourcePosition);this._sourcePosition+=i,this.inputBuffer.putSamples(e,0,i)}extract(t,e=0){this.fillOutputBuffer(this.outputBufferPosition+e);const i=Math.min(e,this.outputBuffer.frameCount-this.outputBufferPosition);this.outputBuffer.extract(t,this.outputBufferPosition,i);const s=this.outputBufferPosition+i;return this.outputBufferPosition=Math.min(this.historyBufferSize,s),this.outputBuffer.receive(Math.max(s-this.historyBufferSize,0)),this._position+=i,i}handleSampleData(t){this.extract(t.data,4096)}clear(){super.clear(),this.outputBufferPosition=0}}const USE_AUTO_SEQUENCE_LEN=0,DEFAULT_SEQUENCE_MS=0,USE_AUTO_SEEKWINDOW_LEN=0,DEFAULT_SEEKWINDOW_MS=0,DEFAULT_OVERLAP_MS=8,_SCAN_OFFSETS=[[124,186,248,310,372,434,496,558,620,682,744,806,868,930,992,1054,1116,1178,1240,1302,1364,1426,1488,0],[-100,-75,-50,-25,25,50,75,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[-20,-15,-10,-5,5,10,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[-4,-3,-2,-1,1,2,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],AUTOSEQ_TEMPO_LOW=.5,AUTOSEQ_TEMPO_TOP=2,AUTOSEQ_AT_MIN=125,AUTOSEQ_AT_MAX=50,AUTOSEQ_K=-50,AUTOSEQ_C=150,AUTOSEEK_AT_MIN=25,AUTOSEEK_AT_MAX=15,AUTOSEEK_K=-10/1.5,AUTOSEEK_C=25-.5*AUTOSEEK_K;class Stretch extends AbstractFifoSamplePipe{constructor(t){super(t),this._quickSeek=!0,this.midBufferDirty=!1,this.midBuffer=null,this.overlapLength=0,this.autoSeqSetting=!0,this.autoSeekSetting=!0,this._tempo=1,this.setParameters(44100,0,0,8)}clear(){super.clear(),this.clearMidBuffer()}clearMidBuffer(){this.midBufferDirty&&(this.midBufferDirty=!1,this.midBuffer=null)}setParameters(t,e,i,s){t>0&&(this.sampleRate=t),s>0&&(this.overlapMs=s),e>0?(this.sequenceMs=e,this.autoSeqSetting=!1):this.autoSeqSetting=!0,i>0?(this.seekWindowMs=i,this.autoSeekSetting=!1):this.autoSeekSetting=!0,this.calculateSequenceParameters(),this.calculateOverlapLength(this.overlapMs),this.tempo=this._tempo}set tempo(t){let e;this._tempo=t,this.calculateSequenceParameters(),this.nominalSkip=this._tempo*(this.seekWindowLength-this.overlapLength),this.skipFract=0,e=Math.floor(this.nominalSkip+.5),this.sampleReq=Math.max(e+this.overlapLength,this.seekWindowLength)+this.seekLength}get tempo(){return this._tempo}get inputChunkSize(){return this.sampleReq}get outputChunkSize(){return this.overlapLength+Math.max(0,this.seekWindowLength-2*this.overlapLength)}calculateOverlapLength(t=0){let e;e=this.sampleRate*t/1e3,e=e<16?16:e,e-=e%8,this.overlapLength=e,this.refMidBuffer=new Float32Array(2*this.overlapLength),this.midBuffer=new Float32Array(2*this.overlapLength)}checkLimits(t,e,i){return t<e?e:t>i?i:t}calculateSequenceParameters(){let t,e;this.autoSeqSetting&&(t=150+-50*this._tempo,t=this.checkLimits(t,50,125),this.sequenceMs=Math.floor(t+.5)),this.autoSeekSetting&&(e=AUTOSEEK_C+AUTOSEEK_K*this._tempo,e=this.checkLimits(e,15,25),this.seekWindowMs=Math.floor(e+.5)),this.seekWindowLength=Math.floor(this.sampleRate*this.sequenceMs/1e3),this.seekLength=Math.floor(this.sampleRate*this.seekWindowMs/1e3)}set quickSeek(t){this._quickSeek=t}clone(){const t=new Stretch;return t.tempo=this._tempo,t.setParameters(this.sampleRate,this.sequenceMs,this.seekWindowMs,this.overlapMs),t}seekBestOverlapPosition(){return this._quickSeek?this.seekBestOverlapPositionStereoQuick():this.seekBestOverlapPositionStereo()}seekBestOverlapPositionStereo(){let t,e,i,s=0;for(this.preCalculateCorrelationReferenceStereo(),t=0,e=Number.MIN_VALUE;s<this.seekLength;s+=1)i=this.calculateCrossCorrelationStereo(2*s,this.refMidBuffer),i>e&&(e=i,t=s);return t}seekBestOverlapPositionStereoQuick(){let t,e,i,s,r,o=0;for(this.preCalculateCorrelationReferenceStereo(),e=Number.MIN_VALUE,t=0,s=0,r=0;o<4;o+=1){let h=0;for(;_SCAN_OFFSETS[o][h]&&(r=s+_SCAN_OFFSETS[o][h],!(r>=this.seekLength));)i=this.calculateCrossCorrelationStereo(2*r,this.refMidBuffer),i>e&&(e=i,t=r),h+=1;s=t}return t}preCalculateCorrelationReferenceStereo(){let t,e,i=0;for(;i<this.overlapLength;i+=1)e=i*(this.overlapLength-i),t=2*i,this.refMidBuffer[t]=this.midBuffer[t]*e,this.refMidBuffer[t+1]=this.midBuffer[t+1]*e}calculateCrossCorrelationStereo(t,e){const i=this._inputBuffer.vector;t+=this._inputBuffer.startIndex;let s=0,r=2;const o=2*this.overlapLength;let h;for(;r<o;r+=2)h=r+t,s+=i[h]*e[r]+i[h+1]*e[r+1];return s}overlap(t){this.overlapStereo(2*t)}overlapStereo(t){const e=this._inputBuffer.vector;t+=this._inputBuffer.startIndex;const i=this._outputBuffer.vector,s=this._outputBuffer.endIndex;let r,o,h=0;const n=1/this.overlapLength;let u,a,f;for(;h<this.overlapLength;h+=1)o=(this.overlapLength-h)*n,u=h*n,r=2*h,a=r+t,f=r+s,i[f+0]=e[a+0]*u+this.midBuffer[r+0]*o,i[f+1]=e[a+1]*u+this.midBuffer[r+1]*o}process(){let t,e,i;if(null===this.midBuffer){if(this._inputBuffer.frameCount<this.overlapLength)return;this.midBuffer=new Float32Array(2*this.overlapLength),this._inputBuffer.receiveSamples(this.midBuffer,this.overlapLength)}for(;this._inputBuffer.frameCount>=this.sampleReq;){t=this.seekBestOverlapPosition(),this._outputBuffer.ensureAdditionalCapacity(this.overlapLength),this.overlap(Math.floor(t)),this._outputBuffer.put(this.overlapLength),e=this.seekWindowLength-2*this.overlapLength,e>0&&this._outputBuffer.putBuffer(this._inputBuffer,t+this.overlapLength,e);const s=this._inputBuffer.startIndex+2*(t+this.seekWindowLength-this.overlapLength);this.midBuffer.set(this._inputBuffer.vector.subarray(s,s+2*this.overlapLength)),this.skipFract+=this.nominalSkip,i=Math.floor(this.skipFract),this.skipFract-=i,this._inputBuffer.receive(i)}}}const testFloatEqual=function(t,e){return(t>e?t-e:e-t)>1e-10};class SoundTouch{constructor(){this.transposer=new RateTransposer(!1),this.stretch=new Stretch(!1),this._inputBuffer=new FifoSampleBuffer,this._intermediateBuffer=new FifoSampleBuffer,this._outputBuffer=new FifoSampleBuffer,this._rate=0,this._tempo=0,this.virtualPitch=1,this.virtualRate=1,this.virtualTempo=1,this.calculateEffectiveRateAndTempo()}clear(){this.transposer.clear(),this.stretch.clear()}clone(){const t=new SoundTouch;return t.rate=this.rate,t.tempo=this.tempo,t}get rate(){return this._rate}set rate(t){this.virtualRate=t,this.calculateEffectiveRateAndTempo()}set rateChange(t){this._rate=1+.01*t}get tempo(){return this._tempo}set tempo(t){this.virtualTempo=t,this.calculateEffectiveRateAndTempo()}set tempoChange(t){this.tempo=1+.01*t}set pitch(t){this.virtualPitch=t,this.calculateEffectiveRateAndTempo()}set pitchOctaves(t){this.pitch=Math.exp(.69314718056*t),this.calculateEffectiveRateAndTempo()}set pitchSemitones(t){this.pitchOctaves=t/12}get inputBuffer(){return this._inputBuffer}get outputBuffer(){return this._outputBuffer}calculateEffectiveRateAndTempo(){const t=this._tempo,e=this._rate;this._tempo=this.virtualTempo/this.virtualPitch,this._rate=this.virtualRate*this.virtualPitch,testFloatEqual(this._tempo,t)&&(this.stretch.tempo=this._tempo),testFloatEqual(this._rate,e)&&(this.transposer.rate=this._rate),this._rate>1?this._outputBuffer!=this.transposer.outputBuffer&&(this.stretch.inputBuffer=this._inputBuffer,this.stretch.outputBuffer=this._intermediateBuffer,this.transposer.inputBuffer=this._intermediateBuffer,this.transposer.outputBuffer=this._outputBuffer):this._outputBuffer!=this.stretch.outputBuffer&&(this.transposer.inputBuffer=this._inputBuffer,this.transposer.outputBuffer=this._intermediateBuffer,this.stretch.inputBuffer=this._intermediateBuffer,this.stretch.outputBuffer=this._outputBuffer)}process(){this._rate>1?(this.stretch.process(),this.transposer.process()):(this.transposer.process(),this.stretch.process())}}class WebAudioBufferSource{constructor(t){this.buffer=t,this._position=0}get dualChannel(){return this.buffer.numberOfChannels>1}get position(){return this._position}set position(t){this._position=t}extract(t,e=0,i=0){this.position=i;let s=this.buffer.getChannelData(0),r=this.dualChannel?this.buffer.getChannelData(1):this.buffer.getChannelData(0),o=0;for(;o<e;o++)t[2*o]=s[o+i],t[2*o+1]=r[o+i];return Math.min(e,s.length-i)}}const getWebAudioNode=function(t,e,i=noop,s=4096){const r=t.createScriptProcessor(s,2,2),o=new Float32Array(2*s);return r.onaudioprocess=t=>{let r=t.outputBuffer.getChannelData(0),h=t.outputBuffer.getChannelData(1),n=e.extract(o,s);i(e.sourcePosition),0===n&&e.onEnd();let u=0;for(;u<n;u++)r[u]=o[2*u],h[u]=o[2*u+1]},r},pad=function(t,e,i){return i=i||"0",(t+="").length>=e?t:new Array(e-t.length+1).join(i)+t},minsSecs=function(t){const e=Math.floor(t/60);return`${e}:${i=parseInt(t-60*e),s=2,r=r||"0",(i+="").length>=s?i:new Array(s-i.length+1).join(r)+i}`;var i,s,r},onUpdate=function(t){const e=this.timePlayed,i=this.sampleRate;if(this.sourcePosition=t,this.timePlayed=t/i,e!==this.timePlayed){const t=new CustomEvent("play",{detail:{timePlayed:this.timePlayed,formattedTimePlayed:this.formattedTimePlayed,percentagePlayed:this.percentagePlayed}});this._node.dispatchEvent(t)}};class PitchShifter{constructor(t,e,i,s=noop){this._soundtouch=new SoundTouch;const r=new WebAudioBufferSource(e);this.timePlayed=0,this.sourcePosition=0,this._filter=new SimpleFilter(r,this._soundtouch,s),this._node=getWebAudioNode(t,this._filter,(t=>onUpdate.call(this,t)),i),this.tempo=1,this.rate=1,this.duration=e.duration,this.sampleRate=t.sampleRate,this.listeners=[]}get formattedDuration(){return minsSecs(this.duration)}get formattedTimePlayed(){return minsSecs(this.timePlayed)}get percentagePlayed(){return 100*this._filter.sourcePosition/(this.duration*this.sampleRate)}set percentagePlayed(t){this._filter.sourcePosition=parseInt(t*this.duration*this.sampleRate),this.sourcePosition=this._filter.sourcePosition,this.timePlayed=this.sourcePosition/this.sampleRate}get node(){return this._node}set pitch(t){this._soundtouch.pitch=t}set pitchSemitones(t){this._soundtouch.pitchSemitones=t}set rate(t){this._soundtouch.rate=t}set tempo(t){this._soundtouch.tempo=t}connect(t){this._node.connect(t)}disconnect(){this._node.disconnect()}on(t,e){this.listeners.push({name:t,cb:e}),this._node.addEventListener(t,(t=>e(t.detail)))}off(t=null){let e=this.listeners;t&&(e=e.filter((e=>e.name===t))),e.forEach((t=>{this._node.removeEventListener(t.name,(e=>t.cb(e.detail)))}))}}export{AbstractFifoSamplePipe,PitchShifter,RateTransposer,SimpleFilter,SoundTouch,Stretch,WebAudioBufferSource,getWebAudioNode};
//# sourceMappingURL=/sm/ce93844129eb945237caaa982b3babcb5fd5403f9285309d21deabd284899de6.map