From 38203f0d4bebd104ac70401d6b2522ca8b6fad7d Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 16 Oct 2024 16:21:01 +0200 Subject: [PATCH] Create one-time fixed views into the heap We can remove the float-by-float JS copy and replace with this simple TypedArray set() calls. --- src/audio_worklet.js | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/audio_worklet.js b/src/audio_worklet.js index 37888be58285f..e317d820dbf10 100644 --- a/src/audio_worklet.js +++ b/src/audio_worklet.js @@ -37,6 +37,9 @@ function createWasmAudioWorkletProcessor(audioParams) { // 'render quantum size', and this exercise of passing in the value // shouldn't be required (to be verified). this.samplesPerChannel = opts['qs']; + // Typed views of the output buffers on the worklet's stack, which after + // creation should not change (since the stack is passed externally once). + this.outputViews = null; } static get parameterDescriptors() { @@ -64,9 +67,6 @@ function createWasmAudioWorkletProcessor(audioParams) { // Allocate the necessary stack space. inputsPtr = stackAlloc(stackMemoryNeeded); -#if WEBAUDIO_DEBUG - console.log(`WasmAudioWorkletProcessorr::process() ${inputsPtr} (needed: ${stackMemoryNeeded})`); -#endif // Copy input audio descriptor structs and data to Wasm k = inputsPtr >> 2; @@ -97,6 +97,20 @@ function createWasmAudioWorkletProcessor(audioParams) { // Reserve space for the output data dataPtr += bytesPerChannel * i.length; } + if (!this.outputViews) { + this.outputViews = []; + k = outputDataPtr; + for (/*which output*/ i of outputList) { + for (/*which channel*/ j of i) { + this.outputViews.push({ + // dataPtr is the sanity check (to be implemented) + // dataSub is the one-time subarray into the heap + dataPtr: k, + dataSub: HEAPF32.subarray(k, k += this.samplesPerChannel) + }); + } + } + } // Copy parameters descriptor structs and data to Wasm paramsPtr = dataPtr; @@ -115,14 +129,12 @@ function createWasmAudioWorkletProcessor(audioParams) { // Call out to Wasm callback to perform audio processing if (didProduceAudio = this.callbackFunction(numInputs, inputsPtr, numOutputs, outputsPtr, numParams, paramsPtr, this.userData)) { // Read back the produced audio data to all outputs and their channels. - // (A garbage-free function TypedArray.copy(dstTypedArray, dstOffset, - // srcTypedArray, srcOffset, count) would sure be handy.. but web does - // not have one, so manually copy all bytes in) - for (/*which output*/ i of outputList) { - for (/*which channel Float32Array*/ j of i) { - for (/*channel index*/ k = 0; k < this.samplesPerChannel; ++k) { - j[k] = HEAPF32[outputDataPtr++]; - } + // The 'outputViews' are subarray views into the heap, each with the + // correct offset and size to be copied directly into the output. + k = 0; + for (i of outputList) { + for (j of i) { + j.set(this.outputViews[k++].dataSub); } } }