UNPKG

interactive-player

Version:

A front-end interactive music audio player using AudioWorklet for javascript and typescript

93 lines 2.77 kB
// src/interactive-player.ts var InteractivePlayer = class { constructor() { this.ctx = new AudioContext(); // 遅延初期化 this.graph = {}; const moduleUrl = ( // ESM (ブラウザ / Node ESM) typeof import.meta !== "undefined" && import.meta.url || `file://${__dirname}/` ); const workletUrl = new URL( "interactive-player-processor.js", moduleUrl ); this.workletReady = this.ctx.audioWorklet.addModule(workletUrl.toString()).then(() => { this.node = new AudioWorkletNode( this.ctx, "interactive-player-processor" ); this.node.connect(this.ctx.destination); }); } /** 複数トラックをまとめてロード */ async loadAll(tracks) { this.graph = tracks.reduce( (g, t, i) => (g[i] = t.next ?? null, g), {} ); const buffers = await Promise.all( tracks.map(async (t) => { const arr = typeof t.src === "string" ? await (await fetch(t.src)).arrayBuffer() : t.src; return this.ctx.decodeAudioData(arr); }) ); await this.workletReady; const transferables = []; const payload = buffers.map((buf) => { const chans = []; for (let ch = 0; ch < buf.numberOfChannels; ch++) { const copy = new Float32Array(buf.getChannelData(ch)); chans.push(copy.buffer); transferables.push(copy.buffer); } return chans; }); this.node.port.postMessage( { type: "loadMulti", tracks: payload, transitions: this.graph }, transferables ); } /** 再生 */ async play(startIdx = 0) { if (this.ctx.state !== "running") await this.ctx.resume(); await this.workletReady; this.node.port.postMessage({ type: "play", start: startIdx }); } /** 停止(頭出し) */ async stop() { await this.workletReady; this.node.port.postMessage({ type: "stop" }); } /** ポーズ/レジューム */ async pause(isPause) { await this.workletReady; this.node.port.postMessage({ type: isPause ? "pause" : "resume" }); } /** 次トラックをキューイング */ async next(idx, currentIs = null) { await this.workletReady; this.node.port.postMessage({ type: "next", next: idx, currentIs }); } async setFadeInSec(sec) { await this.workletReady; this.node.port.postMessage({ type: "setFadeIn", fadeInSamples: this.secToSamples(sec) }); } async setFadeOutSec(sec) { await this.workletReady; this.node.port.postMessage({ type: "setFadeOut", fadeOutSamples: this.secToSamples(sec) }); } secToSamples(sec) { return Math.floor(sec * this.ctx.sampleRate); } }; export { InteractivePlayer as default }; //# sourceMappingURL=interactive-player.js.map