/**
* This class is responsible for playing a singular sound.
*/
export class Sfx {
/**
* @private
* @type {AudioBuffer}
*/
_soundBuffer
/**
* @private
* @type {AudioBufferSourceNode}
*/
_source
//Todo - Check to see if this one works
/**
* @private
* @type {Function}
*/
_onended = ()=>{}
/**
* @private
* @type {AudioNode}
*/
_destination
/**
* @private
* @type {number}
*/
_playingOffset = 0
/**
* Time on the sound to begin playing
*
* @type {number}
*/
offset = 0
/**
* Whether to start from the beginning after sound has finished playing.
*
* @type {boolean}
*/
loop = false
/**
* @private
* @type {number}
*/
delay = 0
/**
* how long to play the sound.
*
* @type {number}
*/
duration = 0
/**
* @param {AudioHandler} handler
* @param {AudioBuffer} buffer
*/
constructor(handler, buffer) {
this.handler = handler
this.ctx = handler.ctx
this._source = handler.ctx.createBufferSource()
this._soundBuffer = buffer
this._destination = handler.masterGainNode
this._startTime = Date.now()
this.finished = false
this.id = -1
this.duration = buffer.duration
}
/**
* Set callback when the sound finishes playing.
*
* @param {Function} x
*/
set onended(x) {
this._onended = x
}
/**
* Plays an sfx from the beginning.
*/
play() {
this._playingOffset = this.offset
this.resume()
}
/**
* Continues playing an sfx from where it was paused.
*/
resume() {
this._source = this.ctx.createBufferSource()
this._source.buffer = this._soundBuffer
this._startTime = Date.now()
this._source.connect(this._destination)
this._source.start(this.delay, this._playingOffset, this.duration)
this._source.loop = this.loop
}
/**
* Halts playing of an sfx.
*/
pause() {
this._source.stop()
let time = (Date.now() - this._startTime) / 1000 + this._playingOffset
this._playingOffset = this.duration <= time ? this.offset : time
}
/**
* Disconnects this sfx from its current destination.
*/
disconnect() {
this._source.disconnect()
}
/**
* Sets the given audionode to be the output destination of an sfx
*
* @param {AudioNode} node
*/
connect(node) {
if (node)
this._destination = node
if (!this._source) return;
this._source.disconnect()
this._source.connect(this._destination)
}
}