audio-inspect
Version:
Lightweight yet powerful audio analysis library
2 lines • 75.4 kB
JavaScript
// audio-inspect - Lightweight yet powerful audio analysis library
var b=class e extends Error{name="AudioInspectError";code;cause;details;constructor(t,n,r,a){super(n,{cause:r}),this.code=t,this.cause=r,this.details=a,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};function Fn(e){return e instanceof b}function Ue(e){if(e.numberOfChannels<=1)return e;let t=new Float32Array(e.length);for(let n=0;n<e.length;n++){let r=0;for(let a=0;a<e.numberOfChannels;a++){let o=e.channelData[a];o&&(r+=o[n]??0)}t[n]=r/e.numberOfChannels}return{sampleRate:e.sampleRate,channelData:[t],numberOfChannels:1,length:e.length,duration:e.duration}}function Ke(e){if(e.numberOfChannels===2)return e;if(e.numberOfChannels===1){let r=e.channelData[0]??new Float32Array(e.length);return{sampleRate:e.sampleRate,numberOfChannels:2,channelData:[r.slice(),r.slice()],length:e.length,duration:e.duration}}let t=e.channelData[0]??new Float32Array(e.length),n=e.channelData[1]??t;return{sampleRate:e.sampleRate,numberOfChannels:2,channelData:[t.slice(),n.slice()],length:e.length,duration:e.duration}}function $e(e){let t=0;for(let r of e.channelData)for(let a=0;a<r.length;a++)t=Math.max(t,Math.abs(r[a]));if(t<=0||t===1)return e;let n=e.channelData.map(r=>{let a=new Float32Array(r.length);for(let o=0;o<r.length;o++)a[o]=r[o]/t;return a});return{...e,channelData:n}}function je(e,t){if(!Number.isFinite(t)||t<=0)throw new b("INVALID_INPUT","sampleRate must be positive");if(t===e.sampleRate)return e;let n=Math.max(1,Math.floor(e.length*t/e.sampleRate)),r=e.sampleRate/t,a=e.channelData.map(o=>{let i=new Float32Array(n);for(let s=0;s<n;s++){let l=s*r,c=Math.floor(l),u=Math.min(c+1,o.length-1),f=l-c;i[s]=o[c]+(o[u]-o[c])*f}return i});return{sampleRate:t,numberOfChannels:e.numberOfChannels,channelData:a,length:n,duration:n/t}}async function He(e,t,n){if(!Number.isFinite(t)||t<=0)throw new b("INVALID_INPUT","sampleRate must be positive");if(t===e.sampleRate)return e;if(n?.aborted)throw new b("ABORTED","Operation aborted");if(e.numberOfChannels===0||e.length===0)return{sampleRate:t,numberOfChannels:e.numberOfChannels,channelData:e.channelData.map(()=>new Float32Array(0)),length:0,duration:0};if(typeof OfflineAudioContext>"u")throw new b("PROCESSING_ERROR","OfflineAudioContext is not available for high-quality resampling");let r=Math.max(1,Math.round(e.length*t/e.sampleRate)),a=new OfflineAudioContext(e.numberOfChannels,r,t),o=a.createBuffer(e.numberOfChannels,e.length,e.sampleRate);for(let c=0;c<e.numberOfChannels;c++){let u=e.channelData[c]??new Float32Array(e.length);o.copyToChannel(u,c,0)}let i=a.createBufferSource();i.buffer=o,i.connect(a.destination),i.start(0);let s=await a.startRendering();if(n?.aborted)throw new b("ABORTED","Operation aborted");let l=[];for(let c=0;c<s.numberOfChannels;c++)l.push(s.getChannelData(c).slice());return{sampleRate:s.sampleRate,numberOfChannels:s.numberOfChannels,channelData:l,length:s.length,duration:s.duration}}var ae=null;function H(e){if(e?.aborted)throw new b("ABORTED","Operation aborted")}function ye(e){return typeof e=="object"&&e!==null&&"sampleRate"in e&&"channelData"in e&&"duration"in e&&"numberOfChannels"in e&&"length"in e}function yn(e){return typeof AudioBuffer<"u"&&e instanceof AudioBuffer}function Qe(e){return e.sampleRate!==void 0||e.channels!==void 0||e.normalize===!0}function Ge(e){let t=[];for(let n=0;n<e.numberOfChannels;n++)t.push(e.getChannelData(n));return{sampleRate:e.sampleRate,channelData:t,duration:e.duration,numberOfChannels:e.numberOfChannels,length:e.length}}function gn(e){return{sampleRate:e.sampleRate,numberOfChannels:e.numberOfChannels,duration:e.duration,length:e.length,channelData:e.channelData.map(t=>t.slice())}}function bn(e){if(e===void 0)return"high";if(e==="high"||e==="fast")return e;throw new b("INVALID_INPUT","resampleQuality must be 'high' or 'fast'")}async function An(e,t,n){if(bn(n.resampleQuality)==="fast")return je(e,t);if(n.resampler){H(n.signal);let a=await n.resampler(e,t,n.signal?{signal:n.signal}:void 0);return H(n.signal),a}if(Ze()&&typeof OfflineAudioContext<"u")return He(e,t,n.signal);throw new b("PROCESSING_ERROR","High-quality resampling backend is unavailable in this runtime. Provide LoadOptions.resampler or set resampleQuality to 'fast'.")}async function Sn(e,t){let n=e;return t.channels==="mono"||t.channels===1?n=Ue(n):(t.channels==="stereo"||t.channels===2)&&(n=Ke(n)),t.normalize&&(n=$e(n)),t.sampleRate!==void 0&&t.sampleRate!==n.sampleRate&&(n=await An(n,t.sampleRate,t)),n}function wn(){return typeof process<"u"&&!!process.versions?.node}function Ze(){return typeof window<"u"&&typeof document<"u"}function In(){if(typeof AudioContext>"u")throw new b("DECODE_BACKEND_MISSING","AudioContext is not available");return(!ae||ae.state==="closed")&&(ae=new AudioContext),ae}function xn(e){if(e.fetch)return e.fetch;if(typeof fetch<"u")return fetch.bind(globalThis)}async function oe(e,t){H(t.signal);let n=t.decoder;if(n){let r=t.signal?{signal:t.signal}:void 0;return n.decode(e,r)}if(Ze()&&typeof AudioContext<"u"){let r=In();try{let a=e instanceof ArrayBuffer?e:e instanceof Blob?await e.arrayBuffer():e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength);H(t.signal);let o=await r.decodeAudioData(a);return Ge(o)}catch(a){throw a instanceof b?a:new b("DECODE_ERROR",`Audio decode failed: ${a instanceof Error?a.message:String(a)}`,a)}}throw new b("DECODE_BACKEND_MISSING","No decode backend configured. Provide LoadOptions.decoder in this runtime.")}async function Mn(e,t){return oe(e,t)}async function Ye(e,t){let n=xn(t);if(!n)throw new b("NETWORK_ERROR","Fetch is not available in this runtime");let r=await n(e,t.signal?{signal:t.signal}:void 0);if(!r.ok)throw new b("NETWORK_ERROR",`Failed to fetch audio source: ${r.status}`);H(t.signal);let a=await r.arrayBuffer();return oe(a,t)}async function Rn(e,t){if(wn()){let n=await import("fs/promises");H(t.signal);let r=await n.readFile(e);return H(t.signal),oe(r,t)}return Ye(e,t)}async function Tn(e,t){if(ye(e))return e;if(yn(e))return Ge(e);if(typeof e=="string")return Rn(e,t);if(e instanceof URL)return Ye(e,t);if(e instanceof Blob)return oe(e,t);if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))return Mn(e,t);throw new b("INVALID_INPUT","Unsupported audio source type")}async function ge(e,t={}){try{if(H(t.signal),ye(e)&&!Qe(t))return e;let n=await Tn(e,t);if(H(t.signal),!Qe(t))return n;let r=ye(e)?gn(n):n;return await Sn(r,t)}catch(n){throw n instanceof b?n:new b("DECODE_ERROR",`Failed to load audio source: ${n instanceof Error?n.message:String(n)}`,n)}}function _(){if(typeof performance<"u"&&performance.now)return performance.now();if(typeof process<"u"&&process.hrtime){let[e,t]=process.hrtime();return e*1e3+t/1e6}return Date.now()}function Pn(e){return Array.isArray(e)}function E(e,t="mix"){if(e.numberOfChannels<=0)throw new b("INVALID_INPUT","No channels available");let n=Array.from({length:e.numberOfChannels},(o,i)=>i),r;if(t==="mix")r=n;else{if(t==="all")throw new b("INVALID_INPUT",'Channel selector "all" is not supported for scalar results; use "mix" or a single channel index');if(Pn(t)){if(t.length===0)throw new b("INVALID_INPUT","Channel selection array cannot be empty");if(t.length>1)throw new b("INVALID_INPUT",'Multi-channel selector arrays are not supported for scalar results; use "mix" or a single channel index');r=t.slice()}else if(typeof t=="number"){if(!Number.isInteger(t))throw new b("INVALID_INPUT",`Invalid channel number: ${t}`);r=[t]}else throw new b("INVALID_INPUT",`Invalid channel selector: ${String(t)}`)}for(let o of r){if(o<0||o>=e.numberOfChannels)throw new b("INVALID_INPUT",`Invalid channel number: ${o}`);if(!e.channelData[o])throw new b("INVALID_INPUT",`Channel ${o} data does not exist`)}if(r.length===1){let o=r[0];return e.channelData[o]}let a=new Float32Array(e.length);for(let o=0;o<e.length;o++){let i=0;for(let s of r){let l=e.channelData[s];l&&o<l.length&&(i+=l[o])}a[o]=i/r.length}return a}function vn(e){return Number.isInteger(e)&&e>0&&(e&e-1)===0}function ie(e){if(!Number.isFinite(e)||e<=1)return 1;if(vn(e))return e;let t=1;for(;t<e&&t<Number.MAX_SAFE_INTEGER;)t*=2;return t}function Xe(e,t,n){return t<0||t>=e.length?n:e[t]??n}function ee(e,t){let{samples:n,frameSize:r,hopSize:a,sampleRate:o,padEnd:i=!0}=e;if(!Number.isInteger(r)||r<=0)throw new b("INVALID_INPUT","frameSize must be a positive integer");if(!Number.isInteger(a)||a<=0)throw new b("INVALID_INPUT","hopSize must be a positive integer");if(!Number.isFinite(o)||o<=0)throw new b("INVALID_INPUT","sampleRate must be positive");if(n.length===0)return 0;let s=new Float32Array(r),l=0,c=0;for(;c<n.length||l===0&&i;){let u=Math.min(c+r,n.length),f=Math.max(0,u-c);if(f<r&&!i&&l>0||(s.fill(0),f>0&&s.set(n.subarray(c,u),0),t({frame:s,frameIndex:l,startSample:c,timeSec:(c+r/2)/o}),l+=1,c+=a,!i&&c+r>n.length)||f<r&&i)break}return l}function et(e){return e==="none"?"rectangular":e}function Cn(e,t,n){let r=n?.kaiserBeta??8.6,a=n?.tukeyAlpha??.5;return`${t}|${e}|${r}|${a}`}function Je(e){let t=1,n=1,r=e*e/4;for(let a=1;a<50&&(n*=r/(a*a),t+=n,!(n<1e-10*t));a++);return t}function Dn(e,t,n){if(!Number.isInteger(e)||e<0)throw new b("INVALID_INPUT",`Invalid window length: ${e}`);if(e===0)return new Float32Array(0);let r=new Float32Array(e);if(e===1||t==="rectangular")return r.fill(1),r;switch(t){case"hann":{for(let a=0;a<e;a++)r[a]=.5*(1-Math.cos(2*Math.PI*a/(e-1)));return r}case"hamming":{for(let a=0;a<e;a++)r[a]=.54-.46*Math.cos(2*Math.PI*a/(e-1));return r}case"blackman":{for(let a=0;a<e;a++)r[a]=.42-.5*Math.cos(2*Math.PI*a/(e-1))+.08*Math.cos(4*Math.PI*a/(e-1));return r}case"bartlett":{for(let a=0;a<e;a++)r[a]=1-Math.abs((a-(e-1)/2)/((e-1)/2));return r}case"kaiser":{let a=n?.kaiserBeta??8.6,o=Je(a);for(let i=0;i<e;i++){let s=2*i/(e-1)-1;r[i]=Je(a*Math.sqrt(1-s*s))/o}return r}case"tukey":{let a=n?.tukeyAlpha??.5;if(a<=0)return r.fill(1),r;if(a>=1){for(let i=0;i<e;i++)r[i]=.5*(1-Math.cos(2*Math.PI*i/(e-1)));return r}let o=a*(e-1)/2;for(let i=0;i<e;i++)i<o?r[i]=.5*(1+Math.cos(Math.PI*(2*i/(a*(e-1))-1))):i<=(e-1)*(1-a/2)?r[i]=1:r[i]=.5*(1+Math.cos(Math.PI*(2*i/(a*(e-1))-2/a+1)));return r}default:throw new b("INVALID_INPUT",`Unknown window type: ${String(t)}`)}}var te=class{cache=new Map;getOrCreate(t,n,r){let a=et(n),o=Cn(t,a,r),i=this.cache.get(o);if(i)return i;let s=Dn(t,a,r);return this.cache.set(o,s),s}clear(){this.cache.clear()}},tt=new te;function se(e,t,n){return tt.getOrCreate(e,t,n)}function $(e){let{src:t,srcStart:n,frameLength:r,dst:a,windowType:o,windowParams:i,cache:s=tt}=e;if(a.fill(0),a.length===0||r<=0||n>=t.length)return a;let l=Math.max(0,n),c=Math.min(r,a.length),u=Math.max(0,Math.min(c,t.length-l));if(u===0)return a;let f=et(o);if(f==="rectangular"||c===1)return a.set(t.subarray(l,l+u),0),a;let m=s.getOrCreate(c,f,i);for(let p=0;p<u;p++)a[p]=t[l+p]*m[p];return a}function On(e,t){let n=0;for(let r=0;r<e.length;r++){let a=e[r],o=t?a*t[r]:a;n+=o*o}return n}function nt(e,t={}){let{frameSize:n=Math.floor(e.sampleRate*.025),hopSize:r=Math.floor(e.sampleRate*.01),channel:a="mix",normalized:o=!1,windowFunction:i="rectangular"}=t;if(!Number.isInteger(n)||n<=0)throw new b("INVALID_INPUT","frameSize must be a positive integer");if(!Number.isInteger(r)||r<=0)throw new b("INVALID_INPUT","hopSize must be a positive integer");let s=E(e,a);if(s.length===0)return{times:new Float32Array(0),energies:new Float32Array(0),totalEnergy:0,statistics:{mean:0,std:0,max:0,min:0}};let l=i==="rectangular"||i==="none"?null:se(n,i),c=[],u=[],f=0,m=-1/0,p=1/0;ee({samples:s,frameSize:n,hopSize:r,sampleRate:e.sampleRate,padEnd:!0},({frame:w,timeSec:M})=>{let S=On(w,l);c.push(M),u.push(S),f+=S,m=Math.max(m,S),p=Math.min(p,S)});let F=new Float32Array(u),d=new Float32Array(c),h=F.length,A=h>0?f/h:0,y=0;for(let w=0;w<h;w++){let M=F[w]-A;y+=M*M}let g=h>0?Math.sqrt(y/h):0;if(o&&f>1e-10){for(let w=0;w<F.length;w++)F[w]=F[w]/f;return{times:d,energies:F,totalEnergy:1,statistics:{mean:A/f,std:g/f,max:m/f,min:p/f}}}return{times:d,energies:F,totalEnergy:f,statistics:{mean:A,std:g,max:Number.isFinite(m)?m:0,min:Number.isFinite(p)?p:0}}}function rt(e,t){let n=new Float32Array(e/2+1),r=t/e;for(let a=0;a<n.length;a++)n[a]=a*r;return n}var be=class{constructor(t,n,r=!1){this.size=t;this.sampleRate=n;this.enableProfiling=r;this.complexInput=new Float32Array(this.size*2),this.frequencyBins=rt(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 n=(await import("webfft")).default;this.fftInstance=new n(this.size),this.enableProfiling&&this.fftInstance?.profile&&await this.fftInstance.profile()}catch(t){throw new b("UNSUPPORTED_FORMAT",`Failed to initialize WebFFT: ${t instanceof Error?t.message:String(t)}`)}}async fft(t){if(this.initializationPromise&&await this.initializationPromise,!this.fftInstance)throw new b("UNSUPPORTED_FORMAT","WebFFT initialization failed");if(t.length!==this.size)throw new b("INVALID_INPUT",`Invalid input size. Expected: ${this.size}, Actual: ${t.length}`);for(let o=0;o<this.size;o++)this.complexInput[o*2]=t[o],this.complexInput[o*2+1]=0;let n=this.fftInstance.fft(this.complexInput),r=new Float32Array(this.size/2+1),a=new Float32Array(this.size/2+1);for(let o=0;o<r.length;o++){let i=n[o*2],s=n[o*2+1];r[o]=Math.sqrt(i*i+s*s),a[o]=Math.atan2(s,i)}return{complex:n,magnitude:r,phase:a,frequencies:this.frequencyBins}}async profile(){if(this.initializationPromise&&await this.initializationPromise,!this.fftInstance||!this.fftInstance.profile)throw new b("UNSUPPORTED_FORMAT","WebFFT is not initialized");await this.fftInstance.profile()}dispose(){if(this.fftInstance)try{this.fftInstance.dispose&&this.fftInstance.dispose()}catch(t){console.warn("FFT instance disposal failed:",t)}finally{this.fftInstance=null,this.initializationPromise=null}}},Ae=class{constructor(t,n){this.size=t;this.sampleRate=n;if(!this.isPowerOfTwo(t))throw new b("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(t){return t>0&&(t&t-1)===0}precomputeTables(){this.bitReversalTable=new Uint32Array(this.size);let t=Math.log2(this.size);for(let r=0;r<this.size;r++){let a=0;for(let o=0;o<t;o++)a=a<<1|r>>o&1;this.bitReversalTable[r]=a}let n=this.size/2;this.twiddleFactorsReal=new Float32Array(n),this.twiddleFactorsImag=new Float32Array(n);for(let r=0;r<n;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=rt(this.size,this.sampleRate)}fft(t){if(t.length!==this.size)throw new b("INVALID_INPUT",`Invalid input size. Expected: ${this.size}, Actual: ${t.length}`);let n=this.scratchReal,r=this.scratchImag;for(let s=0;s<this.size;s++){let l=this.bitReversalTable[s];n[l]=t[s],r[l]=0}for(let s=1;s<this.size;s*=2){let l=s*2,c=this.size/l;for(let u=0;u<this.size;u+=l)for(let f=0;f<s;f++){let m=f*c,p=this.twiddleFactorsReal[m],F=this.twiddleFactorsImag[m],d=u+f,h=u+f+s,A=n[d],y=r[d],g=n[h],w=r[h],M=g*p-w*F,S=g*F+w*p;n[d]=A+M,r[d]=y+S,n[h]=A-M,r[h]=y-S}}let a=new Float32Array(this.size*2),o=new Float32Array(this.size/2+1),i=new Float32Array(this.size/2+1);for(let s=0;s<this.size;s++)if(a[s*2]=n[s],a[s*2+1]=r[s],s<=this.size/2){let l=n[s],c=r[s];o[s]=Math.sqrt(l*l+c*c),i[s]=Math.atan2(c,l)}return{complex:a,magnitude:o,phase:i,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)}},le=class{static async createProvider(t){switch(t.type){case"webfft":{let n=new be(t.fftSize,t.sampleRate,t.enableProfiling);return await n.waitForInitialization(),n}case"native":return new Ae(t.fftSize,t.sampleRate);case"custom":if(!t.customProvider)throw new b("INVALID_INPUT","Custom provider is not specified");return t.customProvider;default:{let n=t.type;throw new b("UNSUPPORTED_FORMAT",`Unsupported FFT provider: ${String(n)}`)}}}static getAvailableProviders(){return["webfft","native"]}};function kn(e){let t=e.provider??"native",n=e.enableProfiling?1:0,r=e.fallbackToNative?1:0;return`${t}|${e.fftSize}|${e.sampleRate}|${n}|${r}`}var ne=class{providers=new Map;async getOrCreate(t){let n=kn(t),r=this.providers.get(n);if(r)return r;let a=await at(t);return this.providers.set(n,a),a}clear(){for(let t of this.providers.values())t.dispose();this.providers.clear()}},zn=new ne;async function j(e){let{cache:t,useSharedCache:n=!1,...r}=e,a=t??(n?zn:void 0);if(a)return{provider:await a.getOrCreate(r),release:()=>{}};let o=await at(r);return{provider:o,release:()=>{o.dispose()}}}async function at(e){let{fftSize:t,sampleRate:n,provider:r="native",enableProfiling:a=!1,fallbackToNative:o=r==="webfft",resolver:i=le}=e,s=o&&r!=="native"?[r,"native"]:[r],l;for(let c of s)try{return await i.createProvider({type:c,fftSize:t,sampleRate:n,enableProfiling:a})}catch(u){l=u}throw new b("INITIALIZATION_FAILED","Failed to create FFT provider",l)}function q(e,t=1,n=-1/0){return!Number.isFinite(e)||!Number.isFinite(t)||e<=0||t<=0?n:20*Math.log10(e/t)}function Q(e,t=1,n=-1/0){return!Number.isFinite(e)||!Number.isFinite(t)||e<=0||t<=0?n:10*Math.log10(e/t)}var Se=new WeakMap;function En(e){return Array.isArray(e)?`[${e.map(t=>String(t)).join(",")}]`:String(e)}function Nn(e){return[e.fftSize,e.windowFunction,En(e.channel),e.provider,e.enableProfiling?1:0,e.normalization].join("|")}function ot(e,t){if(!Number.isInteger(e)||e<=0||(e&e-1)!==0)throw new b("INVALID_INPUT",`${t} must be a power of two`)}function we(e,t){if(!Number.isInteger(e)||e<=0)throw new b("INVALID_INPUT",`${t} must be a positive integer`)}function it(e,t,n){if(!Number.isFinite(t)||!Number.isFinite(n)||t<0)throw new b("INVALID_INPUT",`Invalid frequency range: min=${t}, max=${n}`);let r=e/2;if(t>=n||n>r)throw new b("INVALID_INPUT",`Frequency range must satisfy 0 <= min < max <= Nyquist (${r})`)}function st(e,t,n){let r=e.findIndex(i=>i>=t);r<0&&(r=0);let a=e.findIndex(i=>i>n),o=a===-1?e.length:a;return r>=o?{startIndex:0,endIndex:0}:{startIndex:r,endIndex:o}}function Ln(e,t){if(t<=1||e==="none")return 1;let n=se(t,e),r=0;for(let o=0;o<n.length;o++)r+=n[o]??0;let a=r/t;return a>0?a:1}function lt(e,t,n,r){if(t==="none")return e;if(n<=0||e.length===0)return e.fill(0),e;let a=Ln(r,n),o=n*a;if(o<=0)return e.fill(0),e;let i=1/o,s=i*2,l=e.length-1;for(let c=0;c<e.length;c++){let u=c===0||c===l?i:s;e[c]=(e[c]??0)*u}return e}function ct(e,t){if(t==="amplitude")return e.slice();let n=new Float32Array(e.length);for(let r=0;r<e.length;r++)n[r]=q(e[r]??0,1);return n}function qn(e,t,n){return e===0?0:e<t?1:Math.floor((e-t)/n)+1}function ut(e,t){if(e==="dbfs"&&t!=="amplitude")throw new b("INVALID_INPUT",'scale="dbfs" requires normalization="amplitude"')}async function Z(e,t={}){let{fftSize:n=2048,windowFunction:r="hann",channel:a="mix",provider:o="native",enableProfiling:i=!1,providerCache:s,normalization:l="amplitude"}=t;ot(n,"FFT size");let c=Nn({fftSize:n,windowFunction:r,channel:a,provider:o,enableProfiling:i,normalization:l}),u=Se.get(e);u||(u=new Map,Se.set(e,u));let f=u.get(c);if(f)return f;let m=(async()=>{let F=E(e,a),d=new Float32Array(n),h=Math.min(F.length,n);$({src:F,srcStart:0,frameLength:h,dst:d,windowType:r});let{provider:A,release:y}=await j({fftSize:n,sampleRate:e.sampleRate,provider:o,enableProfiling:i,fallbackToNative:o==="webfft",cache:s});try{let g=await A.fft(d),w=new Float32Array(g.magnitude);return lt(w,l,h,r),{...g,magnitude:w,fftSize:n,windowFunction:r,providerName:A.name,normalization:l}}finally{y()}})();u.set(c,m);let p=()=>{u.delete(c),u.size===0&&Se.delete(e)};return m.then(p,p),m}async function mt(e,t={}){let{fftSize:n=2048,minFrequency:r=0,maxFrequency:a=e.sampleRate/2,scale:o="dbfs",normalization:i="amplitude",...s}=t;it(e.sampleRate,r,a),ut(o,i);let l=await Z(e,{...s,fftSize:n,normalization:i}),{startIndex:c,endIndex:u}=st(l.frequencies,r,a),f=l.frequencies.slice(c,u),m=l.magnitude.slice(c,u);return{frequencies:f,values:ct(m,o),scale:o}}async function ft(e,t={}){let{fftSize:n=2048,frameSize:r=n,hopSize:a=Math.max(1,Math.floor(r/2)),maxFrames:o,minFrequency:i=0,maxFrequency:s=e.sampleRate/2,scale:l="dbfs",normalization:c="amplitude",windowFunction:u="hann",channel:f="mix",provider:m="native",enableProfiling:p=!1,providerCache:F}=t;if(ot(n,"FFT size"),we(r,"frameSize"),we(a,"hopSize"),r>n)throw new b("INVALID_INPUT","frameSize must be <= fftSize");o!==void 0&&we(o,"maxFrames"),it(e.sampleRate,i,s),ut(l,c);let d=E(e,f),h=qn(d.length,r,a),A=o===void 0?h:Math.min(h,o);if(A===0)return{times:new Float32Array(0),frequencies:new Float32Array(0),frames:[],frameCount:0,frequencyBins:0,scale:l,latest:new Float32Array(0)};let y=new Float32Array(A),g=new Array(A),w=new Float32Array(n),M=new Float32Array(0),S=0,T=0,{provider:D,release:C}=await j({fftSize:n,sampleRate:e.sampleRate,provider:m,enableProfiling:p,fallbackToNative:m==="webfft",cache:F});try{for(let x=0;x<A;x++){let R=x*a,P=Math.min(r,Math.max(0,d.length-R));$({src:d,srcStart:R,frameLength:P,dst:w,windowType:u});let k=await D.fft(w),z=new Float32Array(k.magnitude);if(lt(z,c,P,u),x===0){let V=st(k.frequencies,i,s);S=V.startIndex,T=V.endIndex,M=k.frequencies.slice(S,T)}let N=z.slice(S,T);g[x]=ct(N,l),y[x]=(R+r/2)/e.sampleRate}}finally{C()}let v=g[g.length-1]??new Float32Array(M.length);return{times:y,frequencies:M,frames:g,frameCount:g.length,frequencyBins:M.length,scale:l,latest:v}}function _n(e){if(![2,4,8].includes(e))throw new b("INVALID_INPUT","Oversampling factor must be 2, 4, or 8. Sinc interpolation quality is not guaranteed for other values.")}function ce(e,t={}){if(e.length===0)return 0;let{factor:n=4,interpolation:r="cubic"}=t;_n(n);let a=0;if(n<=1||e.length===1){for(let i=0;i<e.length;i++){let s=Math.abs(e[i]);s>a&&(a=s)}return a}if(r==="sinc"){let i=l=>{if(Math.abs(l)<1e-10)return 1;let c=Math.PI*l;return Math.abs(l)<3?3*Math.sin(c/3)*Math.sin(c)/(c*c):0},s=(e.length-1)*n+1;for(let l=0;l<s;l++){let c=l/n,u=0;for(let m=-3;m<=3;m++){let p=Math.floor(c)+m;p>=0&&p<e.length&&(u+=e[p]*i(c-p))}let f=Math.abs(u);f>a&&(a=f)}return a}for(let i=0;i<e.length-1;i++){let s=e[i],l=e[i+1],c=s,u=l;r==="cubic"&&(c=e[Math.max(0,i-1)],u=e[Math.min(e.length-1,i+2)]);for(let f=0;f<n;f++){let m=f/n,p=r==="linear"?s+(l-s)*m:.5*(2*s+(-c+l)*m+(2*c-5*s+4*l-u)*m*m+(-c+3*s-3*l+u)*m*m*m),F=Math.abs(p);F>a&&(a=F)}}let o=Math.abs(e[e.length-1]);return o>a&&(a=o),a}var pt=Object.freeze([Object.freeze([.001708984375,.010986328125,-.0196533203125,.033203125,-.0594482421875,.1373291015625,.97216796875,-.102294921875,.047607421875,-.026611328125,.014892578125,-.00830078125]),Object.freeze([-.0291748046875,.029296875,-.0517578125,.089111328125,-.16650390625,.465087890625,.77978515625,-.2003173828125,.1015625,-.0582275390625,.0330810546875,-.0189208984375]),Object.freeze([-.0189208984375,.0330810546875,-.0582275390625,.1015625,-.2003173828125,.77978515625,.465087890625,-.16650390625,.089111328125,-.0517578125,.029296875,-.0291748046875]),Object.freeze([-.00830078125,.014892578125,-.026611328125,.047607421875,-.102294921875,.97216796875,.1373291015625,-.0594482421875,.033203125,-.0196533203125,.010986328125,.001708984375])]);function Bn(e){if(e!==2&&e!==4)throw new b("INVALID_INPUT","BS.1770 true peak supports oversampling factor 2 or 4")}function Wn(e){let t=0;for(let n=0;n<e.length;n++){let r=Math.abs(e[n]);r>t&&(t=r)}return t}function Vn(e,t){let n=pt[0];if(!n||n.length===0)return 0;let r=n.length,a=new Float64Array(r),o=0,i=0;for(let s=0;s<e.length;s++){a[o]=e[s];for(let l of t){let c=pt[l];if(!c)continue;let u=0;for(let m=0;m<r;m++){let p=o-m;p<0&&(p+=r),u+=a[p]*c[m]}let f=Math.abs(u);f>i&&(i=f)}o=(o+1)%r}return i}function dt(e,t={}){if(e.length===0)return 0;let n=t.factor??4;Bn(n);let r=Wn(e),o=Vn(e,n===2?[0,2]:[0,1,2,3]);return o>r&&(r=o),r}var ht=new Map;function Un(e){if(!isFinite(e)||e<=0)throw new b("INVALID_INPUT","Sample rate must be a positive finite value");if(e<8e3||e>384e3)throw new b("UNSUPPORTED_FORMAT",`Sample rate ${e} Hz is not supported`)}function Kn(e){Un(e);let t=ht.get(e);if(t)return t;let n=[];if(e===48e3)n.push({b0:1.53512485958697,b1:-2.69169618940638,b2:1.19839281085285,a0:1,a1:-1.69065929318241,a2:.73248077421585}),n.push({b0:1,b1:-2,b2:1,a0:1,a1:-1.99004745483398,a2:.99007225036621});else{let r=1681.974450955532,a=3.99984385397,o=.7071752369554193,i=Math.tan(Math.PI*r/e),s=Math.pow(10,a/20),l=Math.pow(s,.499666774155),c=1+i/o+i*i;n.push({b0:(s+l*i/o+i*i)/c,b1:2*(i*i-s)/c,b2:(s-l*i/o+i*i)/c,a0:1,a1:2*(i*i-1)/c,a2:(1-i/o+i*i)/c});let u=38.13547087613982,f=.5003270373253953,m=Math.tan(Math.PI*u/e),p=1+m/f+m*m;n.push({b0:1,b1:-2,b2:1,a0:1,a1:2*(m*m-1)/p,a2:(1-m/f+m*m)/p});let d=1/$n(n,997,e).magnitude;n[0]&&(n[0].b0*=d,n[0].b1*=d,n[0].b2*=d)}return ht.set(e,n),n}function $n(e,t,n){let r=2*Math.PI*t/n,a=1,o=0;for(let l of e){let c=Math.cos(r),u=Math.sin(r),f=Math.cos(2*r),m=Math.sin(2*r),p=l.b0+l.b1*c+l.b2*f,F=-l.b1*u-l.b2*m,d=l.a0+l.a1*c+l.a2*f,h=-l.a1*u-l.a2*m,A=d*d+h*h;if(A===0)throw new b("INVALID_INPUT","Division by zero occurred while calculating frequency response");let y=(p*d+F*h)/A,g=(F*d-p*h)/A,w=a*y-o*g,M=a*g+o*y;a=w,o=M}let i=Math.sqrt(a*a+o*o),s=Math.atan2(o,a);return{magnitude:i,phase:s}}function Ft(e){return Kn(e)}var jn=-70,Hn=10,xe=400,gt=.75,Qn=3e3,Gn=400;function yt(e,t,n,r,a){if(a<=0)return;let{x1:o,x2:i,y1:s,y2:l}=r;for(let c=0;c<a;c++){let u=e[c],f=n.b0*u+n.b1*o+n.b2*i-n.a1*s-n.a2*l;t[c]=f,i=o,o=u,l=s,s=f}r.x1=o,r.x2=i,r.y1=s,r.y2=l}function Zn(e,t=e.length){let n=0,r=Math.min(t,e.length);if(r===0)return-1/0;for(let a=0;a<r;a++){let o=e[a];if(!o||o.length===0)continue;let i=0;for(let l=0;l<o.length;l++){let c=o[l];i+=c*c}if(o.length===0)continue;n+=1*(i/o.length)}return-.691+Q(Math.max(1e-15,n),1)}function Ie(e){if(e.length===0)return-1/0;let t=e.reduce((n,r)=>n+Math.pow(10,(r+.691)/10),0);return-.691+Q(t/e.length,1)}function bt(e,t={}){let{channelMode:n=e.numberOfChannels>=2?"stereo":"mono",gated:r=!0,calculateShortTerm:a=!1,calculateMomentary:o=!1,collectSeries:i=!1,calculateLoudnessRange:s=!1,calculateTruePeak:l=!1,truePeakMethod:c="bs1770",truePeakOversamplingFactor:u=4,truePeakInterpolation:f="sinc"}=t;if(e.numberOfChannels===0)throw new b("INVALID_INPUT","No processable channels available");let m=Yn(e.sampleRate,{channelMode:n,gated:r,maxDurationMs:e.duration*1e3+5e3}),p=[];if(n==="mono"){let x=e.channelData[0];x&&p.push(x)}else{let x=e.channelData[0],R=e.channelData[1];x&&p.push(x),R&&p.push(R)}if(p.length===0)throw new b("INVALID_INPUT","No processable channels available");let F=[],d=p[0].length,h=xe*(1-gt),A=Math.max(1,Math.floor(h/1e3*e.sampleRate));for(let x=0;x<d;x+=A){let R=Math.min(x+A,d),P=p.map(k=>k.subarray(x,R));F.push(P)}let y=i===!0||i==="both"||i==="shortTerm",g=i===!0||i==="both"||i==="momentary",w=s,M=[],S=[],T=[],D=[],C;for(let x=0;x<F.length;x++){let R=F[x];C=m.process(R);let k=Math.min((x+1)*A,d)/e.sampleRate;if((y||g)&&M.push(k),g){let z=Number.isFinite(C.momentary)?C.momentary:-1/0;S.push(z)}if(y){let z=Number.isFinite(C.shortTerm)?C.shortTerm:-1/0;T.push(z)}w&&D.push(C.shortTerm)}let v={integrated:C?.integrated??-1/0};if(a&&(v.shortTerm=C?.shortTerm??-1/0),o&&(v.momentary=C?.momentary??-1/0),s&&D.length>0){let x=D.filter(R=>R>-70&&isFinite(R)).sort((R,P)=>R-P);if(x.length>0){let R=Math.floor(x.length*.1),P=Math.floor(x.length*.95),k=x[R]??-1/0,z=x[P]??-1/0;v.loudnessRange=z-k,v.statistics={percentile10:k,percentile95:z}}}if((y||g)&&(v.series={times:Float32Array.from(M),...y?{shortTerm:Float32Array.from(T)}:{},...g?{momentary:Float32Array.from(S)}:{}}),l){if(c==="bs1770"&&u===8)throw new b("INVALID_INPUT","truePeakOversamplingFactor=8 is unsupported for truePeakMethod='bs1770'; use factor 2 or 4, or switch to interSamplePeak");v.truePeak=p.map(x=>{if(c==="interSamplePeak"){let P=ce(x,{factor:u,interpolation:f});return q(P,1)}let R=dt(x,{factor:u===2?2:4});return q(R,1)})}return v}var Me=class{sampleRate;channelMode;blockSize;hopSize;blockBuffer=[];maxBlocks;currentSamples=[];filterStage1Scratch=[];filterStage2Scratch=[];sampleCount=0;biquadStates=[];totalSamplesProcessed=0;gated;constructor(t,n="stereo",r=3e4,a=!0){if(this.sampleRate=t,this.channelMode=n,this.gated=a,this.blockSize=Math.floor(xe/1e3*t),this.blockSize===0)throw new b("INVALID_INPUT",`Sample rate ${t} Hz is too low for realtime LUFS processing. Minimum required sample rate is ${Math.ceil(1e3/xe)} Hz.`);this.hopSize=Math.floor(this.blockSize*(1-gt)),this.maxBlocks=Math.ceil(r/(this.hopSize/t*1e3));let o=n==="stereo"?2:1;for(let i=0;i<o;i++)this.currentSamples.push(new Float32Array(this.blockSize)),this.filterStage1Scratch.push(new Float32Array(this.blockSize)),this.filterStage2Scratch.push(new Float32Array(this.blockSize)),this.biquadStates.push([{x1:0,x2:0,y1:0,y2:0},{x1:0,x2:0,y1:0,y2:0}])}ensureFilterScratchCapacity(t,n){for(let r=0;r<n;r++){let a=this.filterStage1Scratch[r],o=this.filterStage2Scratch[r];(!a||a.length<t)&&(this.filterStage1Scratch[r]=new Float32Array(t)),(!o||o.length<t)&&(this.filterStage2Scratch[r]=new Float32Array(t))}}process(t){let n=this.channelMode==="stereo"?Math.min(t.length,2):1,r=Ft(this.sampleRate),a=t[0]?.length||0;if(a===0)return this.calculateCurrentLUFS();this.ensureFilterScratchCapacity(a,n);for(let i=0;i<n;i++){let s=t[i],l=this.filterStage1Scratch[i],c=this.filterStage2Scratch[i];if(!(!l||!c)){if(!s){c.fill(0,0,a);continue}yt(s,l,r[0],this.biquadStates[i][0],a),yt(l,c,r[1],this.biquadStates[i][1],a)}}let o=0;for(;o<a;){let i=this.blockSize-this.sampleCount,s=Math.min(a-o,i);for(let l=0;l<n;l++){let c=this.filterStage2Scratch[l],u=this.currentSamples[l];c&&u.set(c.subarray(o,o+s),this.sampleCount)}if(this.sampleCount+=s,o+=s,this.sampleCount>=this.blockSize){let l=Zn(this.currentSamples,n);if(isFinite(l)){let c=this.totalSamplesProcessed+this.blockSize/2;this.blockBuffer.push([l,c]),this.blockBuffer.length>this.maxBlocks&&this.blockBuffer.shift()}for(let c=0;c<n;c++)this.currentSamples[c].copyWithin(0,this.hopSize);this.sampleCount=this.blockSize-this.hopSize,this.totalSamplesProcessed+=this.hopSize}}return this.calculateCurrentLUFS()}calculateCurrentLUFS(){if(this.blockBuffer.length===0)return{integrated:-1/0,momentary:-1/0,shortTerm:-1/0};let t=this.totalSamplesProcessed+this.sampleCount,n=Gn/1e3*this.sampleRate,r=Qn/1e3*this.sampleRate,a=this.blockBuffer.filter(([u,f])=>t-f<=n).map(([u])=>u),o=this.blockBuffer.filter(([u,f])=>t-f<=r).map(([u])=>u),i=-1/0,s=this.blockBuffer.map(([u])=>u).filter(u=>isFinite(u));if(!this.gated)i=Ie(s);else if(s.length>0){let u=s.filter(f=>f>=jn);if(u.length>0){let m=Ie(u)-Hn,p=u.filter(F=>F>=m);i=Ie(p)}}let l=-1/0;if(a.length>0){let u=a.reduce((f,m)=>f+Math.pow(10,(m+.691)/10),0);l=-.691+Q(u/a.length,1)}let c=-1/0;if(o.length>0){let u=o.reduce((f,m)=>f+Math.pow(10,(m+.691)/10),0);c=-.691+Q(u/o.length,1)}return{integrated:i,momentary:l,shortTerm:c}}reset(){this.blockBuffer=[],this.sampleCount=0,this.totalSamplesProcessed=0;for(let t=0;t<this.currentSamples.length;t++){this.currentSamples[t].fill(0);for(let n=0;n<this.biquadStates[t].length;n++)this.biquadStates[t][n]={x1:0,x2:0,y1:0,y2:0}}}getBufferSize(){return this.blockBuffer.length}};function Yn(e,t={}){let{channelMode:n="stereo",maxDurationMs:r=3e4,gated:a=!0}=t;return new Me(e,n,r,a)}function xt(e,t,n,r){let a=0,o=0;for(let i=0;i<e.length&&i<t.length;i++){let s=t[i],l=e[i];s>=n&&s<=r&&(a+=s*l,o+=l)}return o>1e-10?a/o:0}function Mt(e,t,n,r,a){let o=0,i=0;for(let s=0;s<e.length&&s<t.length;s++){let l=t[s],c=e[s];if(l>=r&&l<=a){let u=l-n;o+=u*u*c,i+=c}}return i>1e-10?Math.sqrt(o/i):0}function Rt(e,t,n,r,a){let o=0;for(let l=0;l<e.length&&l<t.length;l++){let c=t[l],u=e[l];c>=r&&c<=a&&(o+=u*u)}let i=o*n,s=0;for(let l=0;l<e.length&&l<t.length;l++){let c=t[l],u=e[l];if(c>=r&&c<=a&&(s+=u*u,s>=i))return c}return a}function Tt(e,t,n){let r=0,a=0,o=0;for(let i=t;i<=n&&i<e.length;i++){let s=Math.max(e[i],1e-10);r+=Math.log(s),a+=s,o++}return o===0?0:(r=Math.exp(r/o),a=a/o,a>1e-10?r/a:0)}function Pt(e){if(e.length<2)return 0;let t=0;for(let n=1;n<e.length;n++){let r=e[n-1],a=e[n];(r>=0&&a<0||r<0&&a>=0)&&t++}return t/(e.length-1)}function Xn(e,t,n={normalize:!0}){if(!t||t.length===0)return 0;let r=Math.min(e.length,t.length);if(r===0)return 0;if(n.normalize!==!1){let o=0,i=0;for(let c=0;c<r;c++){let u=e[c],f=t[c];o+=u*u,i+=f*f}let s=Math.sqrt(o),l=Math.sqrt(i);if(s>1e-10&&l>1e-10){let c=1/s,u=1/l,f=0;for(let m=0;m<r;m++){let p=e[m]*c-t[m]*u;f+=p*p}return Math.sqrt(f)}}let a=0;for(let o=0;o<r;o++){let i=e[o]-t[o];a+=i*i}return Math.sqrt(a)}async function vt(e,t={}){let{fftSize:n=2048,windowFunction:r="hann",channel:a="mix",provider:o="native",enableProfiling:i=!1,providerCache:s,minFrequency:l=0,maxFrequency:c=e.sampleRate/2,rolloffThreshold:u=.85}=t,f=E(e,a),m=await Z(e,{fftSize:n,windowFunction:r,channel:a,provider:o,enableProfiling:i,providerCache:s}),p=Math.max(0,Math.floor(l*n/e.sampleRate)),F=Math.min(m.frequencies.length-1,Math.floor(c*n/e.sampleRate)),d=xt(m.magnitude,m.frequencies,l,c),h=Mt(m.magnitude,m.frequencies,d,l,c),A=Rt(m.magnitude,m.frequencies,u,l,c),y=Tt(m.magnitude,p,F),g=Pt(f);return{spectralCentroid:d,spectralBandwidth:h,spectralRolloff:A,spectralFlatness:y,spectralFlux:0,zeroCrossingRate:g,frequencyRange:{min:l,max:c}}}async function Ct(e,t={}){let{frameSize:n=2048,hopSize:r=n/2,fftSize:a=n,windowFunction:o="hann",channel:i="mix",provider:s="native",enableProfiling:l=!1,providerCache:c,minFrequency:u=0,maxFrequency:f=e.sampleRate/2,rolloffThreshold:m=.85,numFrames:p}=t,F=E(e,i),d=Math.floor((F.length-n)/r)+1,h=p??(F.length>0?Math.max(1,d):0);if(h<=0||F.length===0)throw new b("INVALID_INPUT","Invalid frame count");let A=new Float32Array(h),y=new Float32Array(h),g=new Float32Array(h),w=new Float32Array(h),M=new Float32Array(h),S=new Float32Array(h),T=new Float32Array(h),D=new Float32Array(a),C,{provider:v,release:x}=await j({fftSize:a,sampleRate:e.sampleRate,provider:s,enableProfiling:l,fallbackToNative:s==="webfft",cache:c});try{for(let R=0;R<h;R++){let P=R*r,k=Math.min(P+n,F.length);A[R]=P/e.sampleRate;let z=F.subarray(P,k);$({src:F,srcStart:P,frameLength:Math.min(n,Math.max(0,F.length-P)),dst:D,windowType:o});let N=await v.fft(D),V=Math.max(0,Math.floor(u*a/e.sampleRate)),G=Math.min(N.frequencies.length-1,Math.floor(f*a/e.sampleRate)),Y=xt(N.magnitude,N.frequencies,u,f);y[R]=Y,g[R]=Mt(N.magnitude,N.frequencies,Y,u,f),w[R]=Rt(N.magnitude,N.frequencies,m,u,f),M[R]=Tt(N.magnitude,V,G),T[R]=Pt(z),S[R]=Xn(N.magnitude,C),C=new Float32Array(N.magnitude)}}finally{x()}return{times:A,spectralCentroid:y,spectralBandwidth:g,spectralRolloff:w,spectralFlatness:M,spectralFlux:S,zeroCrossingRate:T,frameInfo:{frameSize:n,hopSize:r,numFrames:h}}}function Jn(e,t,n){let r=[],a=0;for(let c=t;c<=n&&c<e.length;c++){let u=e[c];if(u!==void 0){let f=u*u;r.push(f),a+=f}}if(r.length===0||a<=1e-10)return{entropy:0,entropyNorm:0};let o=r.map(c=>c/a),i=0;for(let c of o)c>1e-10&&(i-=c*Math.log2(c));let s=Math.log2(r.length),l=s>0?i/s:0;return{entropy:i,entropyNorm:l}}function er(e,t,n){let r=0,a=0,o=0;for(let l=t;l<=n&&l<e.length;l++){let c=e[l];c!==void 0&&(r=Math.max(r,c),a+=c,o++)}if(o===0)return{crest:0,peak:0,average:0};let i=a/o;return{crest:i>1e-10?r/i:0,peak:r,average:i}}async function Dt(e,t={}){let{fftSize:n=2048,windowFunction:r="hann",channel:a="mix",provider:o="native",enableProfiling:i=!1,providerCache:s,minFrequency:l=0,maxFrequency:c=e.sampleRate/2}=t,u=await Z(e,{fftSize:n,windowFunction:r,channel:a,provider:o,enableProfiling:i,providerCache:s}),f=Math.max(0,Math.floor(l*n/e.sampleRate)),m=Math.min(u.frequencies.length-1,Math.floor(c*n/e.sampleRate)),{entropy:p,entropyNorm:F}=Jn(u.magnitude,f,m);return{entropy:p,entropyNorm:F,frequencyRange:{min:l,max:c}}}async function Ot(e,t={}){let{fftSize:n=2048,windowFunction:r="hann",channel:a="mix",provider:o="native",enableProfiling:i=!1,providerCache:s,minFrequency:l=0,maxFrequency:c=e.sampleRate/2,asDB:u=!1}=t,f=await Z(e,{fftSize:n,windowFunction:r,channel:a,provider:o,enableProfiling:i,providerCache:s}),m=Math.max(0,Math.floor(l*n/e.sampleRate)),p=Math.min(f.frequencies.length-1,Math.floor(c*n/e.sampleRate)),{crest:F,peak:d,average:h}=er(f.magnitude,m,p),A={crest:F,peak:d,average:h,frequencyRange:{min:l,max:c}};return u&&(A.crestDB=q(F,1)),A}var At=new Map,St=new Map;function tr(e,t,n,r,a){return`${e}|${t}|${n}|${r}|${a}`}function nr(e,t,n,r,a){return`${e}|${t}|${n}|${r}|${a??"auto"}`}function wt(e){return 2595*Math.log10(1+e/700)}function It(e){return 700*(Math.pow(10,e/2595)-1)}function kt(e,t,n,r,a){let o=tr(e,t,n,r,a),i=At.get(o);if(i)return i;let s=[],l=n/2,c=Math.floor(t/2)+1,u=wt(r),f=wt(a),m=new Array(e+2);for(let h=0;h<e+2;h++)m[h]=u+(f-u)*h/(e+1);let p=new Float32Array(e),F=m.map(h=>{let A=It(h);return Math.floor(A/l*(c-1))});for(let h=1;h<=e;h++){let A=new Float32Array(c),y=F[h-1],g=F[h],w=F[h+1];if(y===void 0||g===void 0||w===void 0)continue;let M=m[h];M!==void 0&&(p[h-1]=It(M));for(let S=y;S<=w;S++)S<0||S>=c||S>=A.length||(S<g?g-y>0&&(A[S]=(S-y)/(g-y)):w-g>0&&(A[S]=(w-S)/(w-g)));s.push(A)}let d={filters:s,centerFrequencies:p};return At.set(o,d),d}function Re(e,t,n,r){let a=n.frameSizeMs??25,o=n.hopSizeMs??10,i=Math.round(a/1e3*e.sampleRate),s=Math.round(o/1e3*e.sampleRate),l=n.fftSize??Math.max(1024,ie(i));if(i<=0||s<=0)throw new b("INVALID_INPUT","Frame size or hop size is too small");if(l<=0||(l&l-1)!==0)throw new b("INVALID_INPUT","FFT size must be a power of two");let c=Math.floor((t-i)/s)+1,u=t>0?Math.max(1,c):0;if(u<=0)throw new b("INSUFFICIENT_DATA","Invalid frame count");return{frameSizeMs:a,hopSizeMs:o,frameSizeSamples:i,hopSizeSamples:s,fftSize:l,windowFunction:n.windowFunction??r,channel:n.channel??"mix",numFrames:u}}function zt(e){let t=e??2;if(!Number.isFinite(t)||t<=0)throw new b("INVALID_INPUT","power must be a positive finite number");return t}function Et(e,t){let n=new Float32Array(e.length);if(t===1)return n.set(e),n;if(t===2){for(let r=0;r<e.length;r++){let a=e[r];n[r]=a*a}return n}for(let r=0;r<e.length;r++){let a=e[r];n[r]=Math.pow(a,t)}return n}function Nt(e,t,n){let r=new Float32Array(t.length);for(let a=0;a<t.length;a++){let o=t[a];if(!o)continue;let i=0;for(let s=0;s<o.length&&s<e.length;s++)i+=e[s]*o[s];r[a]=Math.max(i,n)}return r}function rr(e,t,n,r,a){let o=nr(e,t,n,r,a),i=St.get(o);if(i)return i;let s=t/2,l=t/e,c=Math.floor(e/2);if(!Number.isFinite(n)||n<=0)throw new b("INVALID_INPUT","fMin must be a positive number");if(!Number.isFinite(r)||r<=0)throw new b("INVALID_INPUT","binsPerOctave must be a positive number");if(a!==void 0&&(!Number.isFinite(a)||a<=0))throw new b("INVALID_INPUT","numBins must be a positive number");let u=Math.max(1,Math.floor(r*Math.log2(s/n))),f=Math.min(a??u,u),m=1/(2*r),p=[];for(let F=0;F<f;F++){let d=n*Math.pow(2,F/r);if(d<=0||d>=s)break;let h=Math.max(0,d*Math.pow(2,-m)),A=Math.min(s,d*Math.pow(2,m)),y=Math.max(1,Math.floor(h/l)),g=Math.min(c,Math.ceil(A/l));g<y||p.push({centerFrequency:d,lowerFrequency:h,upperFrequency:A,startIndex:y,endIndex:g})}if(p.length===0)throw new b("INVALID_INPUT","Failed to build CQT frequency bins. Review fMin/numBins settings.");return St.set(o,p),p}function ar(e,t,n,r,a,o){let i=1/(2*a),s=0,l=0;for(let f=t.startIndex;f<=t.endIndex;f++){let m=f*n/r;if(m<=0)continue;let p=Math.abs(Math.log2(m/t.centerFrequency));if(p>i)continue;let F=1-p/i,d=e[f],h=o===1?d:o===2?d*d:Math.pow(d,o);s+=h*F,l+=F}if(l>1e-10)return s/l;let c=Math.min(Math.floor(t.centerFrequency*r/n),e.length-1),u=c>=0?e[c]:0;return o===1?u:o===2?u*u:Math.pow(u,o)}function or(e,t){let n=e.length,r=new Array(t);for(let a=0;a<t;a++){let o=0;for(let s=0;s<n;s++){let l=e[s];l!==void 0&&(o+=l*Math.cos(Math.PI*a*(s+.5)/n))}let i=Math.sqrt(a===0?1/n:2/n);r[a]=o*i}return r}function Te(e,t){let n=new Float32Array(e.length);if(e.length===0)return n;n[0]=e[0];for(let r=1;r<e.length;r++)n[r]=e[r]-t*e[r-1];return n}async function Lt(e,t={}){let{numMelFilters:n=80,minFrequency:r=0,maxFrequency:a=e.sampleRate/2,preEmphasis:o=.97,provider:i="native",enableProfiling:s=!1,providerCache:l,power:c,logScale:u=!0,logEpsilon:f=1e-10}=t,m=zt(c),p=E(e,t.channel??"mix"),F=Te(p,o),d=Re(e,F.length,t,"hamming"),h=kt(n,d.fftSize,e.sampleRate,r,a),A=[],y=new Float32Array(d.numFrames),g=new Float32Array(d.fftSize),{provider:w,release:M}=await j({fftSize:d.fftSize,sampleRate:e.sampleRate,provider:i,enableProfiling:s,fallbackToNative:i==="webfft",cache:l});try{for(let S=0;S<d.numFrames;S++){let T=S*d.hopSizeSamples;y[S]=T/e.sampleRate,$({src:F,srcStart:T,frameLength:Math.min(d.frameSizeSamples,Math.max(0,F.length-T)),dst:g,windowType:d.windowFunction});let D=await w.fft(g),C=Et(D.magnitude,m),v=Nt(C,h.filters,f),x=new Array(v.length);for(let R=0;R<v.length;R++){let P=v[R];x[R]=u?Math.log(Math.max(P,f)):P}A.push(x)}}finally{M()}return{melSpectrogram:A,times:y,melFrequencies:h.centerFrequencies,frameInfo:{frameSizeMs:d.frameSizeMs,hopSizeMs:d.hopSizeMs,numFrames:d.numFrames,numBins:h.filters.length},frequencyRange:{min:r,max:a}}}async function qt(e,t={}){let{fMin:n=32.70319566257483,binsPerOctave:r=12,numBins:a,preEmphasis:o=.97,provider:i="native",enableProfiling:s=!1,providerCache:l,power:c,logScale:u=!0,logEpsilon:f=1e-10}=t,m=zt(c),p=E(e,t.channel??"mix"),F=Te(p,o),d=Re(e,F.length,t,"hann"),h=rr(d.fftSize,e.sampleRate,n,r,a),A=new Float32Array(h.length);for(let T=0;T<h.length;T++)A[T]=h[T].centerFrequency;let y=[],g=new Float32Array(d.numFrames),w=new Float32Array(d.fftSize),{provider:M,release:S}=await j({fftSize:d.fftSize,sampleRate:e.sampleRate,provider:i,enableProfiling:s,fallbackToNative:i==="webfft",cache:l});try{for(let T=0;T<d.numFrames;T++){let D=T*d.hopSizeSamples;g[T]=D/e.sampleRate,$({src:F,srcStart:D,frameLength:Math.min(d.frameSizeSamples,Math.max(0,F.length-D)),dst:w,windowType:d.windowFunction});let C=await M.fft(w),v=new Array(h.length);for(let x=0;x<h.length;x++){let R=h[x];if(!R)continue;let P=ar(C.magnitude,R,e.sampleRate,d.fftSize,r,m);v[x]=u?Math.log(Math.max(P,f)):P}y.push(v)}}finally{S()}return{cqt:y,times:g,frequencies:A,frameInfo:{frameSizeMs:d.frameSizeMs,hopSizeMs:d.hopSizeMs,numFrames:d.numFrames,numBins:A.length,binsPerOctave:r},frequencyRange:{min:h[0]?.lowerFrequency??n,max:h[h.length-1]?.upperFrequency??e.sampleRate/2}}}function ir(e,t){return e.map((n,r)=>{if(t===0)return n;let a=1+t/2*Math.sin(Math.PI*r/t);return n*a})}async function Pe(e,t={}){let{numMelFilters:n=40,numMfccCoeffs:r=13,minFrequency:a=0,maxFrequency:o=e.sampleRate/2,preEmphasis:i=.97,lifterCoeff:s=22,provider:l="native",enableProfiling:c=!1,providerCache:u}=t,f=E(e,t.channel??"mix"),m=Te(f,i),p=Re(e,m.length,t,"hamming"),F=kt(n,p.fftSize,e.sampleRate,a,o),d=[],h=new Float32Array(p.numFrames),A=new Float32Array(p.fftSize),{provider:y,release:g}=await j({fftSize:p.fftSize,sampleRate:e.sampleRate,provider:l,enableProfiling:c,fallbackToNative:l==="webfft",cache:u});try{for(let w=0;w<p.numFrames;w++){let M=w*p.hopSizeSamples;h[w]=M/e.sampleRate,$({src:m,srcStart:M,frameLength:Math.min(p.frameSizeSamples,Math.max(0,m.length-M)),dst:A,windowType:p.windowFunction});let S=await y.fft(A),T=Et(S.magnitude,2),D=Nt(T,F.filters,1e-10),C=new Array(D.length);for(let R=0;R<D.length;R++)C[R]=Math.log(Math.max(D[R],1e-10));let v=or(C,r),x=ir(v,s);d.push(x)}}finally{g()}return{mfcc:d,times:h,frameInfo:{frameSizeMs:p.frameSizeMs,hopSizeMs:p.hopSizeMs,numFrames:p.numFrames,numCoeffs:r},frequencyRange:{min:a,max:o}}}function sr(e,t=2){let n=e.length,r=e[0]?.length||0,a=[],o=[];for(let i=0;i<n;i++){let s=[];for(let l=0;l<r;l++){let c=0,u=0;for(let f=-t;f<=t;f++){let m=Math.max(0,Math.min(n-1,i+f)),p=e[m]?.[l]||0;c+=f*p,u+=f*f}s[l]=u>0?c/u:0}a.push(s)}for(let i=0;i<n;i++){let s=[];for(let l=0;l<r;l++){let c=0,u=0;for(let f=-t;f<=t;f++){let m=Math.max(0,Math.min(n-1,i+f)),p=a[m]?.[l]||0;c+=f*p,u+=f*f}s[l]=u>0?c/u:0}o.push(s)}return{delta:a,deltaDelta:o}}async function _t(e,t={}){let{deltaWindowSize:n=2,computeDelta:r=!0,computeDeltaDelta:a=!0,...o}=t,i=await Pe(e,o),s={...i};if(r||a){let l=sr(i.mfcc,n);r&&(s.delta=l.delta),a&&(s.deltaDelta=l.deltaDelta)}return s}function lr(e){let t=2*Math.PI,n=(e+Math.PI)%t;return n<0&&(n+=t),n-Math.PI}async function ue(e,t,n,r,a){let o=a??new Float32Array(n);return $({src:e,srcStart:t,frameLength:Math.min(n,Math.max(0,e.length-t)),dst:o,windowType:"hann"}),r.fft(o)}function cr(e,t,n=44){let r=Math.min(e.length,t.length),a=-1/0,o=0;for(let i=-n;i<=n;i++){let s=0,l=0;for(let c=0;c<r;c++){let u=c+i;if(u>=0&&u<r){let f=e[c],m=t[u];s+=f*m,l++}}l>0&&(s/=l,s>a&&(a=s,o=i))}return o}function Bt(e,t,n){let r=Math.min(e.length,t.length),a=n?new Float32Array(r):void 0,o=n?new Float32Array(r):void 0;if(r===0)return{correlation:0,width:0,balance:0,midSideRatio:0,energyL:0,energyR:0,mid:a,side:o};let i=0,s=0,l=0,c=0,u=0,f=0,m=0,p=0,F=0;for(let C=0;C<r;C++){let v=e[C],x=t[C];i+=v,s+=x,l+=v*x,c+=v*v,u+=x*x,f+=v*v,m+=x*x;let R=(v+x)*.5,P=(v-x)*.5;p+=R*R,F+=P*P,a&&o&&(a[C]=R,o[C]=P)}let d=i/r,h=s/r,A=l/r-d*h,y=Math.sqrt(Math.max(0,c/r-d*d)),g=Math.sqrt(Math.max(0,u/r-h*h)),w=y>1e-10&&g>1e-10?A/(y*g):0,M=Math.max(-1,Math.min(1,w)),S=p+F>1e-10?F/(p+F):0,T=f+m>1e-10?(m-f)/(f+m):0,D=F>1e-10?Q(p/F,1):p>1e-10?1/0:0;return{correlation:M,width:S,balance:T,midSideRatio:D,energyL:f,energyR:m,mid:a,side:o}}async function ur(e,t,n,r,a){let o=Math.min(e.length,t.length),i=Math.floor(n/2)+1,s=new Float32Array(i),l=new Float32Array(i),c=new Float32Array(i),u=new Float32Array(i),f=new Float32Array(n),m=new Float32Array(n),p=0,F=0;for(;F<o||p===0;){let g=Math.min(F+n,o),[w,M]=await Promise.all([ue(e,F,n,a,f),ue(t,F,n,a,m)]);for(let S=0;S<i;S++){let T=w.complex[S*2]??0,D=w.complex[S*2+1]??0,C=M.complex[S*2]??0,v=M.complex[S*2+1]??0;s[S]=s[S]+T*C+D*v,l[S]=l[S]+D*C-T*v,c[S]=c[S]+T*T+D*D,u[S]=u[S]+C*C+v*v}if(p++,g>=o)break;F+=r}let d=new Float32Array(i),h=0;for(let g=0;g<i;g++){let w=c[g]*u[g];w>h&&(h=w)}let A=Math.max(1e-10,h*1e-4),y=Math.sqrt(A);for(let g=0;g<i;g++){let w=c[g]*u[g],M=s[g]**2+l[g]**2;if(w<=A){let T=Math.abs(c[g]??0)<=y,D=Math.abs(u[g]??0)<=y;d[g]=T&&D?1:0;continue}let S=M/w;d[g]=Math.min(1,Math.max(0,S))}return d}function mr(e,t,n,r){let a=new Float32Array(e.length);for(let o=0;o<a.length;o++){let i=e[o],s=t[o],l=n[o],c=r[o],u=l-c,f=Math.abs(i+s)/2,m=Math.abs(i-s)/2,p=Math.abs(Math.sin(u/2)),F=m/(f+m+1e-10);a[o]=Math.max(F,p)}return a}async function Wt(e,t={}){if(e.numberOfChannels<2)throw new b("INVALID_INPUT","Stereo analysis requires audio with at least two channels");let{frameSize:n=Math.min(8192,e.length),calculatePhase:r=!1,calculateITD:a=!1,calculateILD:o=!1,provider:i="native",enableProfiling:s=!1,providerCache:l}=t,c=e.channelData[0],u=e.channelData[1];if(!c||!u)throw new b("INVALID_INPUT","L/R channel data is missing");let f=Math.min(c.length,u.length);if(f===0)return{correlation:0,width:0,balance:0,midSideRatio:0};let m=Bt(c,u,!0),p={correlation:m.correlation,width:m.width,balance:m.balance,midSideRatio:m.midSideRatio};if(m.side&&m.mid&&(p.goniometer={x:m.side,y:m.mid}),r){let F=Math.max(32,Math.min(n,f)),d=ie(F),h=Math.max(1,Math.floor(F/2)),{provider:A,release:y}=await j({fftSize:d,sampleRate:e.sampleRate,provider:i,enableProfiling:s,fallbackToNative:i==="webfft",cache:l});try{let[g,w]=await Promise.all([ue(c.subarray(0,F),0,d,A),ue(u.subarray(0,F),0,d,A)]);p.coherence=await ur(c.subarray(0,f),u.subarray(0,f),d,h,A),p.widthFrequency=mr(g.magnitude,w.magnitude,g.phase,w.phase);let M=0,S=0,T=0;for(let D=1;D<g.phase.length;D++){let C=g.magnitude[D],v=w.magnitude[D],x=C*v;if(x<=0)continue;let R=lr(g.phase[D]-w.phase[D]);M+=R*x,S+=Math.cos(R)*x,T+=x}p.phaseDifference=T>1e-10?M/T*180/Math.PI:0,p.phaseCorrelation=T>1e-10?S/T:0}finally{y()}}if(a){let F=Math.max(1,Math.round(e.sampleRate*.001)),d=cr(c.subarray(0,Math.min(n,f)),u.subarray(0,Math.min(n,f)),F);p.itd=d/e.sampleRate*1e3}if(o){let F=Math.sqrt(m.energyL/f),d=Math.sqrt(m.energyR/f);p.ild=F>1e-10&&d>1e-10?q(d/F,1):0}return p}async function Vt(e,t={}){if(e.numberOfChannels<2)throw new b("INVALID_INPUT","Stereo analysis requires audio with at least two channels");let n=e.channelData[0],r=e.channelData[1];if(!n||!r)throw new b("INVALID_INPUT","L/R channel data is missing");let a=Math.min(n.length,r.length);if(a===0)return{times:new Float32Array(0),correlation:new Float32Array(0),width:new Float32Array(0),balance:new Float32Array(0)};let o=Math.max(32,Math.min(t.windowSize??t.frameSize??2048,a)),i=t.hopSize??Math.max(1,Math.floor(o/2));if(i<=0)throw new b("INVALID_INPUT","hopSize must be a positive integer");let s=a<=o?1:Math.floor((a-o)/i)+1,l=new Float32Array(s),c=new Float32Array(s),u=new Float32Array(s),f=new Float32Array(s);for(let m=0;m<s;m++){let p=m*i,F=Math.min(p+o,a),d=Bt(n.subarray(p,F),r.subarray(p,F),!1);l[m]=(p+(F-p)/2)/e.sampleRate,c[m]=d.correlation,u[m]=d.width,f[m]=d.balance}return{times:l,correlation:c,width:u,balance:f}}function Ut(e,t,n=!1){let r=[],a=e.length;if(a<3)return r;for(let o=1;o<a-1;o++){let i=Math.abs(e[o]),s=Math.abs(e[o-1]),l=Math.abs(e[o+1]);if(i>s&&i>l&&i>t){let c={position:o,amplitude:i};n&&(c.prominence=fr(e,o,i)),r.push(c)}}return r}function fr(e,t,n){let r=n;for(let o=t-1;o>=0;o--){let i=Math.abs(e[o]);if(i>n)break;r=Math.min(r,i)}let a=n;for(let o=t+1;o<e.length;o++){let i=Math.abs(e[o]);if(i>n)break;a=Math.min(a,i)}return n-Math.max(r,a)}function Kt(e,t={}){let{count:n=100,threshold:r=.1,channel:a="mix",minDistance:o=Math.floor(e.sampleRate/100)}=t;if(n<=0)throw new b("INVALID_INPUT","Peak count must be a positive integer");if(r<0||r>1)throw new b("INVALID_INPUT","Threshold must be in the range [0, 1]");let i=E(e,a);if(i.length===0)return{peaks:[],maxAmplitude:0,averageAmplit