wavesurfer.js
Version:
Interactive navigable audio visualization using Web Audio and Canvas
7 lines • 10 kB
JavaScript
/*!
* wavesurfer.js spectrogram plugin 6.0.0 (2022-02-07)
* https://wavesurfer-js.org
* @license BSD-3-Clause
*/
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("WaveSurfer",[],t):"object"==typeof exports?exports.WaveSurfer=t():(e.WaveSurfer=e.WaveSurfer||{},e.WaveSurfer.spectrogram=t())}(self,(function(){return(()=>{"use strict";var e={325:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,a,r){switch(this.bufferSize=e,this.sampleRate=t,this.bandwidth=2/e*(t/2),this.sinTable=new Float32Array(e),this.cosTable=new Float32Array(e),this.windowValues=new Float32Array(e),this.reverseTable=new Uint32Array(e),this.peakBand=0,this.peak=0,a){case"bartlett":for(i=0;i<e;i++)this.windowValues[i]=2/(e-1)*((e-1)/2-Math.abs(i-(e-1)/2));break;case"bartlettHann":for(i=0;i<e;i++)this.windowValues[i]=.62-.48*Math.abs(i/(e-1)-.5)-.38*Math.cos(2*Math.PI*i/(e-1));break;case"blackman":for(r=r||.16,i=0;i<e;i++)this.windowValues[i]=(1-r)/2-.5*Math.cos(2*Math.PI*i/(e-1))+r/2*Math.cos(4*Math.PI*i/(e-1));break;case"cosine":for(i=0;i<e;i++)this.windowValues[i]=Math.cos(Math.PI*i/(e-1)-Math.PI/2);break;case"gauss":for(r=r||.25,i=0;i<e;i++)this.windowValues[i]=Math.pow(Math.E,-.5*Math.pow((i-(e-1)/2)/(r*(e-1)/2),2));break;case"hamming":for(i=0;i<e;i++)this.windowValues[i]=.54-.46*Math.cos(2*Math.PI*i/(e-1));break;case"hann":case void 0:for(i=0;i<e;i++)this.windowValues[i]=.5*(1-Math.cos(2*Math.PI*i/(e-1)));break;case"lanczoz":for(i=0;i<e;i++)this.windowValues[i]=Math.sin(Math.PI*(2*i/(e-1)-1))/(Math.PI*(2*i/(e-1)-1));break;case"rectangular":for(i=0;i<e;i++)this.windowValues[i]=1;break;case"triangular":for(i=0;i<e;i++)this.windowValues[i]=2/e*(e/2-Math.abs(i-(e-1)/2));break;default:throw Error("No such window function '"+a+"'")}var i,s=1,n=e>>1;for(;s<e;){for(i=0;i<s;i++)this.reverseTable[i+s]=this.reverseTable[i]+n;s<<=1,n>>=1}for(i=0;i<e;i++)this.sinTable[i]=Math.sin(-Math.PI/i),this.cosTable[i]=Math.cos(-Math.PI/i);this.calculateSpectrum=function(e){var t,a,r,i=this.bufferSize,s=this.cosTable,n=this.sinTable,l=this.reverseTable,o=new Float32Array(i),h=new Float32Array(i),f=2/this.bufferSize,c=Math.sqrt,u=new Float32Array(i/2),p=Math.floor(Math.log(i)/Math.LN2);if(Math.pow(2,p)!==i)throw"Invalid buffer size, must be a power of 2.";if(i!==e.length)throw"Supplied buffer is not the same size as defined FFT. FFT Size: "+i+" Buffer Size: "+e.length;for(var d,v,w,b,m,y,M,g,k=1,x=0;x<i;x++)o[x]=e[l[x]]*this.windowValues[l[x]],h[x]=0;for(;k<i;){d=s[k],v=n[k],w=1,b=0;for(var S=0;S<k;S++){for(x=S;x<i;)y=w*o[m=x+k]-b*h[m],M=w*h[m]+b*o[m],o[m]=o[x]-y,h[m]=h[x]-M,o[x]+=y,h[x]+=M,x+=k<<1;w=(g=w)*d-b*v,b=g*v+b*d}k<<=1}x=0;for(var C=i/2;x<C;x++)(r=f*c((t=o[x])*t+(a=h[x])*a))>this.peak&&(this.peakBand=x,this.peak=r),u[x]=r;return u}},e.exports=t.default},943:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r,i=(r=a(325))&&r.__esModule?r:{default:r};function s(e,t){for(var a=0;a<t.length;a++){var r=t[a];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var n=function(){function e(t,a){var r=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.params=t,this.wavesurfer=a,this.util=a.util,this.frequenciesDataUrl=t.frequenciesDataUrl,this._onScroll=function(e){r.updateScroll(e)},this._onRender=function(){r.render()},this._onWrapperClick=function(e){r._wrapperClickHandler(e)},this._onReady=function(){var e=r.drawer=a.drawer;if(r.container="string"==typeof t.container?document.querySelector(t.container):t.container,!r.container)throw Error("No container for WaveSurfer spectrogram");if(t.colorMap){if(t.colorMap.length<256)throw new Error("Colormap must contain 256 elements");for(var i=0;i<t.colorMap.length;i++){if(4!==t.colorMap[i].length)throw new Error("ColorMap entries must contain 4 values")}r.colorMap=t.colorMap}else{r.colorMap=[];for(var s=0;s<256;s++){var n=(255-s)/256;r.colorMap.push([n,n,n,1])}}r.width=e.width,r.pixelRatio=r.params.pixelRatio||a.params.pixelRatio,r.fftSamples=r.params.fftSamples||a.params.fftSamples||512,r.height=r.fftSamples/2,r.noverlap=t.noverlap,r.windowFunc=t.windowFunc,r.alpha=t.alpha,r.splitChannels=t.splitChannels,r.channels=r.splitChannels?a.backend.buffer.numberOfChannels:1,r.createWrapper(),r.createCanvas(),r.render(),e.wrapper.addEventListener("scroll",r._onScroll),a.on("redraw",r._onRender)}}var t,a,r;return t=e,r=[{key:"create",value:function(t){return{name:"spectrogram",deferInit:!(!t||!t.deferInit)&&t.deferInit,params:t,staticProps:{FFT:i.default},instance:e}}}],(a=[{key:"init",value:function(){this.wavesurfer.isReady?this._onReady():this.wavesurfer.once("ready",this._onReady)}},{key:"destroy",value:function(){this.unAll(),this.wavesurfer.un("ready",this._onReady),this.wavesurfer.un("redraw",this._onRender),this.drawer&&this.drawer.wrapper.removeEventListener("scroll",this._onScroll),this.wavesurfer=null,this.util=null,this.params=null,this.wrapper&&(this.wrapper.removeEventListener("click",this._onWrapperClick),this.wrapper.parentNode.removeChild(this.wrapper),this.wrapper=null)}},{key:"createWrapper",value:function(){var e=this.container.querySelector("spectrogram");e&&this.container.removeChild(e);var t=this.wavesurfer.params;if(this.wrapper=document.createElement("spectrogram"),this.params.labels){var a=this.labelsEl=document.createElement("canvas");a.classList.add("spec-labels"),this.drawer.style(a,{left:0,position:"absolute",zIndex:9,height:"".concat(this.height*this.channels/this.pixelRatio,"px"),width:"".concat(55/this.pixelRatio,"px")}),this.wrapper.appendChild(a),this.loadLabels("rgba(68,68,68,0.5)","12px","10px","","#fff","#f7f7f7","center","#specLabels")}this.drawer.style(this.wrapper,{display:"block",position:"relative",userSelect:"none",webkitUserSelect:"none",height:"".concat(this.height*this.channels/this.pixelRatio,"px")}),(t.fillParent||t.scrollParent)&&this.drawer.style(this.wrapper,{width:"100%",overflowX:"hidden",overflowY:"hidden"}),this.container.appendChild(this.wrapper),this.wrapper.addEventListener("click",this._onWrapperClick)}},{key:"_wrapperClickHandler",value:function(e){e.preventDefault();var t="offsetX"in e?e.offsetX:e.layerX;this.fireEvent("click",t/this.width||0)}},{key:"createCanvas",value:function(){var e=this.canvas=this.wrapper.appendChild(document.createElement("canvas"));this.spectrCc=e.getContext("2d"),this.util.style(e,{position:"absolute",zIndex:4})}},{key:"render",value:function(){this.updateCanvasStyle(),this.frequenciesDataUrl?this.loadFrequenciesData(this.frequenciesDataUrl):this.getFrequencies(this.drawSpectrogram)}},{key:"updateCanvasStyle",value:function(){var e=Math.round(this.width/this.pixelRatio)+"px";this.canvas.width=this.width,this.canvas.height=this.height*this.channels,this.canvas.style.width=e}},{key:"drawSpectrogram",value:function(e,t){isNaN(e[0][0])||(e=[e]);var a=t.spectrCc,r=t.height,i=t.width;if(a)for(var s=0;s<e.length;s++){for(var n=t.resample(e[s]),l=a.createImageData(i,r),o=0;o<n.length;o++)for(var h=0;h<n[o].length;h++){var f=t.colorMap[n[o][h]],c=4*((r-h)*i+o);l.data[c]=255*f[0],l.data[c+1]=255*f[1],l.data[c+2]=255*f[2],l.data[c+3]=255*f[3]}a.putImageData(l,0,r*s)}}},{key:"getFrequencies",value:function(e){var t=this.fftSamples,a=this.buffer=this.wavesurfer.backend.buffer,r=this.channels;if(a){var s=a.sampleRate,n=[],l=this.noverlap;if(!l){var o=a.length/this.canvas.width;l=Math.max(0,Math.round(t-o))}for(var h=new i.default(t,s,this.windowFunc,this.alpha),f=0;f<r;f++){for(var c=a.getChannelData(f),u=[],p=0;p+t<c.length;){var d=c.slice(p,p+t),v=h.calculateSpectrum(d),w=new Uint8Array(t/2),b=void 0;for(b=0;b<t/2;b++)w[b]=Math.max(-255,45*Math.log10(v[b]));u.push(w),p+=t-l}n.push(u)}e(n,this)}else this.fireEvent("error","Web Audio buffer is not available")}},{key:"loadFrequenciesData",value:function(e){var t=this,a=this.util.fetchFile({url:e});return a.on("success",(function(e){return t.drawSpectrogram(JSON.parse(e),t)})),a.on("error",(function(e){return t.fireEvent("error",e)})),a}},{key:"freqType",value:function(e){return e>=1e3?(e/1e3).toFixed(1):Math.round(e)}},{key:"unitType",value:function(e){return e>=1e3?"KHz":"Hz"}},{key:"loadLabels",value:function(e,t,a,r,i,s,n,l){e=e||"rgba(68,68,68,0)",t=t||"12px",a=a||"10px",r=r||"Helvetica",i=i||"#fff",s=s||"#fff",n=n||"center",l=l||"#specLabels";var o=this.height||512,h=o/256*5,f=(this.wavesurfer.backend.ac.sampleRate/2-0)/h,c=this.labelsEl.getContext("2d");if(this.labelsEl.height=this.height*this.channels,this.labelsEl.width=55,c)for(var u=0;u<this.channels;u++){c.fillStyle=e,c.fillRect(0,u*o,55,(1+u)*o),c.fill();var p=void 0;for(p=0;p<=h;p++){c.textAlign=n,c.textBaseline="middle";var d=0+f*p,v=(Math.round(d/(this.sampleRate/2)*this.fftSamples),this.freqType(d)),w=this.unitType(d),b=void 0;0==p?(b=(1+u)*o+p-10,c.fillStyle=s,c.font=a+" "+r,c.fillText(w,40,b),c.fillStyle=i,c.font=t+" "+r,c.fillText(v,16,b)):(b=(1+u)*o-50*p+2,c.fillStyle=s,c.font=a+" "+r,c.fillText(w,40,b),c.fillStyle=i,c.font=t+" "+r,c.fillText(v,16,b))}}}},{key:"updateScroll",value:function(e){this.wrapper&&(this.wrapper.scrollLeft=e.target.scrollLeft)}},{key:"resample",value:function(e){var t,a=this.width,r=[],i=1/e.length,s=1/a;for(t=0;t<a;t++){var n=new Array(e[0].length),l=void 0;for(l=0;l<e.length;l++){var o=l*i,h=o+i,f=t*s,c=f+s,u=h<=f||c<=o?0:Math.min(Math.max(h,f),Math.max(c,o))-Math.max(Math.min(h,f),Math.min(c,o)),p=void 0;if(u>0)for(p=0;p<e[0].length;p++)null==n[p]&&(n[p]=0),n[p]+=u/s*e[l][p]}var d=new Uint8Array(e[0].length),v=void 0;for(v=0;v<e[0].length;v++)d[v]=n[v];r.push(d)}return r}}])&&s(t.prototype,a),r&&s(t,r),Object.defineProperty(t,"prototype",{writable:!1}),e}();t.default=n,e.exports=t.default}},t={};var a=function a(r){var i=t[r];if(void 0!==i)return i.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,a),s.exports}(943);return a})()}));
//# sourceMappingURL=wavesurfer.spectrogram.min.js.map