UNPKG

audio-inspect

Version:

Lightweight yet powerful audio analysis library

2 lines (1 loc) 6 kB
"use strict";var w=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var $=(e,o)=>{for(var l in o)w(e,l,{get:o[l],enumerable:!0})},G=(e,o,l,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of q(o))!W.call(e,a)&&a!==l&&w(e,a,{get:()=>o[a],enumerable:!(r=B(o,a))||r.enumerable});return e};var K=e=>G(w({},"__esModule",{value:!0}),e);var ne={};$(ne,{getVAD:()=>re});module.exports=K(ne);var c=class e extends Error{name="AudioInspectError";code;cause;details;constructor(o,l,r,a){super(l,{cause:r}),this.code=o,this.cause=r,this.details=a,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};function Q(e){return Array.isArray(e)}function C(e,o="mix"){if(e.numberOfChannels<=0)throw new c("INVALID_INPUT","No channels available");let l=Array.from({length:e.numberOfChannels},(n,i)=>i),r;if(o==="mix")r=l;else{if(o==="all")throw new c("INVALID_INPUT",'Channel selector "all" is not supported for scalar results; use "mix" or a single channel index');if(Q(o)){if(o.length===0)throw new c("INVALID_INPUT","Channel selection array cannot be empty");if(o.length>1)throw new c("INVALID_INPUT",'Multi-channel selector arrays are not supported for scalar results; use "mix" or a single channel index');r=o.slice()}else if(typeof o=="number"){if(!Number.isInteger(o))throw new c("INVALID_INPUT",`Invalid channel number: ${o}`);r=[o]}else throw new c("INVALID_INPUT",`Invalid channel selector: ${String(o)}`)}for(let n of r){if(n<0||n>=e.numberOfChannels)throw new c("INVALID_INPUT",`Invalid channel number: ${n}`);if(!e.channelData[n])throw new c("INVALID_INPUT",`Channel ${n} data does not exist`)}if(r.length===1){let n=r[0];return e.channelData[n]}let a=new Float32Array(e.length);for(let n=0;n<e.length;n++){let i=0;for(let t of r){let s=e.channelData[t];s&&n<s.length&&(i+=s[n])}a[n]=i/r.length}return a}function z(e,o=1,l=-1/0){return!Number.isFinite(e)||!Number.isFinite(o)||e<=0||o<=0?l:10*Math.log10(e/o)}function R(e,o){let{samples:l,frameSize:r,hopSize:a,sampleRate:n,padEnd:i=!0}=e;if(!Number.isInteger(r)||r<=0)throw new c("INVALID_INPUT","frameSize must be a positive integer");if(!Number.isInteger(a)||a<=0)throw new c("INVALID_INPUT","hopSize must be a positive integer");if(!Number.isFinite(n)||n<=0)throw new c("INVALID_INPUT","sampleRate must be positive");if(l.length===0)return 0;let t=new Float32Array(r),s=0,u=0;for(;u<l.length||s===0&&i;){let p=Math.min(u+r,l.length),h=Math.max(0,p-u);if(h<r&&!i&&s>0||(t.fill(0),h>0&&t.set(l.subarray(u,p),0),o({frame:t,frameIndex:s,startSample:u,timeSec:(u+r/2)/n}),s+=1,u+=a,!i&&u+r>l.length)||h<r&&i)break}return s}function H(e,o=.97){let l=new Float32Array(e.length);if(e.length===0)return l;l[0]=e[0];for(let r=1;r<e.length;r++)l[r]=e[r]-o*e[r-1];return l}function Z(e,o,l,r,a=!1){let n=[],i=[];return e.length===0?{energies:new Float32Array(0),times:new Float32Array(0)}:(R({samples:e,frameSize:o,hopSize:l,sampleRate:r,padEnd:!0},({frame:t,timeSec:s})=>{let u=0;for(let p=0;p<t.length;p++){let h=t[p];u+=h*h}u/=t.length,n.push(a?z(u,1,-100):u),i.push(s)}),{energies:new Float32Array(n),times:new Float32Array(i)})}function j(e,o,l,r=!0){let a=[];return e.length===0?new Float32Array(0):(R({samples:e,frameSize:o,hopSize:l,sampleRate:1,padEnd:!0},({frame:n})=>{let i=0,t=Math.sign(n[0]??0);for(let s=1;s<n.length;s++){let u=Math.sign(n[s]??0);t!==u&&t!==0&&u!==0&&(i+=1),t=u}a.push(r?i/Math.max(1,n.length-1):i)}),new Float32Array(a))}function X(e,o,l,r=10){let a=new Float32Array(e.length),n=0,i=Math.min(r,e.length);for(let t=0;t<i;t++)n+=e[t];n=i>0?n/i:0;for(let t=0;t<e.length;t++){let s=e[t];if(t===0)a[t]=n*l;else{let u=a[t-1];u!==void 0&&s<u&&(n=o*n+(1-o)*s),a[t]=n*l}}return a}function Y(e,o=5){let l=new Float32Array(e.length),r=Math.floor(o/2);for(let a=0;a<e.length;a++){let n=Math.max(0,a-r),i=Math.min(e.length,a+r+1),t=[];for(let s=n;s<i;s++)t.push(e[s]);if(t.sort((s,u)=>s-u),t.length>0){let s=Math.floor(t.length/2);l[a]=t[s]}else l[a]=0}return l}function J(e,o,l=.5,r=.1,a=.3){let n=[],i=null;for(let t=0;t<e.length;t++){let s=e[t],u=o[t],p=s>=l;if(!i)i={start:u,end:u,type:p?"speech":"silence",confidence:Math.abs(s-.5)*2};else if(p&&i.type==="speech"||!p&&i.type==="silence"){i.end=u;let h=Math.abs(s-.5)*2;i.confidence=Math.max(i.confidence||0,h)}else n.push(i),i={start:u,end:u,type:p?"speech":"silence",confidence:Math.abs(s-.5)*2}}return i&&n.push(i),ee(n,r,a)}function ee(e,o,l){if(e.length===0)return[];let r=[],a=0;for(;a<e.length;){let n=e[a];if(!n){a++;continue}let i=n.end-n.start;if(n.type==="speech"&&i>=o||n.type==="silence"&&i>=l)r.push(n),a++;else{if(r.length>0&&a+1<e.length){let t=r[r.length-1],s=e[a+1];if(t&&s&&t.type===s.type){t.end=s.end,a+=2;continue}}if(r.length>0){let t=r[r.length-1];t&&(t.end=n.end)}a++}}return r}function re(e,o={}){let{channel:l="mix",frameSizeMs:r=30,hopSizeMs:a=10,method:n="combined",energyThreshold:i=.02,zcrThresholdLow:t=.05,zcrThresholdHigh:s=.15,adaptiveAlpha:u=.99,noiseFactor:p=3,minSilenceDurationMs:h=300,minSpeechDurationMs:O=100,preEmphasis:P=!0,smoothing:V=!0}=o,d=C(e,l);P&&(d=H(d));let S=e.sampleRate,I=Math.floor(r/1e3*S),x=Math.floor(a/1e3*S);if(I===0||x===0)return{segments:[],speechRatio:0};let{energies:b,times:E}=Z(d,I,x,S,!1),y=j(d,I,x,!0);if(b.length===0)return{segments:[],speechRatio:0};let A=new Float32Array(b.length);switch(n){case"energy":{for(let m=0;m<b.length;m++){let f=b[m];A[m]=f>i?1:0}break}case"zcr":{for(let m=0;m<y.length;m++){let f=y[m];A[m]=f>t&&f<s?1:0}break}case"combined":{for(let m=0;m<b.length;m++){let f=b[m],g=y[m],F=f>i?1:0,D=g>t&&g<s?1:0;A[m]=(F+D)/2}break}case"adaptive":{let m=X(b,u,p);for(let f=0;f<b.length;f++){let g=b[f],F=y[f],D=m[f],v=g>D?1:0,U=F>t&&F<s?.5:0;A[f]=Math.min(1,v+U)}break}}let T=V?Y(A,5):A,_=O/1e3,L=h/1e3,N=J(T,E,.5,_,L),M=0;for(let m of N)m.type==="speech"&&(M+=m.end-m.start);let k=e.duration>0?Math.min(1,M/e.duration):0;return{segments:N,speechRatio:k,features:{energies:b,zcrs:y,decisions:T,times:E}}}