Skip to content

Commit 1791a2e

Browse files
committed
Work in progress, moved the output buffers first
Lots of juggling with the various pointers, and next will be to reduce the code and move all of the output first to stop repeating some of the calculations. Some can also move to the constructor.
1 parent 41f89e9 commit 1791a2e

File tree

1 file changed

+50
-28
lines changed

1 file changed

+50
-28
lines changed

src/audio_worklet.js

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ function createWasmAudioWorkletProcessor(audioParams) {
3333
this.userData = opts['ud'];
3434
// Then the samples per channel to process, fixed for the lifetime of the
3535
// context that created this processor. Note for when moving to Web Audio
36-
// 1.1: the typed array passed to process() should be the same size as this
37-
// 'render quantum size', and this exercise of passing in the value
38-
// shouldn't be required (to be verified).
36+
// 1.1: the typed array passed to process() should be the same size as
37+
// this 'render quantum size', and this exercise of passing in the value
38+
// shouldn't be required (to be verified with the in/out data lengths).
3939
this.samplesPerChannel = opts['sc'];
4040
// Typed views of the output buffers on the worklet's stack, which after
4141
// creation should only change if the audio chain changes.
@@ -47,6 +47,7 @@ function createWasmAudioWorkletProcessor(audioParams) {
4747
}
4848

4949
process(inputList, outputList, parameters) {
50+
var time = Date.now();
5051
// Marshal all inputs and parameters to the Wasm memory on the thread stack,
5152
// then perform the wasm audio worklet call,
5253
// and finally marshal audio output data back.
@@ -65,12 +66,47 @@ function createWasmAudioWorkletProcessor(audioParams) {
6566
for (i of outputList) stackMemoryNeeded += i.length * bytesPerChannel;
6667
for (i in parameters) stackMemoryNeeded += parameters[i].byteLength + {{{ C_STRUCTS.AudioParamFrame.__size__ }}}, ++numParams;
6768

68-
// Allocate the necessary stack space.
69-
inputsPtr = stackAlloc(stackMemoryNeeded);
69+
// Allocate the necessary stack space (dataPtr is always in bytes, and
70+
// advances as space for structs as data is taken, but note the switching
71+
// between bytes and indices into the various heaps).
72+
dataPtr = stackAlloc(stackMemoryNeeded);
73+
74+
// But start the output view allocs first, since once views are created we
75+
// want them to always start from the same address. Even if in the next
76+
// process() the outputList is empty, as soon as there are channels again
77+
// the views' addresses will still be the same (and only if more views are
78+
// required we will recreate them).
79+
outputDataPtr = dataPtr;
80+
for (/*which output*/i of outputList) {
81+
#if ASSERTIONS
82+
for (/*which channel*/ j of i) {
83+
console.assert(j.byteLength === bytesPerChannel, `Unexpected AudioWorklet output buffer size (expected ${bytesPerChannel} got ${j.byteLength})`);
84+
}
85+
#endif
86+
// Keep advancing to make room for the output views
87+
dataPtr += bytesPerChannel * i.length;
88+
// How many output views are needed in total?
89+
requiredViews += i.length;
90+
}
91+
// Verify we have enough views (it doesn't matter if we have too many, any
92+
// excess won't be accessed) then also verify the views' start address
93+
// haven't changed.
94+
if (this.outputViews.length < requiredViews || (this.outputViews.length && this.outputViews[0].byteOffset != outputDataPtr)) {
95+
this.outputViews = [];
96+
k = outputDataPtr >> 2;
97+
for (i of outputList) {
98+
for (j of i) {
99+
this.outputViews.push(
100+
HEAPF32.subarray(k, k += this.samplesPerChannel)
101+
);
102+
}
103+
}
104+
}
70105

71106
// Copy input audio descriptor structs and data to Wasm
107+
inputsPtr = dataPtr;
72108
k = inputsPtr >> 2;
73-
dataPtr = inputsPtr + numInputs * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
109+
dataPtr += numInputs * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
74110
for (i of inputList) {
75111
// Write the AudioSampleFrame struct instance
76112
HEAPU32[k + {{{ C_STRUCTS.AudioSampleFrame.numberOfChannels / 4 }}}] = i.length;
@@ -85,35 +121,18 @@ function createWasmAudioWorkletProcessor(audioParams) {
85121
}
86122

87123
// Copy output audio descriptor structs to Wasm
124+
// TODO: now dataPtr tracks the next address, move this above
88125
outputsPtr = dataPtr;
89126
k = outputsPtr >> 2;
90-
outputDataPtr = (dataPtr += numOutputs * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}}) >> 2;
127+
dataPtr += numOutputs * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
91128
for (i of outputList) {
92129
// Write the AudioSampleFrame struct instance
93130
HEAPU32[k + {{{ C_STRUCTS.AudioSampleFrame.numberOfChannels / 4 }}}] = i.length;
94131
HEAPU32[k + {{{ C_STRUCTS.AudioSampleFrame.samplesPerChannel / 4 }}}] = this.samplesPerChannel;
95-
HEAPU32[k + {{{ C_STRUCTS.AudioSampleFrame.data / 4 }}}] = dataPtr;
132+
HEAPU32[k + {{{ C_STRUCTS.AudioSampleFrame.data / 4 }}}] = outputDataPtr;
96133
k += {{{ C_STRUCTS.AudioSampleFrame.__size__ / 4 }}};
97-
// Reserve space for the output data
98-
dataPtr += bytesPerChannel * i.length;
99-
// How many output views are needed in total?
100-
requiredViews += i.length;
101-
}
102-
103-
// Verify we have enough views (it doesn't matter if we have too many, any
104-
// excess won't be accessed) then also verify the views' start address
105-
// hasn't changed.
106-
// TODO: allocate space for outputDataPtr before any inputs?
107-
k = outputDataPtr;
108-
if (this.outputViews.length < requiredViews || (this.outputViews.length && this.outputViews[0].byteOffset != k << 2)) {
109-
this.outputViews = [];
110-
for (/*which output*/ i of outputList) {
111-
for (/*which channel*/ j of i) {
112-
this.outputViews.push(
113-
HEAPF32.subarray(k, k += this.samplesPerChannel)
114-
);
115-
}
116-
}
134+
// Advance the output pointer to the next output
135+
outputDataPtr += bytesPerChannel * i.length;
117136
}
118137

119138
// Copy parameters descriptor structs and data to Wasm
@@ -144,6 +163,9 @@ function createWasmAudioWorkletProcessor(audioParams) {
144163
}
145164

146165
stackRestore(oldStackPtr);
166+
167+
time = Date.now() - time;
168+
//console.log(time);
147169

148170
// Return 'true' to tell the browser to continue running this processor.
149171
// (Returning 1 or any other truthy value won't work in Chrome)

0 commit comments

Comments
 (0)