UNPKG

audio-inspect

Version:

Lightweight yet powerful audio analysis library

2 lines (1 loc) 8.36 kB
"use strict";var v=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var i in t)v(e,i,{get:t[i],enumerable:!0})},W=(e,t,i,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of B(t))!V.call(e,n)&&n!==i&&v(e,n,{get:()=>t[n],enumerable:!(a=q(t,n))||a.enumerable});return e};var z=e=>W(v({},"__esModule",{value:!0}),e);var Z={};U(Z,{getCrestFactor:()=>H});module.exports=z(Z);var f=class e extends Error{name="AudioInspectError";code;cause;details;constructor(t,i,a,n){super(i,{cause:a}),this.code=t,this.cause=a,this.details=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};function j(e){return Array.isArray(e)}function P(e,t="mix"){if(e.numberOfChannels<=0)throw new f("INVALID_INPUT","No channels available");let i=Array.from({length:e.numberOfChannels},(r,c)=>c),a;if(t==="mix")a=i;else{if(t==="all")throw new f("INVALID_INPUT",'Channel selector "all" is not supported for scalar results; use "mix" or a single channel index');if(j(t)){if(t.length===0)throw new f("INVALID_INPUT","Channel selection array cannot be empty");if(t.length>1)throw new f("INVALID_INPUT",'Multi-channel selector arrays are not supported for scalar results; use "mix" or a single channel index');a=t.slice()}else if(typeof t=="number"){if(!Number.isInteger(t))throw new f("INVALID_INPUT",`Invalid channel number: ${t}`);a=[t]}else throw new f("INVALID_INPUT",`Invalid channel selector: ${String(t)}`)}for(let r of a){if(r<0||r>=e.numberOfChannels)throw new f("INVALID_INPUT",`Invalid channel number: ${r}`);if(!e.channelData[r])throw new f("INVALID_INPUT",`Channel ${r} data does not exist`)}if(a.length===1){let r=a[0];return e.channelData[r]}let n=new Float32Array(e.length);for(let r=0;r<e.length;r++){let c=0;for(let s of a){let o=e.channelData[s];o&&r<o.length&&(c+=o[r])}n[r]=c/a.length}return n}function I(e,t=1,i=-1/0){return!Number.isFinite(e)||!Number.isFinite(t)||e<=0||t<=0?i:20*Math.log10(e/t)}var O=new Map;function $(e){if(e<=0||!isFinite(e))throw new f("INVALID_INPUT","Sample rate must be a positive finite value");if(e<8e3||e>384e3)throw new f("UNSUPPORTED_FORMAT",`Sample rate ${e} Hz is not supported`)}function G(e){$(e);let t=O.get(e);if(t)return t;let i=20.598997,a=107.65265,n=737.86223,r=12194.217,c=1.9997,s=[],o=2*e*Math.tan(Math.PI*i/e),p=2*e*Math.tan(Math.PI*a/e),h=2*e*Math.tan(Math.PI*n/e),d=2*e*Math.tan(Math.PI*r/e),u=Math.pow(10,c/20);{let m=o,l=m*m,b=Math.SQRT2,A=4*e*e+2*b*m*e+l,x=2*(l-4*e*e)/A,w=(4*e*e-2*b*m*e+l)/A;s.push({b0:4*e*e*u/A,b1:-8*e*e*u/A,b2:4*e*e*u/A,a0:1,a1:x,a2:w})}{let m=p,l=2*e+m,b=(m-2*e)/l;s.push({b0:2*e/l,b1:-2*e/l,b2:0,a0:1,a1:b,a2:0})}{let m=h,l=2*e+m,b=(m-2*e)/l;s.push({b0:2*e/l,b1:-2*e/l,b2:0,a0:1,a1:b,a2:0})}{let m=d,l=m*m,b=Math.SQRT2,A=4*e*e+2*b*m*e+l,x=2*(l-4*e*e)/A,w=(4*e*e-2*b*m*e+l)/A;s.push({b0:l/A,b1:2*l/A,b2:l/A,a0:1,a1:x,a2:w})}let y=1/Q(s,1e3,e).magnitude;return s.forEach(m=>{m.b0*=y,m.b1*=y,m.b2*=y}),O.set(e,s),s}function Q(e,t,i){let a=2*Math.PI*t/i,n=1,r=0;for(let o of e){let p=Math.cos(a),h=Math.sin(a),d=Math.cos(2*a),u=Math.sin(2*a),g=o.b0+o.b1*p+o.b2*d,y=-o.b1*h-o.b2*u,m=o.a0+o.a1*p+o.a2*d,l=-o.a1*h-o.a2*u,b=m*m+l*l;if(b===0)throw new f("INVALID_INPUT","Division by zero occurred while calculating frequency response");let A=(g*m+y*l)/b,x=(y*m-g*l)/b,w=n*A-r*x,D=n*x+r*A;n=w,r=D}let c=Math.sqrt(n*n+r*r),s=Math.atan2(r,n);return{magnitude:c,phase:s}}function X(e,t,i={x1:0,x2:0,y1:0,y2:0}){let{x1:a,x2:n,y1:r,y2:c}=i;for(let s=0;s<e.length;s++){let o=e[s],p=t.b0*o+t.b1*a+t.b2*n-t.a1*r-t.a2*c;e[s]=p,n=a,a=o,c=r,r=p}i.x1=a,i.x2=n,i.y1=r,i.y2=c}function S(e,t){let i=G(t),a=e.slice();for(let n of i)X(a,n);return a}function K(e){if(![2,4,8].includes(e))throw new f("INVALID_INPUT","Oversampling factor must be 2, 4, or 8. Sinc interpolation quality is not guaranteed for other values.")}function T(e,t={}){if(e.length===0)return 0;let{factor:i=4,interpolation:a="cubic"}=t;K(i);let n=0;if(i<=1||e.length===1){for(let c=0;c<e.length;c++){let s=Math.abs(e[c]);s>n&&(n=s)}return n}if(a==="sinc"){let c=o=>{if(Math.abs(o)<1e-10)return 1;let p=Math.PI*o;return Math.abs(o)<3?3*Math.sin(p/3)*Math.sin(p)/(p*p):0},s=(e.length-1)*i+1;for(let o=0;o<s;o++){let p=o/i,h=0;for(let u=-3;u<=3;u++){let g=Math.floor(p)+u;g>=0&&g<e.length&&(h+=e[g]*c(p-g))}let d=Math.abs(h);d>n&&(n=d)}return n}for(let c=0;c<e.length-1;c++){let s=e[c],o=e[c+1],p=s,h=o;a==="cubic"&&(p=e[Math.max(0,c-1)],h=e[Math.min(e.length-1,c+2)]);for(let d=0;d<i;d++){let u=d/i,g=a==="linear"?s+(o-s)*u:.5*(2*s+(-p+o)*u+(2*p-5*s+4*o-h)*u*u+(-p+3*s-3*o+h)*u*u*u),y=Math.abs(g);y>n&&(n=y)}}let r=Math.abs(e[e.length-1]);return r>n&&(n=r),n}var le=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])]);var C=-1/0;function N(e,t={}){if(typeof t!="object"||t===null||Array.isArray(t))throw new f("INVALID_INPUT","RMS options must be an object");let i={channel:t.channel??"mix",asDB:t.asDB??!1,reference:t.reference??1,truePeak:t.truePeak??!1,oversamplingFactor:t.oversamplingFactor??4,interpolation:t.interpolation??"cubic"},a=P(e,i.channel);if(a.length===0)return i.asDB?C:0;let n=0,r=0;for(let s=0;s<a.length;s++){let o=a[s];Number.isFinite(o)&&(n+=o*o,r++)}if(r===0)return i.asDB?C:0;let c=Math.sqrt(n/r);return i.asDB?I(c,i.reference):c}function R(e,t={}){let i={channel:t.channel??"mix",asDB:t.asDB??!1,reference:t.reference??1,truePeak:t.truePeak??!1,oversamplingFactor:t.oversamplingFactor??4,interpolation:t.interpolation??"cubic"},a=P(e,i.channel);if(a.length===0)return i.asDB?C:0;let n;if(i.truePeak)n=T(a,{factor:i.oversamplingFactor,interpolation:i.interpolation});else{n=0;for(let r=0;r<a.length;r++)n=Math.max(n,Math.abs(a[r]))}return i.asDB?I(n,i.reference):n}function _(e,t,i="simple"){if(e.length===0)return{peak:0,rms:0,cfDb:-1/0,cfLinear:0};let n=e;i==="weighted"&&(n=S(e,t));let r=0,c=0;for(let h=0;h<n.length;h++){let d=n[h],u=Math.abs(d);r=Math.max(r,u),c+=d*d}if(n.length===0)return{peak:0,rms:0,cfDb:-1/0,cfLinear:0};let s=Math.sqrt(c/n.length);if(r<1e-10&&s<1e-10)return{peak:0,rms:0,cfDb:-1/0,cfLinear:0};if(s<1e-10)return{peak:r,rms:s,cfDb:-1/0,cfLinear:0};let o=r/s,p=I(o,1);return{peak:r,rms:s,cfDb:p,cfLinear:o}}function H(e,t={}){let{channel:a="mix",windowSize:n,hopSize:r,method:c="simple"}=t,s,o;if(c==="weighted"){let u=P(e,a),g=S(u,e.sampleRate),y=0,m=0;for(let l=0;l<g.length;l++){let b=g[l],A=Math.abs(b);y=Math.max(y,A),m+=b*b}s=y,o=g.length>0?Math.sqrt(m/g.length):0}else{let u={channel:a,asDB:!1};s=R(e,u),o=N(e,u)}let p,h;s<1e-10&&o<1e-10||o<1e-10?(p=0,h=-1/0):(p=s/o,h=I(p,1));let d;if(typeof n=="number"&&typeof r=="number"){if(n<=0||r<=0)throw new f("INVALID_INPUT","windowSize and hopSize must be positive values");r>n&&console.warn("[audio-inspect] hopSize is larger than windowSize, so gaps will occur between analysis windows");let u=Math.floor(n*e.sampleRate),g=Math.floor(r*e.sampleRate);if(u===0||g===0)throw new f("INVALID_INPUT","Window size is too small for the sample rate");let y=P(e,a),m=y.length;if(m<u){let l=_(y,e.sampleRate,c);d={times:new Float32Array([e.duration/2]),values:new Float32Array([l.cfDb]),valuesLinear:new Float32Array([l.cfLinear]),peaks:new Float32Array([l.peak]),rmsValues:new Float32Array([l.rms])}}else{let l=Math.floor((m-u)/g)+1,b=new Float32Array(l),A=new Float32Array(l),x=new Float32Array(l),w=new Float32Array(l),D=new Float32Array(l);for(let F=0;F<l;F++){let k=F*g,E=Math.min(k+u,m),L=y.subarray(k,E),M=_(L,e.sampleRate,c);b[F]=(k+u/2)/e.sampleRate,A[F]=M.cfDb,x[F]=M.cfLinear,w[F]=M.peak,D[F]=M.rms}d={times:b,values:A,valuesLinear:x,peaks:w,rmsValues:D}}}return{crestFactor:h,crestFactorLinear:p,peak:s,rms:o,timeVarying:d}}