audio-inspect
Version:
Lightweight yet powerful audio analysis library
2 lines (1 loc) • 9.64 kB
JavaScript
"use strict";var X=Object.create;var z=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty;var ne=(t,e)=>{for(var n in e)z(t,n,{get:e[n],enumerable:!0})},B=(t,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Z(e))!te.call(t,o)&&o!==n&&z(t,o,{get:()=>e[o],enumerable:!(a=Y(e,o))||a.enumerable});return t};var re=(t,e,n)=>(n=t!=null?X(ee(t)):{},B(e||!t||!t.__esModule?z(n,"default",{value:t,enumerable:!0}):n,t)),ae=t=>B(z({},"__esModule",{value:!0}),t);var me={};ne(me,{getStereoAnalysis:()=>ue,getTimeVaryingStereoAnalysis:()=>fe});module.exports=ae(me);var u=class t extends Error{constructor(n,a,o,s){super(a,{cause:o});this.code=n;this.details=s;this.cause=o,Error.captureStackTrace&&Error.captureStackTrace(this,t)}name="AudioInspectError";timestamp=new Date;cause;toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,timestamp:this.timestamp,stack:this.stack,cause:this.cause}}};var _=class{constructor(e,n,a=!1){this.size=e;this.sampleRate=n;this.enableProfiling=a;this.initializationPromise=this.initializeWebFFT()}fftInstance=null;initializationPromise=null;get name(){return"WebFFT"}async waitForInitialization(){this.initializationPromise&&await this.initializationPromise}async initializeWebFFT(){try{let n=(await import("webfft")).default;this.fftInstance=new n(this.size),this.enableProfiling&&this.fftInstance?.profile&&await this.fftInstance.profile()}catch(e){throw new u("UNSUPPORTED_FORMAT",`WebFFT\u306E\u521D\u671F\u5316\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${e instanceof Error?e.message:String(e)}`)}}async fft(e){if(this.initializationPromise&&await this.initializationPromise,!this.fftInstance)throw new u("UNSUPPORTED_FORMAT","WebFFT initialization failed");if(e.length!==this.size)throw new u("INVALID_INPUT",`\u5165\u529B\u30B5\u30A4\u30BA\u304C\u4E0D\u6B63\u3067\u3059\u3002\u671F\u5F85\u5024: ${this.size}, \u5B9F\u969B: ${e.length}`);let n=new Float32Array(this.size*2);for(let i=0;i<this.size;i++)n[i*2]=e[i]||0,n[i*2+1]=0;let a=this.fftInstance.fft(n),o=new Float32Array(this.size/2+1),s=new Float32Array(this.size/2+1),l=new Float32Array(this.size/2+1);for(let i=0;i<o.length;i++){let r=a[i*2]||0,c=a[i*2+1]||0;o[i]=Math.sqrt(r*r+c*c),s[i]=Math.atan2(c,r),l[i]=i*this.sampleRate/this.size}return{complex:a,magnitude:o,phase:s,frequencies:l}}async profile(){if(this.initializationPromise&&await this.initializationPromise,!this.fftInstance||!this.fftInstance.profile)throw new u("UNSUPPORTED_FORMAT","WebFFT\u304C\u521D\u671F\u5316\u3055\u308C\u3066\u3044\u307E\u305B\u3093");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}}},k=class{constructor(e,n){this.size=e;this.sampleRate=n;if(!this.isPowerOfTwo(e))throw new u("INVALID_INPUT","FFT\u30B5\u30A4\u30BA\u306F2\u306E\u51AA\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");this.precomputeTables()}bitReversalTable;twiddleFactorsReal;twiddleFactorsImag;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 a=0;a<this.size;a++){let o=0;for(let s=0;s<e;s++)o=o<<1|a>>s&1;this.bitReversalTable[a]=o}let n=this.size/2;this.twiddleFactorsReal=new Float32Array(n),this.twiddleFactorsImag=new Float32Array(n);for(let a=0;a<n;a++){let o=-2*Math.PI*a/this.size;this.twiddleFactorsReal[a]=Math.cos(o),this.twiddleFactorsImag[a]=Math.sin(o)}}fft(e){if(e.length!==this.size)throw new u("INVALID_INPUT",`\u5165\u529B\u30B5\u30A4\u30BA\u304C\u4E0D\u6B63\u3067\u3059\u3002\u671F\u5F85\u5024: ${this.size}, \u5B9F\u969B: ${e.length}`);let n=new Float32Array(this.size),a=new Float32Array(this.size);for(let r=0;r<this.size;r++){let c=this.bitReversalTable[r];c!==void 0&&(n[c]=e[r]||0,a[c]=0)}for(let r=1;r<this.size;r*=2){let c=r*2,p=this.size/c;for(let h=0;h<this.size;h+=c)for(let f=0;f<r;f++){let y=f*p,F=this.twiddleFactorsReal[y]||0,I=this.twiddleFactorsImag[y]||0,A=h+f,g=h+f+r,v=n[A]||0,R=a[A]||0,P=n[g]||0,M=a[g]||0,q=P*F-M*I,S=P*I+M*F;n[A]=v+q,a[A]=R+S,n[g]=v-q,a[g]=R-S}}let o=new Float32Array(this.size*2),s=new Float32Array(this.size/2+1),l=new Float32Array(this.size/2+1),i=new Float32Array(this.size/2+1);for(let r=0;r<this.size;r++)if(o[r*2]=n[r]||0,o[r*2+1]=a[r]||0,r<=this.size/2){let c=n[r]||0,p=a[r]||0;s[r]=Math.sqrt(c*c+p*p),l[r]=Math.atan2(p,c),i[r]=r*this.sampleRate/this.size}return{complex:o,magnitude:s,phase:l,frequencies:i}}dispose(){}},C=class{static async createProvider(e){switch(e.type){case"webfft":{let n=new _(e.fftSize,e.sampleRate,e.enableProfiling);return await n.waitForInitialization(),n}case"native":return new k(e.fftSize,e.sampleRate);case"custom":if(!e.customProvider)throw new u("INVALID_INPUT","\u30AB\u30B9\u30BF\u30E0\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093");return e.customProvider;default:{let n=e.type;throw new u("UNSUPPORTED_FORMAT",`\u672A\u5BFE\u5FDC\u306EFFT\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC: ${String(n)}`)}}}static getAvailableProviders(){return["webfft","native"]}};function oe(t,e){let n=new Float32Array(t.length),a=t.length;for(let o=0;o<a;o++){let s=1;switch(e){case"hann":s=.5*(1-Math.cos(2*Math.PI*o/(a-1)));break;case"hamming":s=.54-.46*Math.cos(2*Math.PI*o/(a-1));break;case"blackman":s=.42-.5*Math.cos(2*Math.PI*o/(a-1))+.08*Math.cos(4*Math.PI*o/(a-1));break;case"rectangular":default:s=1;break}n[o]=(t[o]||0)*s}return n}function ie(t,e){if(e===-1){let a=new Float32Array(t.length);for(let o=0;o<t.length;o++){let s=0;for(let l=0;l<t.numberOfChannels;l++){let i=t.channelData[l];i&&o<i.length&&(s+=i[o])}a[o]=s/t.numberOfChannels}return a}if(e<-1||e>=t.numberOfChannels)throw new u("INVALID_INPUT",`Invalid channel number: ${e}`);let n=t.channelData[e];if(!n)throw new u("INVALID_INPUT",`Channel ${e} data does not exist`);return n}async function U(t,e={}){let{fftSize:n=2048,windowFunction:a="hann",channel:o=0,provider:s="native",enableProfiling:l=!1}=e,i=ie(t,o),r;i.length<n?(r=new Float32Array(n),r.set(i)):r=i.slice(0,n);let c=oe(r,a),p=s==="webfft"?["webfft","native"]:[s],h,f=null;for(let y of p)try{f=await C.createProvider({type:y,fftSize:n,sampleRate:t.sampleRate,enableProfiling:l});break}catch(F){if(h=F,y==="webfft"&&p.includes("native"))continue}if(!f)throw h||new u("FFT_PROVIDER_ERROR","Failed to create FFT provider");try{return{...await f.fft(c),fftSize:n,windowFunction:a,providerName:f.name}}finally{f.dispose()}}function O(t){return t==null||isNaN(t)||!isFinite(t)?0:t}function se(t,e,n=44){let a=Math.min(t.length,e.length),o=-1/0,s=0;for(let l=-n;l<=n;l++){let i=0,r=0;for(let c=0;c<a;c++){let p=c,h=c+l;if(h>=0&&h<a){let f=O(t[p]??0),y=O(e[h]??0);i+=f*y,r++}}r>0&&(i/=r,i>o&&(o=i,s=l))}return s}async function le(t,e){let n=new Float32Array(t.magnitude.length);for(let a=0;a<n.length;a++){let o=t.magnitude[a]??0,s=e.magnitude[a]??0,l=(t.phase[a]??0)-(e.phase[a]??0),i=o*s*Math.cos(l),r=o*o*s*s;n[a]=r>1e-10?i*i/r:0}return n}function ce(t,e,n,a){let o=new Float32Array(t.length);for(let s=0;s<o.length;s++){let l=t[s]||0,i=e[s]||0,r=n[s]||0,c=a[s]||0,p=r-c,h=Math.abs(l+i)/2,f=Math.abs(l-i)/2,y=Math.abs(Math.sin(p/2)),F=f/(h+f+1e-10);o[s]=Math.max(F,y)}return o}async function ue(t,e={}){if(t.numberOfChannels<2)throw new u("INVALID_INPUT","\u30B9\u30C6\u30EC\u30AA\u89E3\u6790\u306B\u306F2\u30C1\u30E3\u30F3\u30CD\u30EB\u4EE5\u4E0A\u306E\u97F3\u58F0\u304C\u5FC5\u8981\u3067\u3059");let{frameSize:n=Math.min(8192,t.length),calculatePhase:a=!1,calculateITD:o=!1,calculateILD:s=!1}=e,l=t.channelData[0],i=t.channelData[1];if(!l||!i)throw new u("INVALID_INPUT","L/R\u30C1\u30E3\u30F3\u30CD\u30EB\u306E\u30C7\u30FC\u30BF\u304C\u5B58\u5728\u3057\u307E\u305B\u3093");let r=Math.min(l.length,i.length);if(r===0)return{correlation:0,width:0,balance:0,midSideRatio:0};let c=0,p=0,h=0,f=0,y=0,F=0,I=0,A=0,g=0,v=new Float32Array(r),R=new Float32Array(r);for(let m=0;m<r;m++){let b=O(l[m]??0),d=O(i[m]??0);c+=b,p+=d,h+=b*d,f+=b*b,y+=d*d,F+=b*b,I+=d*d;let w=(b+d)*.5,T=(b-d)*.5;A+=w*w,g+=T*T,v[m]=w,R[m]=T}let P=c/r,M=p/r,q=h/r-P*M,S=Math.sqrt(f/r-P*P),L=Math.sqrt(y/r-M*M),V=S>1e-10&&L>1e-10?q/(S*L):0,$=A+g>1e-10?g/(A+g):0,j=F+I>1e-10?(I-F)/(F+I):0,G=g>1e-10?10*Math.log10(A/g):1/0,x={correlation:V,width:$,balance:j,midSideRatio:G};if(x.goniometer={x:R,y:v},a){let m=Math.min(n,r),b=Math.pow(2,Math.ceil(Math.log2(m))),[d,w]=await Promise.all([U({channelData:[l.subarray(0,m)],sampleRate:t.sampleRate,numberOfChannels:1,length:m,duration:m/t.sampleRate},{fftSize:b}),U({channelData:[i.subarray(0,m)],sampleRate:t.sampleRate,numberOfChannels:1,length:m,duration:m/t.sampleRate},{fftSize:b})]);x.coherence=await le(d,w),x.widthFrequency=ce(d.magnitude,w.magnitude,d.phase,w.phase);let T=0,N=0;for(let D=1;D<d.phase.length;D++){let H=d.magnitude[D]||0,K=w.magnitude[D]||0,Q=d.phase[D]||0,J=w.phase[D]||0,W=H*K,E=Q-J;E=(E+Math.PI)%(2*Math.PI)-Math.PI,T+=E*W,N+=W}x.phaseDifference=N>1e-10?T/N*180/Math.PI:0}if(o){let m=se(l.subarray(0,Math.min(n,r)),i.subarray(0,Math.min(n,r)));x.itd=m/t.sampleRate*1e3}if(s){let m=Math.sqrt(F/r),b=Math.sqrt(I/r);x.ild=m>1e-10&&b>1e-10?20*Math.log10(b/m):0}return x}function fe(t,e={}){return Promise.reject(new u("UNSUPPORTED_FORMAT","\u6642\u7CFB\u5217\u30B9\u30C6\u30EC\u30AA\u89E3\u6790\u306F\u5C06\u6765\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u3067\u5B9F\u88C5\u4E88\u5B9A\u3067\u3059"))}