Skip to content

Commit da38e4b

Browse files
committed
Simplify struct fills, fix wasm64
1 parent fc7abc8 commit da38e4b

File tree

1 file changed

+30
-36
lines changed

1 file changed

+30
-36
lines changed

src/audio_worklet.js

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -72,56 +72,60 @@ function createWasmAudioWorkletProcessor(audioParams) {
7272
}
7373

7474
/**
75+
* Marshals all inputs and parameters to the Wasm memory on the thread's
76+
* stack, then performs the wasm audio worklet call, and finally marshals
77+
* audio output data back.
78+
*
7579
* @param {Object} parameters
7680
*/
7781
process(inputList, outputList, parameters) {
78-
// Marshal all inputs and parameters to the Wasm memory on the thread stack,
79-
// then perform the wasm audio worklet call,
80-
// and finally marshal audio output data back.
81-
8282
var numInputs = inputList.length;
8383
var numOutputs = outputList.length;
8484

8585
var entry; // reused list entry or index
8686
var subentry; // reused channel or other array in each list entry or index
8787

88-
// Calculate the required stack and output buffer views
89-
var stackMemoryNeeded = (numInputs + numOutputs) * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
88+
// Calculate the required stack and output buffer views (stack is further
89+
// split into aligned structs and the raw float data).
90+
var stackMemoryStruct = (numInputs + numOutputs) * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
91+
var stackMemoryData = 0;
9092
for (entry of inputList) {
91-
stackMemoryNeeded += entry.length * this.bytesPerChannel;
93+
stackMemoryData += entry.length * this.bytesPerChannel;
9294
}
95+
// Collect the total number of output channels (mapped to array views)
9396
var outputViewsNeeded = 0;
9497
for (entry of outputList) {
9598
outputViewsNeeded += entry.length;
9699
}
97-
stackMemoryNeeded += outputViewsNeeded * this.bytesPerChannel;
100+
stackMemoryData += outputViewsNeeded * this.bytesPerChannel;
98101
var numParams = 0;
99102
for (entry in parameters) {
100-
stackMemoryNeeded += parameters[entry].byteLength + {{{ C_STRUCTS.AudioParamFrame.__size__ }}};
101103
++numParams;
104+
stackMemoryStruct += {{{ C_STRUCTS.AudioParamFrame.__size__ }}};
105+
stackMemoryData += parameters[entry].byteLength;
102106
}
103107
#if ASSERTIONS
104108
console.assert(outputViewsNeeded <= this.outputViews.length, `Too many AudioWorklet outputs (need ${outputViewsNeeded} but have stack space for ${this.outputViews.length})`);
105109
#endif
106110
107111
var oldStackPtr = stackSave();
108-
// Allocate the necessary stack space. All pointer variables are always in
109-
// bytes; 'dataPtr' is the start of the data section, advancing as space
110-
// for structs and data is taken; 'structPtr' is reused as the working
111-
// start to each struct record.
112-
// Ordinarily 'dataPtr' would be 16-byte aligned, from the internal
113-
// _emscripten_stack_alloc(), as were the output views, and so to ensure
114-
// the views fall on the correct addresses (and we finish at the stacktop)
115-
// bytes are added and the start advanced.
116-
var alignedNeededStack = (stackMemoryNeeded + 15) & ~15;
117-
var dataPtr = stackAlloc(alignedNeededStack);
112+
// Allocate the necessary stack space. All pointer variables are in bytes;
113+
// 'structPtr' starts at the first struct entry (all run sequentially)
114+
// and is the working start to each record; 'dataPtr' is the same for the
115+
// audio/params data, starting after *all* the structs.
116+
// 'structPtr' begins 16-byte aligned, allocated from the internal
117+
// _emscripten_stack_alloc(), as are the output views, and so to ensure
118+
// the views fall on the correct addresses (and we finish at stacktop) we
119+
// request additional bytes, taking this alignment into account, then
120+
// offset `dataPtr` by the difference.
121+
var stackMemoryAligned = (stackMemoryStruct + stackMemoryData + 15) & ~15;
122+
var structPtr = stackAlloc(stackMemoryAligned);
123+
var dataPtr = structPtr + (stackMemoryAligned - stackMemoryData);
118124
119125
// Copy input audio descriptor structs and data to Wasm (recall, structs
120126
// first, audio data after). 'inputsPtr' is the start of the C callback's
121127
// input AudioSampleFrame.
122-
var /*const*/ inputsPtr = dataPtr;
123-
var structPtr = inputsPtr;
124-
dataPtr += numInputs * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
128+
var /*const*/ inputsPtr = structPtr;
125129
for (entry of inputList) {
126130
// Write the AudioSampleFrame struct instance
127131
{{{ makeSetValue('structPtr', C_STRUCTS.AudioSampleFrame.numberOfChannels, 'entry.length', 'u32') }}};
@@ -137,9 +141,7 @@ function createWasmAudioWorkletProcessor(audioParams) {
137141
138142
// Copy parameters descriptor structs and data to Wasm. 'paramsPtr' is the
139143
// start of the C callback's input AudioParamFrame.
140-
var /*const*/ paramsPtr = dataPtr;
141-
structPtr = paramsPtr;
142-
dataPtr += numParams * {{{ C_STRUCTS.AudioParamFrame.__size__ }}};
144+
var /*const*/ paramsPtr = structPtr;
143145
for (entry = 0; subentry = parameters[entry++];) {
144146
// Write the AudioParamFrame struct instance
145147
{{{ makeSetValue('structPtr', C_STRUCTS.AudioParamFrame.length, 'subentry.length', 'u32') }}};
@@ -150,18 +152,10 @@ function createWasmAudioWorkletProcessor(audioParams) {
150152
dataPtr += subentry.length * {{{ getNativeTypeSize('float') }}};
151153
}
152154
153-
// TODO: why does Chrome wasm64 (Chrome has weird rules for params) need
154-
// the manual alignment here? An off-by-one somewhere? outputsPtr is
155-
// getting clobbered otherwise, is the struct correctly aligned? Do more
156-
// stack allocs instead? Probably needs alignments between struct writes?
157-
dataPtr += alignedNeededStack - stackMemoryNeeded;
158-
159155
// Copy output audio descriptor structs to Wasm. 'outputsPtr' is the start
160-
// of the C callback's output AudioSampleFrame.
161-
// Note: dataPtr after the struct offsets should now be 16-byte aligned.
162-
var /*const*/ outputsPtr = dataPtr;
163-
structPtr = outputsPtr;
164-
dataPtr += numOutputs * {{{ C_STRUCTS.AudioSampleFrame.__size__ }}};
156+
// of the C callback's output AudioSampleFrame. 'dataPtr' will now be
157+
// aligned with the output views, ending at stacktop.
158+
var /*const*/ outputsPtr = structPtr;
165159
for (entry of outputList) {
166160
// Write the AudioSampleFrame struct instance
167161
{{{ makeSetValue('structPtr', C_STRUCTS.AudioSampleFrame.numberOfChannels, 'entry.length', 'u32') }}};

0 commit comments

Comments
 (0)