@@ -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