UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 11 kB
import{EventHandler as t}from"../../core/event-handler.js";import{math as s}from"../../core/math/math.js";import{hasAudioContext as e}from"../audio/capabilities.js";function i(t,s){return t%s||0}class n extends t{constructor(t,i,n){super(),this.source=null,this._manager=t,this._volume=void 0!==n.volume?s.clamp(Number(n.volume)||0,0,1):1,this._pitch=void 0!==n.pitch?Math.max(.01,Number(n.pitch)||0):1,this._loop=!(void 0===n.loop||!n.loop),this._sound=i,this._state=2,this._suspended=!1,this._suspendEndEvent=0,this._suspendInstanceEvents=!1,this._playWhenLoaded=!0,this._startTime=Math.max(0,Number(n.startTime)||0),this._duration=Math.max(0,Number(n.duration)||0),this._startOffset=null,this._onPlayCallback=n.onPlay,this._onPauseCallback=n.onPause,this._onResumeCallback=n.onResume,this._onStopCallback=n.onStop,this._onEndCallback=n.onEnd,e()?(this._startedAt=0,this._currentTime=0,this._currentOffset=0,this._inputNode=null,this._connectorNode=null,this._firstNode=null,this._lastNode=null,this._waitingContextSuspension=!1,this._initializeNodes(),this._endedHandler=this._onEnded.bind(this)):(this._isReady=!1,this._loadedMetadataHandler=this._onLoadedMetadata.bind(this),this._timeUpdateHandler=this._onTimeUpdate.bind(this),this._endedHandler=this._onEnded.bind(this),this._createSource())}set currentTime(t){if(!(t<0))if(0===this._state){const s=this._suspendInstanceEvents;this._suspendInstanceEvents=!0,this.stop(),this._startOffset=t,this.play(),this._suspendInstanceEvents=s}else this._startOffset=t,this._currentTime=t}get currentTime(){return null!==this._startOffset?this._startOffset:1===this._state?this._currentTime:2!==this._state&&this.source?(this._updateCurrentTime(),this._currentTime):0}set duration(t){this._duration=Math.max(0,Number(t)||0);const s=0===this._state;this.stop(),s&&this.play()}get duration(){return this._sound?this._duration?i(this._duration,this._sound.duration):this._sound.duration:0}get isPaused(){return 1===this._state}get isPlaying(){return 0===this._state}get isStopped(){return 2===this._state}get isSuspended(){return this._suspended}set loop(t){this._loop=!!t,this.source&&(this.source.loop=this._loop)}get loop(){return this._loop}set pitch(t){this._currentOffset=this.currentTime,this._startedAt=this._manager.context.currentTime,this._pitch=Math.max(Number(t)||0,.01),this.source&&(this.source.playbackRate.value=this._pitch)}get pitch(){return this._pitch}set sound(t){this._sound=t,2!==this._state?this.stop():this._createSource()}get sound(){return this._sound}set startTime(t){this._startTime=Math.max(0,Number(t)||0);const s=0===this._state;this.stop(),s&&this.play()}get startTime(){return this._startTime}set volume(t){t=s.clamp(t,0,1),this._volume=t,this.gain&&(this.gain.gain.value=t*this._manager.volume)}get volume(){return this._volume}_onPlay(){this.fire("play"),this._onPlayCallback&&this._onPlayCallback(this)}_onPause(){this.fire("pause"),this._onPauseCallback&&this._onPauseCallback(this)}_onResume(){this.fire("resume"),this._onResumeCallback&&this._onResumeCallback(this)}_onStop(){this.fire("stop"),this._onStopCallback&&this._onStopCallback(this)}_onEnded(){this._suspendEndEvent>0?this._suspendEndEvent--:(this.fire("end"),this._onEndCallback&&this._onEndCallback(this),this.stop())}_onManagerVolumeChange(){this.volume=this._volume}_onManagerSuspend(){0!==this._state||this._suspended||(this._suspended=!0,this.pause())}_onManagerResume(){this._suspended&&(this._suspended=!1,this.resume())}_initializeNodes(){this.gain=this._manager.context.createGain(),this._inputNode=this.gain,this._connectorNode=this.gain,this._connectorNode.connect(this._manager.context.destination)}play(){return 2!==this._state&&this.stop(),this._state=0,this._playWhenLoaded=!1,!this._waitingContextSuspension&&(this._manager.suspended?(this._manager.once("resume",this._playAudioImmediate,this),this._waitingContextSuspension=!0,!1):(this._playAudioImmediate(),!0))}_playAudioImmediate(){if(this._waitingContextSuspension=!1,0!==this._state)return;this.source||this._createSource();let t=i(this._startOffset,this.duration);t=i(this._startTime+t,this._sound.duration),this._startOffset=null,this._duration?this.source.start(0,t,this._duration):this.source.start(0,t),this._startedAt=this._manager.context.currentTime,this._currentTime=0,this._currentOffset=t,this.volume=this._volume,this.loop=this._loop,this.pitch=this._pitch,this._manager.on("volumechange",this._onManagerVolumeChange,this),this._manager.on("suspend",this._onManagerSuspend,this),this._manager.on("resume",this._onManagerResume,this),this._manager.on("destroy",this._onManagerDestroy,this),this._suspendInstanceEvents||this._onPlay()}pause(){return this._playWhenLoaded=!1,0===this._state&&(this._state=1,this._waitingContextSuspension||(this._updateCurrentTime(),this._suspendEndEvent++,this.source.stop(0),this.source=null,this._startOffset=null,this._suspendInstanceEvents||this._onPause()),!0)}resume(){if(1!==this._state)return!1;let t=this.currentTime;return this._state=0,this._waitingContextSuspension||(this.source||this._createSource(),null!==this._startOffset&&(t=i(this._startOffset,this.duration),t=i(this._startTime+t,this._sound.duration),this._startOffset=null),this._duration?this.source.start(0,t,this._duration):this.source.start(0,t),this._startedAt=this._manager.context.currentTime,this._currentOffset=t,this.volume=this._volume,this.loop=this._loop,this.pitch=this._pitch,this._playWhenLoaded=!1,this._suspendInstanceEvents||this._onResume()),!0}stop(){if(this._playWhenLoaded=!1,2===this._state)return!1;const t=0===this._state;return this._state=2,this._waitingContextSuspension||(this._manager.off("volumechange",this._onManagerVolumeChange,this),this._manager.off("suspend",this._onManagerSuspend,this),this._manager.off("resume",this._onManagerResume,this),this._manager.off("destroy",this._onManagerDestroy,this),this._startedAt=0,this._currentTime=0,this._currentOffset=0,this._startOffset=null,this._suspendEndEvent++,t&&this.source&&this.source.stop(0),this.source=null,this._suspendInstanceEvents||this._onStop()),!0}setExternalNodes(t,s){if(!t)return void console.error("The firstNode must be a valid Audio Node");s||(s=t);const e=this._manager.context.destination;this._firstNode!==t&&(this._firstNode?this._connectorNode.disconnect(this._firstNode):this._connectorNode.disconnect(e),this._firstNode=t,this._connectorNode.connect(t)),this._lastNode!==s&&(this._lastNode&&this._lastNode.disconnect(e),this._lastNode=s,this._lastNode.connect(e))}clearExternalNodes(){const t=this._manager.context.destination;this._firstNode&&(this._connectorNode.disconnect(this._firstNode),this._firstNode=null),this._lastNode&&(this._lastNode.disconnect(t),this._lastNode=null),this._connectorNode.connect(t)}getExternalNodes(){return[this._firstNode,this._lastNode]}_createSource(){if(!this._sound)return null;const t=this._manager.context;return this._sound.buffer&&(this.source=t.createBufferSource(),this.source.buffer=this._sound.buffer,this.source.connect(this._inputNode),this.source.onended=this._endedHandler,this.source.loopStart=i(this._startTime,this.source.buffer.duration),this._duration&&(this.source.loopEnd=Math.max(this.source.loopStart,i(this._startTime+this._duration,this.source.buffer.duration)))),this.source}_updateCurrentTime(){this._currentTime=i((this._manager.context.currentTime-this._startedAt)*this._pitch+this._currentOffset,this.duration)}_onManagerDestroy(){this.source&&0===this._state&&(this.source.stop(0),this.source=null)}}n.EVENT_PLAY="play",n.EVENT_PAUSE="pause",n.EVENT_RESUME="resume",n.EVENT_STOP="stop",n.EVENT_END="end",e()||(Object.assign(n.prototype,{play:function(){return 2!==this._state&&this.stop(),!(!this.source&&!this._createSource())&&(this.volume=this._volume,this.pitch=this._pitch,this.loop=this._loop,this.source.play(),this._state=0,this._playWhenLoaded=!1,this._manager.on("volumechange",this._onManagerVolumeChange,this),this._manager.on("suspend",this._onManagerSuspend,this),this._manager.on("resume",this._onManagerResume,this),this._manager.on("destroy",this._onManagerDestroy,this),this._manager.suspended&&this._onManagerSuspend(),this._suspendInstanceEvents||this._onPlay(),!0)},pause:function(){return!(!this.source||0!==this._state)&&(this._suspendEndEvent++,this.source.pause(),this._playWhenLoaded=!1,this._state=1,this._startOffset=null,this._suspendInstanceEvents||this._onPause(),!0)},resume:function(){return!(!this.source||1!==this._state)&&(this._state=0,this._playWhenLoaded=!1,this.source.paused&&(this.source.play(),this._suspendInstanceEvents||this._onResume()),!0)},stop:function(){return!(!this.source||2===this._state)&&(this._manager.off("volumechange",this._onManagerVolumeChange,this),this._manager.off("suspend",this._onManagerSuspend,this),this._manager.off("resume",this._onManagerResume,this),this._manager.off("destroy",this._onManagerDestroy,this),this._suspendEndEvent++,this.source.pause(),this._playWhenLoaded=!1,this._state=2,this._startOffset=null,this._suspendInstanceEvents||this._onStop(),!0)},setExternalNodes:function(){},clearExternalNodes:function(){},getExternalNodes:function(){return[null,null]},_onLoadedMetadata:function(){this.source.removeEventListener("loadedmetadata",this._loadedMetadataHandler),this._isReady=!0;let t=i(this._startOffset,this.duration);t=i(this._startTime+t,this._sound.duration),this._startOffset=null,this.source.currentTime=t},_createSource:function(){return this._sound&&this._sound.audio&&(this._isReady=!1,this.source=this._sound.audio.cloneNode(!0),this.source.addEventListener("loadedmetadata",this._loadedMetadataHandler),this.source.addEventListener("timeupdate",this._timeUpdateHandler),this.source.onended=this._endedHandler),this.source},_onTimeUpdate:function(){this._duration&&this.source.currentTime>i(this._startTime+this._duration,this.source.duration)&&(this.loop?this.source.currentTime=i(this._startTime,this.source.duration):(this.source.removeEventListener("timeupdate",this._timeUpdateHandler),this.source.pause(),this._onEnded()))},_onManagerDestroy:function(){this.source&&this.source.pause()}}),Object.defineProperty(n.prototype,"volume",{get:function(){return this._volume},set:function(t){t=s.clamp(t,0,1),this._volume=t,this.source&&(this.source.volume=t*this._manager.volume)}}),Object.defineProperty(n.prototype,"pitch",{get:function(){return this._pitch},set:function(t){this._pitch=Math.max(Number(t)||0,.01),this.source&&(this.source.playbackRate=this._pitch)}}),Object.defineProperty(n.prototype,"sound",{get:function(){return this._sound},set:function(t){this.stop(),this._sound=t}}),Object.defineProperty(n.prototype,"currentTime",{get:function(){return null!==this._startOffset?this._startOffset:2!==this._state&&this.source?this.source.currentTime-this._startTime:0},set:function(t){t<0||(this._startOffset=t,this.source&&this._isReady&&(this.source.currentTime=i(this._startTime+i(t,this.duration),this._sound.duration),this._startOffset=null))}}));export{n as SoundInstance};