audio-inspect
Version:
Lightweight yet powerful audio analysis library
2 lines (1 loc) • 4.64 kB
JavaScript
var s=class l extends Error{name="AudioInspectError";code;cause;details;constructor(e,t,r,a){super(t,{cause:r}),this.code=e,this.cause=r,this.details=a,Error.captureStackTrace&&Error.captureStackTrace(this,l)}};function x(l,e){let t=new Float32Array(l/2+1),r=e/l;for(let a=0;a<t.length;a++)t[a]=a*r;return t}var h=class{constructor(e,t,r=!1){this.size=e;this.sampleRate=t;this.enableProfiling=r;this.complexInput=new Float32Array(this.size*2),this.frequencyBins=x(this.size,this.sampleRate),this.initializationPromise=this.initializeWebFFT()}fftInstance=null;initializationPromise=null;complexInput;frequencyBins;get name(){return"WebFFT"}async waitForInitialization(){this.initializationPromise&&await this.initializationPromise}async initializeWebFFT(){try{let t=(await import("webfft")).default;this.fftInstance=new t(this.size),this.enableProfiling&&this.fftInstance?.profile&&await this.fftInstance.profile()}catch(e){throw new s("UNSUPPORTED_FORMAT",`Failed to initialize WebFFT: ${e instanceof Error?e.message:String(e)}`)}}async fft(e){if(this.initializationPromise&&await this.initializationPromise,!this.fftInstance)throw new s("UNSUPPORTED_FORMAT","WebFFT initialization failed");if(e.length!==this.size)throw new s("INVALID_INPUT",`Invalid input size. Expected: ${this.size}, Actual: ${e.length}`);for(let n=0;n<this.size;n++)this.complexInput[n*2]=e[n],this.complexInput[n*2+1]=0;let t=this.fftInstance.fft(this.complexInput),r=new Float32Array(this.size/2+1),a=new Float32Array(this.size/2+1);for(let n=0;n<r.length;n++){let u=t[n*2],i=t[n*2+1];r[n]=Math.sqrt(u*u+i*i),a[n]=Math.atan2(i,u)}return{complex:t,magnitude:r,phase:a,frequencies:this.frequencyBins}}async profile(){if(this.initializationPromise&&await this.initializationPromise,!this.fftInstance||!this.fftInstance.profile)throw new s("UNSUPPORTED_FORMAT","WebFFT is not initialized");await this.fftInstance.profile()}dispose(){if(this.fftInstance)try{this.fftInstance.dispose&&this.fftInstance.dispose()}catch(e){console.warn("FFT instance disposal failed:",e)}finally{this.fftInstance=null,this.initializationPromise=null}}},F=class{constructor(e,t){this.size=e;this.sampleRate=t;if(!this.isPowerOfTwo(e))throw new s("INVALID_INPUT","FFT size must be a power of two");this.precomputeTables()}bitReversalTable;twiddleFactorsReal;twiddleFactorsImag;scratchReal;scratchImag;frequencyBins;get name(){return"Native FFT (Cooley-Tukey)"}isPowerOfTwo(e){return e>0&&(e&e-1)===0}precomputeTables(){this.bitReversalTable=new Uint32Array(this.size);let e=Math.log2(this.size);for(let r=0;r<this.size;r++){let a=0;for(let n=0;n<e;n++)a=a<<1|r>>n&1;this.bitReversalTable[r]=a}let t=this.size/2;this.twiddleFactorsReal=new Float32Array(t),this.twiddleFactorsImag=new Float32Array(t);for(let r=0;r<t;r++){let a=-2*Math.PI*r/this.size;this.twiddleFactorsReal[r]=Math.cos(a),this.twiddleFactorsImag[r]=Math.sin(a)}this.scratchReal=new Float32Array(this.size),this.scratchImag=new Float32Array(this.size),this.frequencyBins=x(this.size,this.sampleRate)}fft(e){if(e.length!==this.size)throw new s("INVALID_INPUT",`Invalid input size. Expected: ${this.size}, Actual: ${e.length}`);let t=this.scratchReal,r=this.scratchImag;for(let i=0;i<this.size;i++){let o=this.bitReversalTable[i];t[o]=e[i],r[o]=0}for(let i=1;i<this.size;i*=2){let o=i*2,c=this.size/o;for(let p=0;p<this.size;p+=o)for(let m=0;m<i;m++){let y=m*c,A=this.twiddleFactorsReal[y],b=this.twiddleFactorsImag[y],d=p+m,f=p+m+i,w=t[d],R=r[d],I=t[f],T=r[f],g=I*A-T*b,P=I*b+T*A;t[d]=w+g,r[d]=R+P,t[f]=w-g,r[f]=R-P}}let a=new Float32Array(this.size*2),n=new Float32Array(this.size/2+1),u=new Float32Array(this.size/2+1);for(let i=0;i<this.size;i++)if(a[i*2]=t[i],a[i*2+1]=r[i],i<=this.size/2){let o=t[i],c=r[i];n[i]=Math.sqrt(o*o+c*c),u[i]=Math.atan2(c,o)}return{complex:a,magnitude:n,phase:u,frequencies:this.frequencyBins}}dispose(){this.scratchReal=new Float32Array(0),this.scratchImag=new Float32Array(0),this.bitReversalTable=new Uint32Array(0),this.twiddleFactorsReal=new Float32Array(0),this.twiddleFactorsImag=new Float32Array(0),this.frequencyBins=new Float32Array(0)}},v=class{static async createProvider(e){switch(e.type){case"webfft":{let t=new h(e.fftSize,e.sampleRate,e.enableProfiling);return await t.waitForInitialization(),t}case"native":return new F(e.fftSize,e.sampleRate);case"custom":if(!e.customProvider)throw new s("INVALID_INPUT","Custom provider is not specified");return e.customProvider;default:{let t=e.type;throw new s("UNSUPPORTED_FORMAT",`Unsupported FFT provider: ${String(t)}`)}}}static getAvailableProviders(){return["webfft","native"]}};export{v as FFTProviderFactory,F as NativeFFTProvider};