audio-inspect
Version:
Lightweight yet powerful audio analysis library
2 lines (1 loc) • 11.2 kB
JavaScript
;var w=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var n in t)w(e,n,{get:t[n],enumerable:!0})},V=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of L(t))!B.call(e,a)&&a!==n&&w(e,a,{get:()=>t[a],enumerable:!(r=_(t,a))||r.enumerable});return e};var W=e=>V(w({},"__esModule",{value:!0}),e);var J={};U(J,{getPeak:()=>G,getPeakAmplitude:()=>G,getPeaks:()=>$,getPeaksAnalysis:()=>H,getRMS:()=>X,getRMSAnalysis:()=>Y,getWaveform:()=>Q,getWaveformAnalysis:()=>Z,getZeroCrossing:()=>K});module.exports=W(J);var d=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 y(){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 q(e){return Array.isArray(e)}function I(e,t="mix"){if(e.numberOfChannels<=0)throw new d("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 d("INVALID_INPUT",'Channel selector "all" is not supported for scalar results; use "mix" or a single channel index');if(q(t)){if(t.length===0)throw new d("INVALID_INPUT","Channel selection array cannot be empty");if(t.length>1)throw new d("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 d("INVALID_INPUT",`Invalid channel number: ${t}`);r=[t]}else throw new d("INVALID_INPUT",`Invalid channel selector: ${String(t)}`)}for(let o of r){if(o<0||o>=e.numberOfChannels)throw new d("INVALID_INPUT",`Invalid channel number: ${o}`);if(!e.channelData[o])throw new d("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 S(e,t,n){return t<0||t>=e.length?n:e[t]??n}function k(e,t=1,n=-1/0){return!Number.isFinite(e)||!Number.isFinite(t)||e<=0||t<=0?n:20*Math.log10(e/t)}function j(e){if(![2,4,8].includes(e))throw new d("INVALID_INPUT","Oversampling factor must be 2, 4, or 8. Sinc interpolation quality is not guaranteed for other values.")}function O(e,t={}){if(e.length===0)return 0;let{factor:n=4,interpolation:r="cubic"}=t;j(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 m=Math.PI*l;return Math.abs(l)<3?3*Math.sin(m/3)*Math.sin(m)/(m*m):0},s=(e.length-1)*n+1;for(let l=0;l<s;l++){let m=l/n,u=0;for(let p=-3;p<=3;p++){let f=Math.floor(m)+p;f>=0&&f<e.length&&(u+=e[f]*i(m-f))}let h=Math.abs(u);h>a&&(a=h)}return a}for(let i=0;i<e.length-1;i++){let s=e[i],l=e[i+1],m=s,u=l;r==="cubic"&&(m=e[Math.max(0,i-1)],u=e[Math.min(e.length-1,i+2)]);for(let h=0;h<n;h++){let p=h/n,f=r==="linear"?s+(l-s)*p:.5*(2*s+(-m+l)*p+(2*m-5*s+4*l-u)*p*p+(-m+3*s-3*l+u)*p*p*p),b=Math.abs(f);b>a&&(a=b)}}let o=Math.abs(e[e.length-1]);return o>a&&(a=o),a}var ie=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 T(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 m={position:o,amplitude:i};n&&(m.prominence=z(e,o,i)),r.push(m)}}return r}function z(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 $(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 d("INVALID_INPUT","Peak count must be a positive integer");if(r<0||r>1)throw new d("INVALID_INPUT","Threshold must be in the range [0, 1]");let i=I(e,a);if(i.length===0)return{peaks:[],maxAmplitude:0,averageAmplitude:0};let s=T(i,r);if(s.length===0)return{peaks:[],maxAmplitude:0,averageAmplitude:0};s.sort((p,f)=>f.amplitude-p.amplitude);let l=[],m=[];for(let p of s){if(l.length>=n)break;let f=p.position-o,b=p.position+o;m.some(([x,P])=>!(b<x||f>P))||(l.push({position:p.position,time:p.position/e.sampleRate,amplitude:p.amplitude}),m.push([f,b]))}l.sort((p,f)=>p.position-f.position);let u=s.length>0?s[0]?.amplitude??0:0,h=s.length>0?s.reduce((p,f)=>p+f.amplitude,0)/s.length:0;return{peaks:l,maxAmplitude:u,averageAmplitude:h}}var M=-1/0;function X(e,t={}){if(typeof t!="object"||t===null||Array.isArray(t))throw new d("INVALID_INPUT","RMS options must be an object");let n={channel:t.channel??"mix",asDB:t.asDB??!1,reference:t.reference??1,truePeak:t.truePeak??!1,oversamplingFactor:t.oversamplingFactor??4,interpolation:t.interpolation??"cubic"},r=I(e,n.channel);if(r.length===0)return n.asDB?M:0;let a=0,o=0;for(let s=0;s<r.length;s++){let l=r[s];Number.isFinite(l)&&(a+=l*l,o++)}if(o===0)return n.asDB?M:0;let i=Math.sqrt(a/o);return n.asDB?k(i,n.reference):i}function G(e,t={}){let n={channel:t.channel??"mix",asDB:t.asDB??!1,reference:t.reference??1,truePeak:t.truePeak??!1,oversamplingFactor:t.oversamplingFactor??4,interpolation:t.interpolation??"cubic"},r=I(e,n.channel);if(r.length===0)return n.asDB?M:0;let a;if(n.truePeak)a=O(r,{factor:n.oversamplingFactor,interpolation:n.interpolation});else{a=0;for(let o=0;o<r.length;o++)a=Math.max(a,Math.abs(r[o]))}return n.asDB?k(a,n.reference):a}function K(e,t="mix"){let n=I(e,t);if(n.length<2)return 0;let r=0;for(let a=1;a<n.length;a++){let o=n[a-1],i=n[a];(o>=0&&i<0||o<0&&i>=0)&&r++}return r/(n.length-1)}function Q(e,t={}){let{framesPerSecond:n=60,channel:r="mix",method:a="rms"}=t,o=I(e,r),i=Math.ceil(e.duration*n),s=e.length>0?e.length:i>0?1:0,l=Math.min(i,s),m=l>0?Math.max(1,Math.floor(e.length/l)):0,u=[],h=0,p=0;for(let b=0;b<l;b++){let A=b*m,x=Math.min(A+m,o.length);if(x<=A){let R=u.length>0?S(u,u.length-1,{time:0,amplitude:0}).amplitude:0;u.push({time:(A+m/2)/e.sampleRate,amplitude:R});continue}let P=o.subarray(A,x),c;switch(a){case"peak":c=C(P);break;case"average":c=E(P);break;case"rms":default:c=N(P);break}let g=(A+(x-A)/2)/e.sampleRate;u.push({time:g,amplitude:c}),h=Math.max(h,c),p+=c}let f=l>0?p/l:0;return{waveform:u,maxAmplitude:h,averageAmplitude:f,frameCount:l,samplesPerFrame:m}}function N(e){if(e.length===0)return 0;let t=0;for(let n=0;n<e.length;n++){let r=e[n];t+=r*r}return Math.sqrt(t/e.length)}function C(e){let t=0;for(let n=0;n<e.length;n++){let r=Math.abs(e[n]);t=Math.max(t,r)}return t}function E(e){if(e.length===0)return 0;let t=0;for(let n=0;n<e.length;n++)t+=Math.abs(e[n]);return t/e.length}function Z(e,t={}){let n=y(),{framesPerSecond:r=60,channel:a="mix",method:o="rms",onProgress:i}=t;i?.(0,"Starting waveform analysis");let s=I(e,a),l=Math.ceil(e.duration*r),m=e.length>0?e.length:l>0?1:0,u=Math.min(l,m),h=u>0?Math.max(1,Math.floor(e.length/u)):0;i?.(25,"Frame configuration complete");let p=new Float32Array(u),f=new Float32Array(u),b=0,A=0;i?.(50,"Starting amplitude calculation");for(let c=0;c<u;c++){let g=c*h,R=Math.min(g+h,s.length);if(R<=g){let D=c>0?p[c-1]:0;p[c]=D,f[c]=(g+h/2)/e.sampleRate;continue}let v=s.subarray(g,R),F;switch(o){case"peak":F=C(v);break;case"average":F=E(v);break;case"rms":default:F=N(v);break}if(p[c]=F,f[c]=(g+(R-g)/2)/e.sampleRate,b=Math.max(b,F),A+=F,c%Math.max(1,Math.floor(u/20))===0){let D=50+c/u*45;i?.(Math.round(D),`Processing frame ${c+1}/${u}`)}}let x=u>0?A/u:0,P=y()-n;return i?.(100,"Processing complete"),{amplitudes:p,timestamps:f,frameCount:u,samplesPerFrame:h,framesPerSecond:r,maxAmplitude:b,averageAmplitude:x,sampleRate:e.sampleRate,duration:e.duration,processingTime:P}}function H(e,t={}){let n=y(),{count:r=100,threshold:a=.1,channel:o="mix",minDistance:i=Math.floor(e.sampleRate/100),onProgress:s}=t;if(s?.(0,"Starting peaks analysis"),r<=0)throw new d("INVALID_INPUT","Peak count must be a positive integer");if(a<0||a>1)throw new d("INVALID_INPUT","Threshold must be in the range [0, 1]");let l=I(e,o);if(l.length===0)return{positions:new Float32Array(0),amplitudes:new Float32Array(0),times:new Float32Array(0),maxAmplitude:0,averageAmplitude:0,count:0,sampleRate:e.sampleRate,duration:e.duration,processingTime:y()-n};s?.(25,"Detecting peak candidates");let m=T(l,a);if(m.length===0)return{positions:new Float32Array(0),amplitudes:new Float32Array(0),times:new Float32Array(0),maxAmplitude:0,averageAmplitude:0,count:0,sampleRate:e.sampleRate,duration:e.duration,processingTime:y()-n};s?.(50,"Sorting peaks"),m.sort((c,g)=>g.amplitude-c.amplitude),s?.(75,"Selecting peaks");let u=[],h=[];for(let c of m){if(u.length>=r)break;let g=c.position-i,R=c.position+i;h.some(([F,D])=>!(R<F||g>D))||(u.push({position:c.position,time:c.position/e.sampleRate,amplitude:c.amplitude}),h.push([g,R]))}u.sort((c,g)=>c.position-g.position);let p=new Float32Array(u.length),f=new Float32Array(u.length),b=new Float32Array(u.length);for(let c=0;c<u.length;c++){let g=u[c];g&&(p[c]=g.position,f[c]=g.amplitude,b[c]=g.time)}let A=m.length>0?m[0]?.amplitude??0:0,x=m.length>0?m.reduce((c,g)=>c+g.amplitude,0)/m.length:0,P=y()-n;return s?.(100,"Processing complete"),{positions:p,amplitudes:f,times:b,maxAmplitude:A,averageAmplitude:x,count:u.length,sampleRate:e.sampleRate,duration:e.duration,processingTime:P}}function Y(e,t={}){let n=y(),{channel:r="mix",asDB:a=!1,reference:o=1,onProgress:i}=t,s=typeof r=="number"?r:-1;i?.(0,"Starting RMS analysis");let l=I(e,r);if(l.length===0)return{value:a?-1/0:0,channel:s,sampleRate:e.sampleRate,duration:e.duration,processingTime:y()-n};i?.(50,"Computing RMS value");let m=0,u=0;for(let f=0;f<l.length;f++){let b=l[f];Number.isFinite(b)&&(m+=b*b,u++)}if(u===0){let f=a?-1/0:0,b=y()-n;return i?.(100,"Processing complete"),a?{value:f,channel:s,sampleRate:e.sampleRate,duration:e.duration,processingTime:b}:{value:f,valueDB:-1/0,channel:s,sampleRate:e.sampleRate,duration:e.duration,processingTime:b}}let h=Math.sqrt(m/u),p=y()-n;return i?.(100,"Processing complete"),a?{value:k(h,o),channel:s,sampleRate:e.sampleRate,duration:e.duration,processingTime:p}:{value:h,valueDB:k(h,o),channel:s,sampleRate:e.sampleRate,duration:e.duration,processingTime:p}}