UNPKG

wavesurfer.js

Version:
209 lines (208 loc) 7.19 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import EventEmitter from './event-emitter.js'; /** * A Web Audio buffer player emulating the behavior of an HTML5 Audio element. */ class WebAudioPlayer extends EventEmitter { constructor(audioContext = new AudioContext()) { super(); this.bufferNode = null; this.playStartTime = 0; this.playedDuration = 0; this._muted = false; this._playbackRate = 1; this._duration = undefined; this.buffer = null; this.currentSrc = ''; this.paused = true; this.crossOrigin = null; this.seeking = false; this.autoplay = false; /** Subscribe to an event. Returns an unsubscribe function. */ this.addEventListener = this.on; /** Unsubscribe from an event */ this.removeEventListener = this.un; this.audioContext = audioContext; this.gainNode = this.audioContext.createGain(); this.gainNode.connect(this.audioContext.destination); } load() { return __awaiter(this, void 0, void 0, function* () { return; }); } get src() { return this.currentSrc; } set src(value) { this.currentSrc = value; this._duration = undefined; if (!value) { this.buffer = null; this.emit('emptied'); return; } fetch(value) .then((response) => { if (response.status >= 400) { throw new Error(`Failed to fetch ${value}: ${response.status} (${response.statusText})`); } return response.arrayBuffer(); }) .then((arrayBuffer) => { if (this.currentSrc !== value) return null; return this.audioContext.decodeAudioData(arrayBuffer); }) .then((audioBuffer) => { if (this.currentSrc !== value) return; this.buffer = audioBuffer; this.emit('loadedmetadata'); this.emit('canplay'); if (this.autoplay) this.play(); }); } _play() { var _a; if (!this.paused) return; this.paused = false; (_a = this.bufferNode) === null || _a === void 0 ? void 0 : _a.disconnect(); this.bufferNode = this.audioContext.createBufferSource(); if (this.buffer) { this.bufferNode.buffer = this.buffer; } this.bufferNode.playbackRate.value = this._playbackRate; this.bufferNode.connect(this.gainNode); let currentPos = this.playedDuration * this._playbackRate; if (currentPos >= this.duration || currentPos < 0) { currentPos = 0; this.playedDuration = 0; } this.bufferNode.start(this.audioContext.currentTime, currentPos); this.playStartTime = this.audioContext.currentTime; this.bufferNode.onended = () => { if (this.currentTime >= this.duration) { this.pause(); this.emit('ended'); } }; } _pause() { var _a; this.paused = true; (_a = this.bufferNode) === null || _a === void 0 ? void 0 : _a.stop(); this.playedDuration += this.audioContext.currentTime - this.playStartTime; } play() { return __awaiter(this, void 0, void 0, function* () { if (!this.paused) return; this._play(); this.emit('play'); }); } pause() { if (this.paused) return; this._pause(); this.emit('pause'); } stopAt(timeSeconds) { const delay = timeSeconds - this.currentTime; const currentBufferNode = this.bufferNode; currentBufferNode === null || currentBufferNode === void 0 ? void 0 : currentBufferNode.stop(this.audioContext.currentTime + delay); currentBufferNode === null || currentBufferNode === void 0 ? void 0 : currentBufferNode.addEventListener('ended', () => { if (currentBufferNode === this.bufferNode) { this.bufferNode = null; this.pause(); } }, { once: true }); } setSinkId(deviceId) { return __awaiter(this, void 0, void 0, function* () { const ac = this.audioContext; return ac.setSinkId(deviceId); }); } get playbackRate() { return this._playbackRate; } set playbackRate(value) { this._playbackRate = value; if (this.bufferNode) { this.bufferNode.playbackRate.value = value; } } get currentTime() { const time = this.paused ? this.playedDuration : this.playedDuration + (this.audioContext.currentTime - this.playStartTime); return time * this._playbackRate; } set currentTime(value) { const wasPlaying = !this.paused; wasPlaying && this._pause(); this.playedDuration = value / this._playbackRate; wasPlaying && this._play(); this.emit('seeking'); this.emit('timeupdate'); } get duration() { var _a, _b; return (_a = this._duration) !== null && _a !== void 0 ? _a : (((_b = this.buffer) === null || _b === void 0 ? void 0 : _b.duration) || 0); } set duration(value) { this._duration = value; } get volume() { return this.gainNode.gain.value; } set volume(value) { this.gainNode.gain.value = value; this.emit('volumechange'); } get muted() { return this._muted; } set muted(value) { if (this._muted === value) return; this._muted = value; if (this._muted) { this.gainNode.disconnect(); } else { this.gainNode.connect(this.audioContext.destination); } } canPlayType(mimeType) { return /^(audio|video)\//.test(mimeType); } /** Get the GainNode used to play the audio. Can be used to attach filters. */ getGainNode() { return this.gainNode; } /** Get decoded audio */ getChannelData() { const channels = []; if (!this.buffer) return channels; const numChannels = this.buffer.numberOfChannels; for (let i = 0; i < numChannels; i++) { channels.push(this.buffer.getChannelData(i)); } return channels; } } export default WebAudioPlayer;