UNPKG

react-audio-wave

Version:
2 lines (1 loc) 15.1 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@babel/runtime-corejs3/helpers/extends"),require("react"),require("classnames"),require("resize-observer-polyfill"),require("@babel/runtime-corejs3/helpers/defineProperty"),require("webaudio-peaks")):"function"==typeof define&&define.amd?define(["exports","@babel/runtime-corejs3/helpers/extends","react","classnames","resize-observer-polyfill","@babel/runtime-corejs3/helpers/defineProperty","webaudio-peaks"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactAudioWave={},e._extends,e.React,e.classnames,e["resize-observer-polyfill"],e._defineProperty,e["webaudio-peaks"])}(this,(function(e,t,r,i,s,n,a){"use strict";const o=(e,t)=>{const[i,n]=r.useState({width:void 0,height:void 0});return r.useLayoutEffect((()=>{let r;if(r="function"==typeof e?e():"current"in e?e.current:e,!r)return;const i=new s((e=>{e.forEach((e=>{const{clientWidth:r,clientHeight:i}=e.target,s={width:r,height:i};null==t||t(s),n(s)}))}));return i.observe(r),()=>{i.disconnect()}}),[t,e]),i},l=e=>{let{width:t,height:s,peaks:n,color:a,bits:o,barGap:l,barWidth:u,className:c,pixelRatio:d,offset:h=0}=e;const f=r.useRef(null);return r.useEffect((()=>{const e=t/d,r=f.current.getContext("2d"),i=s/d/2,c=2**(o-1),p=u+l;r.clearRect(0,0,t,s),r.save(),r.fillStyle=a,r.scale(d,d);for(let t=0;t<e;t+=p){const e=n[2*(t+h)]/c,s=n[2*(t+h)+1]/c,a=Math.abs(e*i),o=Math.abs(s*i);r.fillRect(t,i-o,u,o+a)}r.restore()}),[l,u,o,a,s,h,n,d,t]),React.createElement("canvas",{width:t,height:s,ref:f,className:i(c)},"Your browser does not support HTML5 canvas.")};var u=r.memo(l);const c=r.forwardRef(((e,t)=>{let{className:s,progressColor:n,progressStyle:a,children:o,cursorColor:l,progressCursorVisible:u}=e;const[c,d]=r.useState(0);return r.useImperativeHandle(t,(()=>({changeOffsetPixels:e=>{void 0!==e&&d(e)}}))),React.createElement("div",{className:i(s),style:{...a,width:c,borderRight:u?"1px solid ".concat(l||n):"none"}},o)}));var d=r.memo(c);const h=r.forwardRef(((e,t)=>{const[i,s]=r.useState();return r.useImperativeHandle(t,(()=>({changeLoadedPercent:e=>{void 0!==e&&s(e)}}))),React.createElement("span",null,i)}));var f=r.memo(h);function p(e,t){void 0===t&&(t={});var r=t.insertAt;if(e&&"undefined"!=typeof document){var i=document.head||document.getElementsByTagName("head")[0],s=document.createElement("style");s.type="text/css","top"===r&&i.firstChild?i.insertBefore(s,i.firstChild):i.appendChild(s),s.styleSheet?s.styleSheet.cssText=e:s.appendChild(document.createTextNode(e))}}p(".cursor-time{align-items:center;bottom:0;box-sizing:border-box;display:flex;left:0;position:absolute;top:0;width:auto}.cursor-time,.cursor-time .time{pointer-events:none}");const m=r.forwardRef(((e,t)=>{let{config:i,cursorColor:s,cursorVisible:n,timeFormat:a}=e;const{zIndex:l=4,customShowTimeStyle:u}=i||{},{backgroundColor:c=s,color:d="#fff",padding:h="2px",fontSize:f="10px",...p}=u||{},[m,v]=r.useState(0),[g,b]=r.useState(0),[y,R]=r.useState(!1),[C,w]=r.useState((()=>(null==a?void 0:a(0))||"00:00:00")),x=r.useRef(null),{width:E}=o(x);return r.useImperativeHandle(t,(()=>({updateCursorPosition:(e,t,r,i)=>{const s=null==a?void 0:a(e);w(s),b(1),R(i<r+E),v(t)},hideCursor:()=>{b(0)},showCursor:()=>{b(1)}}))),n?React.createElement("div",{className:"cursor-time",style:{opacity:g,zIndex:l,left:m,borderLeftStyle:"solid",borderLeftWidth:1,borderLeftColor:c}},React.createElement("div",{ref:x,className:"time",style:{backgroundColor:c,color:d,padding:h,fontSize:f,marginLeft:y?-E:0,...p}},C)):null}));var v=r.memo(m);class g{constructor(e){n(this,"audioContext",void 0),n(this,"buffer",void 0),n(this,"source",void 0),n(this,"gain",void 0),n(this,"peakData",void 0),n(this,"duration",void 0),n(this,"lastOffsetPixels",void 0),n(this,"pausedAtOffsetTime",void 0),n(this,"currentOffsetTime",void 0),n(this,"startTime",void 0),n(this,"samplesPerPixel",void 0),n(this,"volume",void 0),n(this,"playing",void 0),n(this,"supportPlaybackRate",void 0),n(this,"hasEndedListener",void 0),n(this,"audioMedia",void 0),n(this,"pixelRatio",void 0),this.supportPlaybackRate=e,this.audioContext=new(window.AudioContext||window.webkitAudioContext),this.source=null,this.gain=null,this.peakData={length:0,data:[],bits:8},this.samplesPerPixel=1e3,this.duration=0,this.volume=1,this.pausedAtOffsetTime=0,this.currentOffsetTime=0,this.startTime=0,this.lastOffsetPixels=0,this.playing=!1,this.audioMedia=null,this.hasEndedListener=!1,this.pixelRatio=Math.max(1,Math.floor(window.devicePixelRatio))}initWebAudio(e,t,r){try{this.audioContext.decodeAudioData(e,(e=>{this.buffer=e,this.duration=e.duration,t(this.duration)}))}catch(e){null==r||r(e)}}initAudioElement(e,t){this.supportPlaybackRate&&(this.audioMedia&&(this.audioMedia.remove(),this.audioMedia=null),this.audioMedia=document.createElement("audio"),this.audioMedia.preload="auto",this.audioMedia.controls=!1,this.audioMedia.src=e,t.append(this.audioMedia))}getWebaudioPeaks(e,t){if(e&&this.buffer)return this.samplesPerPixel=Math.floor(this.buffer.length/e),this.peakData=a(this.buffer,this.samplesPerPixel,t),this.peakData}getCurrentOffsetTime(){return this.supportPlaybackRate?(this.currentOffsetTime=this.audioMedia.currentTime,this.currentOffsetTime):(this.currentOffsetTime=this.playing?this.audioContext.currentTime-this.startTime+this.pausedAtOffsetTime:this.pausedAtOffsetTime,this.currentOffsetTime)}getCurrentOffsetPixels(){const e=(t=this.currentOffsetTime,r=this.samplesPerPixel,i=this.buffer.sampleRate,Math.ceil(t*i/r));var t,r,i;if(e!==this.lastOffsetPixels)return this.lastOffsetPixels=e,e}getPixelsToSeconds(e){return t=e,r=this.samplesPerPixel,i=this.buffer.sampleRate,t*r/i;var t,r,i}updateCurrentOffsetPositon(e){this.supportPlaybackRate?this.audioMedia.currentTime=e:(this.currentOffsetTime=e,this.pausedAtOffsetTime=e)}pause(){var e;this.playing=!1,this.supportPlaybackRate?this.audioMedia.pause():(this.pausedAtOffsetTime+=this.audioContext.currentTime-this.startTime,null===(e=this.source)||void 0===e||e.stop(),this.source.disconnect())}ended(){var e,t,r;if(this.playing=!1,this.currentOffsetTime=0,this.lastOffsetPixels=0,this.hasEndedListener=!1,this.supportPlaybackRate)return this.audioMedia.currentTime=0,void this.audioMedia.pause();null===(e=this.source)||void 0===e||e.stop(0),null===(t=this.source)||void 0===t||t.disconnect(),null===(r=this.gain)||void 0===r||r.disconnect(),this.pausedAtOffsetTime=0,this.startTime=0,this.source=null,this.gain=null}updateAudioSource(){return new Promise((e=>{const t=()=>{var r,i,s,n;(e(!0),this.supportPlaybackRate)?null===(s=this.audioMedia)||void 0===s||null===(n=s.removeEventListener)||void 0===n||n.call(s,"ended",t):null===(r=this.source)||void 0===r||null===(i=r.removeEventListener)||void 0===i||i.call(r,"ended",t)};this.supportPlaybackRate?this.hasEndedListener||(this.audioMedia.addEventListener("ended",t),this.hasEndedListener=!0):(this.gain=this.audioContext.createGain(),this.source=this.audioContext.createBufferSource(),this.source.buffer=this.buffer,this.gain.gain.value=this.volume,this.source.connect(this.gain),this.gain.connect(this.audioContext.destination),this.source.loop=!1,this.source.addEventListener("ended",t))}))}play(){var e;this.playing=!0,this.supportPlaybackRate?this.audioMedia.play():(this.startTime=this.audioContext.currentTime,null===(e=this.source)||void 0===e||e.start(this.startTime,this.pausedAtOffsetTime,this.duration))}changeVolume(e){this.volume=e,this.supportPlaybackRate?this.audioMedia.volume=e:this.gain&&(this.gain.gain.value=e)}changePlaybackRate(e){this.supportPlaybackRate&&(this.audioMedia.playbackRate=e)}}function b(e,t,r){!function(e,t){if(t.has(e))throw new TypeError("Cannot initialize the same private elements twice on an object")}(e,t),t.set(e,r)}function y(e,t){return e.get(function(e,t,r){if("function"==typeof e?e===t:e.has(t))return arguments.length<3?t:r;throw new TypeError("Private element is not present on this object")}(e,t))}var R=new WeakMap;class C{constructor(){b(this,R,new Map)}on(e){let t=y(R,this).get(e);t||y(R,this).set(e,t=[]);for(var r=arguments.length,i=new Array(r>1?r-1:0),s=1;s<r;s++)i[s-1]=arguments[s];t.push(...i)}off(e,t){if(!t)return y(R,this).delete(e);const r=y(R,this).get(e);if(!r)return!1;const i=r.indexOf(t);return!(i<0)&&(r.splice(i,1),0===r.length&&y(R,this).delete(e),!0)}emit(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),i=1;i<t;i++)r[i-1]=arguments[i];const s=y(R,this).get(e);s&&s.forEach((e=>{try{e(...r)}catch(e){console.log(e)}}))}}p(".wave-container{box-sizing:border-box;overflow:hidden;position:relative}.wave-container .channel{position:relative;z-index:1}.wave-container .channel .progress{bottom:0;box-sizing:border-box;left:0;overflow:hidden;position:absolute;top:0;z-index:4}.wave-container .channel .wave-canvas{margin:0;padding:0}.error-container{align-items:center;display:flex;height:100%}.error-container .wave-error-text{color:#ff4d4f}");let w=function(e){return e[e.EMPTY=-1]="EMPTY",e[e.INIT=0]="INIT",e[e.LOADING=1]="LOADING",e[e.SUCCESS=2]="SUCCESS",e[e.ERROR=3]="ERROR",e}({});const x=e=>React.createElement("div",{className:"error-container"},React.createElement("span",{className:"wave-error-text"},"Decoding failed: ",e)),E=r.forwardRef(((e,s)=>{const{audioSrc:n,waveHeight:a,colors:l,progressStyle:c,onChangeLoadState:h,onCurrentTimeChange:p,onPlayEnded:m,cursorTimeConfig:b,className:y,children:R,timeFormat:E,onWaveSizeChange:P,placeholder:T,barGap:S=0,barWidth:k=1,mono:O=!0,cursorVisible:M=!0,progressCursorVisible:A=!0,supportPlaybackRate:N=!1,emptyElement:L=React.createElement("span",null,"no audio content"),renderErrorElement:I=x}=e,[z,W]=r.useState(w.INIT),D=r.useRef(null),j=r.useRef(null),q=r.useRef(null),F=r.useRef(null),G=r.useRef(null),H=r.useRef(null),U=r.useRef(null),V=r.useRef(null),{width:B}=o(j,P);r.useRef(B).current=B,D.current||(D.current=new g(N));const{progressColor:Y,waveColor:X,cursorColor:_,waveBackground:J="transparent"}=l,K=r.useCallback((e=>{U.current=e,W(w.ERROR),null==h||h(w.ERROR)}),[h]),Q=r.useCallback((async()=>{try{W(w.LOADING),null==h||h(w.LOADING);const e=await function(e,t){if(!e)throw new Error("fetch url missing");let r=0,i=0;const s=new C,n=new Headers,a=new Request(e),{headers:o,responseType:l="arraybuffer",method:u="GET",mode:c="cors",credentials:d="same-origin",cache:h="default",redirect:f="follow",referrer:p="client"}=t||{};s.controller=new AbortController,o&&Object.entries(t.headers).forEach((e=>{let[t,r]=e;n.append(t,r)}));const m={method:u,mode:c,credentials:d,cache:h,redirect:f,referrer:p,headers:n,signal:s.controller.signal};return fetch(a,m).then((e=>{let t=!0;e.body||(t=!1);const n=e.headers.get("content-length");if(r=Number.parseInt(n,10),null===n&&(t=!1),!t)return e;const a=e.body.getReader();return new Response(new ReadableStream({start(e){const t=()=>{a.read().then((n=>{let{done:a,value:o}=n;if(a)return s.emit("progress",{loaded:i,total:r,lengthComputable:!1}),void e.close();i+=o.byteLength,s.emit("progress",{loaded:i,total:r,lengthComputable:!(0===r)}),e.enqueue(o),t()})).catch((t=>{e.error(t)}))};t()}}),m)})).then((e=>{let t;if(e.ok)switch(l){case"arraybuffer":return e.arrayBuffer();case"json":return e.json();case"blob":return e.blob();case"text":return e.text();default:t="Unknown responseType: ".concat(l)}throw t||(t="HTTP error status: ".concat(e.status)),new Error(t)})).then((e=>{s.emit("success",e)})).catch((e=>{s.emit("error",e)})),s.fetchRequest=a,s}(n);e.on("success",(e=>{if(0===e.byteLength)return W(w.EMPTY),void(null==h||h(w.EMPTY));D.current.initWebAudio(e,(e=>{U.current=null,W(w.SUCCESS),null==h||h(w.SUCCESS,e)}),K)})),e.on("progress",(e=>{void 0!==e&&H.current.changeLoadedPercent(function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2;return[Number.isNaN(e),void 0===e,null===e].includes(!0)?"":[0,"0"].includes(e)?"0":"".concat(Number.parseFloat(String((100*Number(e)).toFixed(t))),"%")}(e.loaded/e.total))})),e.on("error",K)}catch(e){K(e)}}),[n,K,h]),Z=r.useCallback((()=>{var e;const t=D.current.getCurrentOffsetTime(),r=D.current.getCurrentOffsetPixels();null===(e=F.current)||void 0===e||e.changeOffsetPixels(r),null==p||p(t)}),[p]),$=r.useCallback((()=>{D.current.playing?(Z(),q.current=window.requestAnimationFrame($)):window.cancelAnimationFrame(q.current)}),[Z]),ee=r.useCallback((()=>{D.current.pause(),window.cancelAnimationFrame(q.current)}),[]),te=r.useCallback((()=>{V.current=D.current.updateAudioSource(),D.current.play(),$(),V.current.then((e=>{e&&D.current.playing&&(D.current.ended(),F.current.changeOffsetPixels(0),null==m||m(),null==p||p(0),window.cancelAnimationFrame(q.current))}))}),[p,m,$]),re=r.useCallback(((e,t)=>{const{playing:r}=D.current;if(!1===r)return D.current.updateCurrentOffsetPositon(e),Z(),void(!0===t&&te());if(!0===r){if(N)return D.current.updateCurrentOffsetPositon(e),void(!1===t&&(ee(),Z()));if(!0===t||void 0===t)return ee(),D.current.updateCurrentOffsetPositon(e),void V.current.then((()=>{te()}));ee(),D.current.updateCurrentOffsetPositon(e),Z()}}),[Z,ee,te,N]),ie=r.useCallback((e=>{D.current.changeVolume(e)}),[]),se=r.useCallback((e=>{D.current.changePlaybackRate(e)}),[]),ne=r.useCallback((()=>{D.current.playing&&ee(),D.current=null,W(w.INIT)}),[ee]),ae=e=>{const t=j.current.getBoundingClientRect(),r=e.clientX-t.left;return{x:r,time:Math.max(0,D.current.getPixelsToSeconds(r)),clientX:e.clientX,right:t.right}};r.useImperativeHandle(s,(()=>({seekTo:re,destroy:ne,play:te,pause:ee,volume:ie,playbackRate:se}))),r.useEffect((()=>{Q()}),[Q]),r.useEffect((()=>{D.current.initAudioElement(n,j.current)}),[n]);const oe=r.useMemo((()=>{if(B&&z===w.SUCCESS){const e=D.current.getWebaudioPeaks(B,O);return e.data.map(((r,i)=>{var s;const n=null!==(s=null==e?void 0:e.length)&&void 0!==s?s:B,o={pixelRatio:D.current.pixelRatio,color:X,peaks:r,bits:e.bits,width:n,height:a,className:"wave-canvas",barGap:S,barWidth:k};return React.createElement("div",{key:i,className:"channel",style:{height:a,width:n,backgroundColor:J}},React.createElement(d,{ref:F,progressStyle:c,progressCursorVisible:A,progressColor:Y,cursorColor:_,className:"progress"},React.createElement(u,t({},o,{color:Y}))),React.createElement(v,{ref:G,timeFormat:E,config:b,cursorColor:_,cursorVisible:M}),React.createElement(u,o))}))}}),[S,k,_,b,M,z,O,Y,A,c,J,X,a,B,E]);return React.createElement("div",{className:i("wave-container",{[y]:!!y}),style:{height:a},ref:j,onMouseMove:e=>{var t;if(!M||z!==w.SUCCESS)return;const{time:r,x:i,clientX:s,right:n}=ae(e);null===(t=G.current)||void 0===t||t.updateCursorPosition(r,i,s,n)},onMouseLeave:()=>{var e;M&&z===w.SUCCESS&&(null===(e=G.current)||void 0===e||e.hideCursor())},onMouseEnter:()=>{var e;M&&z===w.SUCCESS&&(null===(e=G.current)||void 0===e||e.showCursor())},onClick:e=>{const{time:t}=ae(e);re(t)}},z===w.EMPTY?L:z===w.LOADING?React.createElement(T,null,React.createElement(f,{ref:H})):z===w.ERROR?null==I?void 0:I(null===(le=U.current)||void 0===le?void 0:le.toString()):React.createElement(React.Fragment,null,R,oe));var le}));var P=r.memo(E);e.LoadStateEnum=w,e.ReactAudioWave=P}));