import SharedAudioContext from './shared-audio-context.js'; class AudioBufferPlayer { constructor (samples, sampleRate) { this.audioContext = new SharedAudioContext(); this.buffer = this.audioContext.createBuffer(1, samples.length, sampleRate); this.buffer.getChannelData(0).set(samples); this.source = null; this.startTime = null; this.updateCallback = null; this.trimStart = null; this.trimEnd = null; } play (trimStart, trimEnd, onUpdate, onEnded) { this.updateCallback = onUpdate; this.trimStart = trimStart; this.trimEnd = trimEnd; this.startTime = Date.now(); const trimStartTime = this.buffer.duration * trimStart; const trimmedDuration = (this.buffer.duration * trimEnd) - trimStartTime; this.source = this.audioContext.createBufferSource(); this.source.onended = onEnded; this.source.buffer = this.buffer; this.source.connect(this.audioContext.destination); this.source.start(0, trimStartTime, trimmedDuration); this.update(); } update () { const timeSinceStart = (Date.now() - this.startTime) / 1000; const percentage = timeSinceStart / this.buffer.duration; if (percentage + this.trimStart < this.trimEnd && this.source.onended) { requestAnimationFrame(this.update.bind(this)); this.updateCallback(percentage + this.trimStart); } else { this.updateCallback = null; } } stop () { if (this.source) { this.source.onended = null; // Do not call onEnded callback if manually stopped try { this.source.stop(); } catch (e) { // This is probably Safari, which dies when you call stop more than once // which the spec says is allowed: https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode console.log('Caught error while stopping buffer source node.'); // eslint-disable-line no-console } } } } export default AudioBufferPlayer;