audio-inspect
Version:
Lightweight yet powerful audio analysis library
2 lines (1 loc) • 4.61 kB
JavaScript
var g=class e extends Error{constructor(c,s,t,r){super(s,{cause:t});this.code=c;this.details=r;this.cause=t,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 P(e,i=0){if(i===-1){if(e.numberOfChannels===0)throw new g("INVALID_INPUT","No channels available");for(let t=0;t<e.numberOfChannels;t++)if(!e.channelData[t])throw new g("INVALID_INPUT",`Channel ${t} data does not exist for averaging`);let s=new Float32Array(e.length);for(let t=0;t<e.length;t++){let r=0;for(let a=0;a<e.numberOfChannels;a++){let n=e.channelData[a];n&&t<n.length&&(r+=n[t]??0)}s[t]=r/e.numberOfChannels}return s}if(i<-1||i>=e.numberOfChannels)throw new g("INVALID_INPUT",`Invalid channel number: ${i}`);let c=e.channelData[i];if(!c)throw new g("INVALID_INPUT",`Channel ${i} data does not exist`);return c}function x(e){return e==null||isNaN(e)||!isFinite(e)?0:e}function R(e,i=.97){let c=new Float32Array(e.length);c[0]=e[0]||0;for(let s=1;s<e.length;s++){let t=x(e[s]??0),r=x(e[s-1]??0);c[s]=t-i*r}return c}function L(e,i,c,s,t=!1){let r=e.length;if(r<i)return{energies:new Float32Array(0),times:new Float32Array(0)};let a=Math.floor((r-i)/c)+1,n=new Float32Array(a),o=new Float32Array(a);for(let u=0;u<a;u++){let f=u*c,p=Math.min(f+i,r),h=0,y=0;for(let d=f;d<p;d++){let A=x(e[d]??0);h+=A*A,y++}h=y>0?h/y:0,t?n[u]=h>1e-10?10*Math.log10(h):-100:n[u]=h,o[u]=(f+i/2)/s}return{energies:n,times:o}}function V(e,i,c,s=!0){let t=e.length;if(t<i)return new Float32Array(0);let r=Math.floor((t-i)/c)+1,a=new Float32Array(r);for(let n=0;n<r;n++){let o=n*c,u=Math.min(o+i,t),f=0,p=Math.sign(x(e[o]??0));for(let h=o+1;h<u;h++){let y=x(e[h]??0),d=Math.sign(y);p!==d&&p!==0&&d!==0&&f++,p=d}a[n]=s?f/Math.max(1,u-o-1):f}return a}function U(e,i,c,s=10){let t=new Float32Array(e.length),r=0,a=Math.min(s,e.length);for(let n=0;n<a;n++){let o=e[n]??0;o!==void 0&&(r+=o)}r=a>0?r/a:0;for(let n=0;n<e.length;n++){let o=e[n]??0;if(o===void 0){t[n]=n>0?t[n-1]??r*c:r*c;continue}if(n===0)t[n]=r*c;else{let u=t[n-1];u!==void 0&&o<u&&(r=i*r+(1-i)*o),t[n]=r*c}}return t}function W(e,i=5){let c=new Float32Array(e.length),s=Math.floor(i/2);for(let t=0;t<e.length;t++){let r=Math.max(0,t-s),a=Math.min(e.length,t+s+1),n=[];for(let o=r;o<a;o++){let u=e[o]??0;u!==void 0&&n.push(u)}if(n.sort((o,u)=>o-u),n.length>0){let o=Math.floor(n.length/2),u=n[o];c[t]=u??0}else c[t]=0}return c}function j(e,i,c=.5,s=.1,t=.3){let r=[],a=null;for(let n=0;n<e.length;n++){let o=e[n]??0,u=i[n]??0;if(o===void 0||u===void 0)continue;let f=o>=c;if(!a)a={start:u,end:u,type:f?"speech":"silence",confidence:Math.abs(o-.5)*2};else if(f&&a.type==="speech"||!f&&a.type==="silence"){a.end=u;let p=Math.abs(o-.5)*2;a.confidence=Math.max(a.confidence||0,p)}else r.push(a),a={start:u,end:u,type:f?"speech":"silence",confidence:Math.abs(o-.5)*2}}return a&&r.push(a),H(r,s,t)}function H(e,i,c){if(e.length===0)return[];let s=[],t=0;for(;t<e.length;){let r=e[t];if(!r){t++;continue}let a=r.end-r.start;if(r.type==="speech"&&a>=i||r.type==="silence"&&a>=c)s.push(r),t++;else{if(s.length>0&&t+1<e.length){let n=s[s.length-1],o=e[t+1];if(n&&o&&n.type===o.type){n.end=o.end,t+=2;continue}}if(s.length>0){let n=s[s.length-1];n&&(n.end=r.end)}t++}}return s}function re(e,i={}){let{channel:c=0,frameSizeMs:s=30,hopSizeMs:t=10,method:r="combined",energyThreshold:a=.02,zcrThresholdLow:n=.05,zcrThresholdHigh:o=.15,adaptiveAlpha:u=.99,noiseFactor:f=3,minSilenceDurationMs:p=300,minSpeechDurationMs:h=100,preEmphasis:y=!0,smoothing:d=!0}=i,A=P(e,c);y&&(A=R(A));let S=e.sampleRate,I=Math.floor(s/1e3*S),C=Math.floor(t/1e3*S);if(I===0||C===0)return{segments:[],speechRatio:0};let{energies:b,times:v}=L(A,I,C,S,!1),w=V(A,I,C,!0);if(b.length===0)return{segments:[],speechRatio:0};let F=new Float32Array(b.length);switch(r){case"energy":{for(let l=0;l<b.length;l++){let m=b[l]??0;F[l]=m>a?1:0}break}case"zcr":{for(let l=0;l<w.length;l++){let m=w[l]??0;F[l]=m>n&&m<o?1:0}break}case"combined":{for(let l=0;l<b.length;l++){let m=b[l]??0,M=w[l]??0,D=m>a?1:0,O=M>n&&M<o?1:0;F[l]=(D+O)/2}break}case"adaptive":{let l=U(b,u,f);for(let m=0;m<b.length;m++){let M=b[m]??0,D=w[m]??0,O=l[m]??0,k=M>O?1:0,B=D>n&&D<o?.5:0;F[m]=Math.min(1,k+B)}break}}let E=d?W(F,5):F,_=h/1e3,q=p/1e3,T=j(E,v,.5,_,q),N=0;for(let l of T)l.type==="speech"&&(N+=l.end-l.start);let z=e.duration>0?Math.min(1,N/e.duration):0;return{segments:T,speechRatio:z,features:{energies:b,zcrs:w,decisions:E,times:v}}}export{re as getVAD};