UNPKG

ts-audio

Version:

`ts-audio` is an agnostic and easy-to-use library to work with the `AudioContext` API and create Playlists.

3 lines (2 loc) 5.76 kB
const t=(s,e=3,i)=>{fetch(s).then(i).catch(()=>{e&&t(s,e-1)})},s={isDecoded:!1,isPlaying:!1,hasStarted:!1,source:null,gainNode:null};class e{constructor(){this.events=void 0,this.events={}}listener(t,s){this.events[t]=s}emit(t,s){this.events[t]&&this.events[t](s)}}class i{constructor(t,s){this.emitter=void 0,this.audioCtx=void 0,this.emitter=t,this.audioCtx=s}ready(t){this.emitter.listener("decoded",t)}start(t){this.emitter.listener("start",t)}end(t){this.emitter.listener("end",t)}state(t){this.audioCtx&&(this.audioCtx.onstatechange=()=>t({data:this.audioCtx?.state}))}}const o=(t,s,e)=>"suspended"===t.state?t.resume().then(()=>s.start(0,e)):s.start(0,e);class a{constructor({file:o,volume:a=1,time:r=0,autoPlay:d=!1,loop:h=!1,preload:u=!1}){this._file=void 0,this._initialVolume=void 0,this._initialTime=void 0,this._autoPlay=void 0,this._initialLoop=void 0,this._audioCtx=void 0,this._states=void 0,this._emitter=void 0,this._eventHandler=void 0,this._file=o,this._initialVolume=a,this._initialTime=r,this._autoPlay=d,this._initialLoop=h,this._audioCtx=(()=>{const t=window.AudioContext||window.webkitAudioContext;return t||(t=>{throw new Error("`ts-audio`: Your browser doesn't support AudioContext - https://bit.ly/2YWmpnX")})(),new t})(),this._states={...s},this._emitter=new e,this._eventHandler=new i(this._emitter,this._audioCtx),u&&t(o)}curryGetBuffer(t){var s;this._states.isDecoded=!1,(s=this._file,fetch(s).then(t=>{if(!t.ok)throw new Error(`HTTP error, status = ${t.status}`);return t.arrayBuffer()})).then(s=>{(({audioCtx:t,source:s,arrayBuffer:e,autoPlay:i,loop:o,states:a,emitter:r})=>{t.decodeAudioData(e,t=>{s.buffer=t,s.loop=o,a.isDecoded=!0,r.emit("decoded",{data:t}),i&&(s.start(0),a.isPlaying=!0)},console.error)})({audioCtx:this._audioCtx,source:t,arrayBuffer:s,autoPlay:this._autoPlay,loop:this._initialLoop,states:this._states,emitter:this._emitter})}).catch(console.error)}play(){if(this._states.hasStarted)return this._audioCtx.resume(),void(this._states.isPlaying=!0);(({audioCtx:t,volume:s,emitter:e,states:i})=>{const o=i.source=t.createBufferSource(),a=i.gainNode=t.createGain();a.gain.value=s,a.connect(t.destination),o.connect(a),o.onended=()=>{i.hasStarted=!1,i.isPlaying=!1,e.emit("end",{data:null})}})({audioCtx:this._audioCtx,volume:this._initialVolume,emitter:this._emitter,states:this._states});const{source:t}=this._states;t&&(this.curryGetBuffer(t),this._states.isDecoded?o(this._audioCtx,t,this._initialTime):this._emitter.listener("decoded",()=>o(this._audioCtx,t,this._initialTime)),this._states.hasStarted=!0,this._states.isPlaying=!0,this._emitter.emit("start",{data:null}))}pause(){this._audioCtx.suspend(),this._states.isPlaying=!1}toggle(){this._states.isPlaying?this.pause():this.play()}stop(){this._states.hasStarted&&(this._states.source?.stop(0),this._states.isPlaying=!1)}on(t,s){this._eventHandler[t]?.(s)}get volume(){return this._states.gainNode?.gain.value??0}set volume(t){this._states.gainNode&&(this._states.gainNode.gain.value=t)}get loop(){return this._states.source?.loop??!1}set loop(t){this._states.source&&(this._states.source.loop=t)}get state(){return this._audioCtx.state}get audioCtx(){return this._audioCtx}get duration(){return this._states.source?.buffer?.duration??0}get currentTime(){return this._states.source?.context.currentTime??0}}var r=t=>new a(t);const d={volume:1,loop:!1,audio:null,isStopped:!1,isPlaying:!1,audioIndex:0};class h{constructor({files:t,volume:s=1,loop:i=!1,shuffle:o=!1,preload:a=!1,preloadLimit:h=3}){this.emmiter=void 0,this.states=void 0,this.copiedFiles=void 0,this.shouldLoop=void 0,this.curryPlayAudio=void 0,this.emmiter=new e,this.states={...d,volume:s,loop:i};const u=!Array.isArray(t);this.shouldLoop=i||u;const n=u?(t=>Object.entries(t).flatMap(([t,s])=>Array(Math.floor(s)).fill(t)))(t):t;this.copiedFiles=o||u?(t=>{const s=t.slice();let e=t.length-1;for(;e>=0;){const t=Math.floor(Math.random()*e+1),i=s[e];s[e]=s[t],s[t]=i,e--}return s})(n):n.slice(),this.curryPlayAudio=((t,s)=>{const e=(i,o)=>{const a=r({file:i[t.audioIndex],volume:t.volume});t.audio=a,a.on("start",t=>{s.emit("start",t)}),a.on("end",()=>{t.isStopped||(i.length===t.audioIndex+1?(t.audio=null,t.audioIndex=0,t.loop?e(i):(s.emit("end",{data:null}),t.isPlaying=!1)):(t.audioIndex++,e(i)))}),a.play()};return e})(this.states,this.emmiter),a&&((t,s,e=fetch,i)=>{const o=t.slice(s).reverse();let a=!1;const r=()=>{o.length?d(o.pop()):a||(i?.(),a=!0)},d=t=>{e(t).then(r).catch(r)};for(let e=0;e<s;e++)d(t[e])})(this.copiedFiles,h)}play(){const{audio:t}=this.states;if(this.states.isPlaying=!0,!t||this.states.isStopped)return this.curryPlayAudio(this.copiedFiles,this.shouldLoop),void(this.states.isStopped=!1);t.play()}toggle(){this.states.isPlaying?this.pause():this.play()}pause(){this.states.audio?.pause(),this.states.isPlaying=!1}stop(){this.states.isPlaying=!1,this.states.isStopped=!0,this.states.audio?.stop()}next(){this.states.audioIndex=this.states.audioIndex===this.copiedFiles.length-1?0:this.states.audioIndex+1,this.states.audio?.pause();const t=r({file:this.copiedFiles[this.states.audioIndex],volume:this.states.volume});this.states.audio=t,t.play()}prev(){this.states.audioIndex=0===this.states.audioIndex?this.copiedFiles.length-1:this.states.audioIndex-1,this.states.audio?.pause();const t=r({file:this.copiedFiles[this.states.audioIndex],volume:this.states.volume});this.states.audio=t,t.play()}on(t,s){this.emmiter.listener(t,s)}get volume(){return this.states.volume}set volume(t){this.states.volume=t,this.states.audio&&(this.states.audio.volume=t)}get loop(){return this.states.loop}set loop(t){this.states.loop=t}get audioCtx(){return this.states.audio?.audioCtx}}exports.Audio=r,exports.AudioPlaylist=t=>new h(t); //# sourceMappingURL=index.js.map