audio-inspect
Version:
Lightweight yet powerful audio analysis library
2 lines (1 loc) • 7.25 kB
JavaScript
"use strict";var w=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var B=(e,t)=>{for(var n in t)w(e,n,{get:t[n],enumerable:!0})},q=(e,t,n,u)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of k(t))!P.call(e,r)&&r!==n&&w(e,r,{get:()=>t[r],enumerable:!(u=T(t,r))||u.enumerable});return e};var E=e=>q(w({},"__esModule",{value:!0}),e);var $={};B($,{getKWeightingCoeffs:()=>j,getLUFS:()=>H,getLUFSRealtime:()=>D});module.exports=E($);var y=class e extends Error{constructor(n,u,r,s){super(u,{cause:r});this.code=n;this.details=s;this.cause=r,Error.captureStackTrace&&Error.captureStackTrace(this,e)}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}}};function M(e){return e==null||isNaN(e)||!isFinite(e)?0:e}var I=new Map;function N(e){if(!isFinite(e)||e<=0)throw new y("INVALID_INPUT","\u30B5\u30F3\u30D7\u30EB\u30EC\u30FC\u30C8\u306F\u6B63\u306E\u6709\u9650\u5024\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");if(e<8e3||e>384e3)throw new y("UNSUPPORTED_FORMAT",`\u30B5\u30F3\u30D7\u30EB\u30EC\u30FC\u30C8 ${e}Hz \u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093`)}function v(e){N(e);let t=I.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 u=1681.974450955532,r=3.99984385397,s=.7071752369554193,o=Math.tan(Math.PI*u/e),b=Math.pow(10,r/20),a=Math.pow(b,.499666774155),f=1+o/s+o*o;n.push({b0:(b+a*o/s+o*o)/f,b1:2*(o*o-b)/f,b2:(b-a*o/s+o*o)/f,a0:1,a1:2*(o*o-1)/f,a2:(1-o/s+o*o)/f});let c=38.13547087613982,m=.5003270373253953,h=Math.tan(Math.PI*c/e),g=1+h/m+h*h;n.push({b0:1,b1:-2,b2:1,a0:1,a1:2*(h*h-1)/g,a2:(1-h/m+h*h)/g});let i=1/L(n,997,e).magnitude;n[0]&&(n[0].b0*=i,n[0].b1*=i,n[0].b2*=i)}return I.set(e,n),n}function L(e,t,n){let u=2*Math.PI*t/n,r=1,s=0;for(let a of e){let f=Math.cos(u),c=Math.sin(u),m=Math.cos(2*u),h=Math.sin(2*u),g=a.b0+a.b1*f+a.b2*m,p=-a.b1*c-a.b2*h,i=a.a0+a.a1*f+a.a2*m,l=-a.a1*c-a.a2*h,d=i*i+l*l;if(d===0)throw new y("INVALID_INPUT","\u5468\u6CE2\u6570\u5FDC\u7B54\u8A08\u7B97\u3067\u30BC\u30ED\u9664\u7B97\u304C\u767A\u751F\u3057\u307E\u3057\u305F");let A=(g*i+p*l)/d,x=(p*i-g*l)/d,_=r*A-s*x,O=r*x+s*A;r=_,s=O}let o=Math.sqrt(r*r+s*s),b=Math.atan2(s,r);return{magnitude:o,phase:b}}function F(e){return v(e)}var U=-70,z=10,R=400,W=.75,V=3e3,K=400;function C(e,t,n={x1:0,x2:0,y1:0,y2:0}){let u=new Float32Array(e.length),{x1:r,x2:s,y1:o,y2:b}=n;for(let a=0;a<e.length;a++){let f=M(e[a]??0),c=t.b0*f+t.b1*r+t.b2*s-t.a1*o-t.a2*b;u[a]=c,s=r,r=f,b=o,o=c}return n.x1=r,n.x2=s,n.y1=o,n.y2=b,u}function G(e){let t=0,n=e.length;if(n===0)return-1/0;for(let u=0;u<n;u++){let r=e[u];if(!r||r.length===0)continue;let s=0,o=0;for(let a=0;a<r.length;a++){let f=M(r[a]??0);s+=f*f,o++}if(o===0)continue;t+=1*(s/o)}return-.691+10*Math.log10(Math.max(1e-15,t))}function j(e){return F(e)}function H(e,t={}){let{channelMode:n=e.numberOfChannels>=2?"stereo":"mono",calculateShortTerm:u=!1,calculateMomentary:r=!1,calculateLoudnessRange:s=!1,calculateTruePeak:o=!1}=t;if(e.numberOfChannels===0)throw new y("INVALID_INPUT","\u51E6\u7406\u53EF\u80FD\u306A\u30C1\u30E3\u30F3\u30CD\u30EB\u304C\u3042\u308A\u307E\u305B\u3093");let b=D(e.sampleRate,{channelMode:n,maxDurationMs:e.duration*1e3+5e3}),a=[];if(n==="mono"){let i=e.channelData[0];i&&a.push(i)}else{let i=e.channelData[0],l=e.channelData[1];i&&a.push(i),l&&a.push(l)}if(a.length===0)throw new y("INVALID_INPUT","\u51E6\u7406\u53EF\u80FD\u306A\u30C1\u30E3\u30F3\u30CD\u30EB\u304C\u3042\u308A\u307E\u305B\u3093");let f=[],c=a[0].length;if(e.duration<5)f.push(a);else{let i=Math.floor(e.sampleRate*.5);for(let l=0;l<c;l+=i){let d=Math.min(l+i,c),A=a.map(x=>x.subarray(l,d));f.push(A)}}let m=[],h=[],g;for(let i of f)g=b.process(i),r&&isFinite(g.momentary)&&m.push(g.momentary),u&&isFinite(g.shortTerm)&&h.push(g.shortTerm);let p={integrated:g?.integrated??-1/0};if(u&&h.length>0&&(p.shortTerm=new Float32Array(h)),r&&m.length>0&&(p.momentary=new Float32Array(m)),s&&p.shortTerm){let i=Array.from(p.shortTerm).filter(l=>l>-70&&isFinite(l)).sort((l,d)=>l-d);if(i.length>0){let l=Math.floor(i.length*.1),d=Math.floor(i.length*.95),A=i[l]??-1/0,x=i[d]??-1/0;p.loudnessRange=x-A,p.statistics={percentile10:A,percentile95:x}}}return o&&(p.truePeak=a.map(i=>{let l=0;for(let d of i){let A=M(d??0);l=Math.max(l,Math.abs(A))}return l>0?20*Math.log10(l):-1/0})),p}var S=class{sampleRate;channelMode;blockSize;hopSize;blockBuffer=[];maxBlocks;currentSamples=[];sampleCount=0;biquadStates=[];totalSamplesProcessed=0;constructor(t,n="stereo",u=3e4){this.sampleRate=t,this.channelMode=n,this.blockSize=Math.floor(R/1e3*t),this.hopSize=Math.floor(this.blockSize*(1-W)),this.maxBlocks=Math.ceil(u/(this.hopSize/t*1e3));let r=n==="stereo"?2:1;for(let s=0;s<r;s++)this.currentSamples.push(new Float32Array(this.blockSize)),this.biquadStates.push([{x1:0,x2:0,y1:0,y2:0},{x1:0,x2:0,y1:0,y2:0}])}process(t){let n=this.channelMode==="stereo"?Math.min(t.length,2):1,u=F(this.sampleRate);for(let r=0;r<n;r++){let s=t[r];if(!s)continue;let o=C(s,u[0],this.biquadStates[r][0]);o=C(o,u[1],this.biquadStates[r][1]);let b=this.currentSamples[r],a=0;for(;a<o.length;){let f=this.blockSize-this.sampleCount,c=Math.min(o.length-a,f);if(b.set(o.subarray(a,a+c),this.sampleCount),this.sampleCount+=c,a+=c,this.sampleCount>=this.blockSize){let m=G(this.currentSamples.slice(0,n));if(isFinite(m)){let h=this.totalSamplesProcessed+this.blockSize/2;this.blockBuffer.push([m,h]),this.blockBuffer.length>this.maxBlocks&&this.blockBuffer.shift()}b.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=K/1e3*this.sampleRate,u=V/1e3*this.sampleRate,r=this.blockBuffer.filter(([c,m])=>t-m<=n).map(([c])=>c),s=this.blockBuffer.filter(([c,m])=>t-m<=u).map(([c])=>c),o=this.blockBuffer.map(([c])=>c);o=o.filter(c=>c>=U);let b=-1/0;if(o.length>0){let c=o.reduce((p,i)=>p+Math.pow(10,(i+.691)/10),0),h=-.691+10*Math.log10(c/o.length)-z,g=o.filter(p=>p>=h);if(g.length>0){let p=g.reduce((i,l)=>i+Math.pow(10,(l+.691)/10),0);b=-.691+10*Math.log10(p/g.length)}}let a=-1/0;if(r.length>0){let c=r.reduce((m,h)=>m+Math.pow(10,(h+.691)/10),0);a=-.691+10*Math.log10(c/r.length)}let f=-1/0;if(s.length>0){let c=s.reduce((m,h)=>m+Math.pow(10,(h+.691)/10),0);f=-.691+10*Math.log10(c/s.length)}return{integrated:b,momentary:a,shortTerm:f}}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 D(e,t={}){let{channelMode:n="stereo",maxDurationMs:u=3e4}=t;return new S(e,n,u)}