From c4df71c25c64dbac50d1311a59d951b9118292c0 Mon Sep 17 00:00:00 2001 From: terry feng Date: Sat, 6 Jul 2024 00:42:47 -0700 Subject: [PATCH] update record impl to record exact number of samples --- .../processors/recorder/recorder-main.js | 40 +++++++++---------- .../processors/recorder/recorder-processor.js | 24 ++++++++++- src/tests/playwright/pages/realtime-sine.html | 2 +- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/tests/playwright/pages/processors/recorder/recorder-main.js b/src/tests/playwright/pages/processors/recorder/recorder-main.js index 6813b24a3..74eeefc49 100644 --- a/src/tests/playwright/pages/processors/recorder/recorder-main.js +++ b/src/tests/playwright/pages/processors/recorder/recorder-main.js @@ -1,36 +1,36 @@ -import concat from '../../util/concat.js'; - export default async (ctx, length) => { console.assert(ctx instanceof AudioContext); console.assert(typeof length === 'number' && length > 0); - const mutex = new Promise((resolve) => - setTimeout(resolve, 1000 * length)); + const maxSamps = length * ctx.sampleRate; await ctx.audioWorklet.addModule('./processors/recorder/recorder-processor.js'); - const recorder = new AudioWorkletNode(ctx, 'recorder'); + const recorder = new AudioWorkletNode(ctx, 'recorder', { + processorOptions: { + maxSamps + } + }); - const arrays = []; + let bufferResolve; recorder.port.onmessage = (e) => { - !(e.data.channel in arrays) && (arrays[e.data.channel] = []); - arrays[e.data.channel].push(e.data.data); + if (e.data.message === 'RECORD_DONE') { + // Resolve bufferData to buffer + const bufferData = e.data.buffer; + const audioBuffer = new AudioBuffer({ + length: maxSamps, + sampleRate: ctx.sampleRate, + numberOfChannels: bufferData.length + }) + bufferData.forEach((array, i) => audioBuffer.copyToChannel(array, i)); + + bufferResolve(audioBuffer) + } }; // eslint-disable-next-line no-async-promise-executor const buffer = new Promise(async (resolve) => { - await mutex; - const res = []; - arrays.forEach((array, i) => res[i] = concat(array)); - - const buf = new AudioBuffer({ - length: res[0].length, - sampleRate: ctx.sampleRate, - numberOfChannels: res.length, - }); - - res.forEach((array, i) => buf.copyToChannel(array, i)); - resolve(buf); + bufferResolve = resolve; }); return {recorder, buffer}; diff --git a/src/tests/playwright/pages/processors/recorder/recorder-processor.js b/src/tests/playwright/pages/processors/recorder/recorder-processor.js index 782f7a983..b2b7452c1 100644 --- a/src/tests/playwright/pages/processors/recorder/recorder-processor.js +++ b/src/tests/playwright/pages/processors/recorder/recorder-processor.js @@ -1,17 +1,37 @@ +const MAX_RENDER_QUANTUM = 128; + // bypass-processor.js class RecorderProcessor extends AudioWorkletProcessor { - constructor() { + constructor(options) { super(); + this._pos = 0; + this._maxSamps = options.processorOptions.maxSamps; + this._recordingBuffer = new Array(this.numberOfChannels) + .fill(new Float32Array(this._maxSamps)); } process(inputs, outputs) { const input = inputs[0]; const output = outputs[0]; + // how many samps to record + const advance = Math.min(MAX_RENDER_QUANTUM, this._maxSamps - this._pos); + for (let channel = 0; channel < input.length; channel++) { + // pass-through output[channel].set(input[channel]); - this.port.postMessage({channel, data: input[channel]}); + // record `advance` samps + this._recordingBuffer[channel].set(input[channel].subarray(0, advance), this._pos) + } + + this._pos += advance; + if (this._pos >= this._maxSamps) { + this.port.postMessage({ + message: 'RECORD_DONE', + buffer: this._recordingBuffer + }) } + return true; } diff --git a/src/tests/playwright/pages/realtime-sine.html b/src/tests/playwright/pages/realtime-sine.html index 83e7f9594..be7531e46 100644 --- a/src/tests/playwright/pages/realtime-sine.html +++ b/src/tests/playwright/pages/realtime-sine.html @@ -13,7 +13,7 @@ helloSine.connect(recorder).connect(ctx.destination); helloSine.start(); - helloSine.stop(ctx.currentTime + 1); + // helloSine.stop(ctx.currentTime + 1); const audioBuffer = await buffer; const float32Buffer = audioBuffer.getChannelData(0);