@@ -72,56 +72,60 @@ function createWasmAudioWorkletProcessor(audioParams) {
72
72
}
73
73
74
74
/**
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
+ *
75
79
* @param {Object } parameters
76
80
*/
77
81
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
-
82
82
var numInputs = inputList . length ;
83
83
var numOutputs = outputList . length ;
84
84
85
85
var entry ; // reused list entry or index
86
86
var subentry ; // reused channel or other array in each list entry or index
87
87
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 ;
90
92
for ( entry of inputList ) {
91
- stackMemoryNeeded += entry . length * this . bytesPerChannel ;
93
+ stackMemoryData += entry . length * this . bytesPerChannel ;
92
94
}
95
+ // Collect the total number of output channels (mapped to array views)
93
96
var outputViewsNeeded = 0 ;
94
97
for ( entry of outputList ) {
95
98
outputViewsNeeded += entry . length ;
96
99
}
97
- stackMemoryNeeded += outputViewsNeeded * this . bytesPerChannel ;
100
+ stackMemoryData += outputViewsNeeded * this . bytesPerChannel ;
98
101
var numParams = 0 ;
99
102
for ( entry in parameters ) {
100
- stackMemoryNeeded += parameters [ entry ] . byteLength + { { { C_STRUCTS . AudioParamFrame . __size__ } } } ;
101
103
++ numParams ;
104
+ stackMemoryStruct += { { { C_STRUCTS . AudioParamFrame . __size__ } } } ;
105
+ stackMemoryData + = parameters [ entry ] . byteLength ;
102
106
}
103
107
#if ASSERTIONS
104
108
console . assert ( outputViewsNeeded <= this . outputViews . length , `Too many AudioWorklet outputs ( need $ { outputViewsNeeded } but have stack space for ${this . outputViews . length } ) `);
105
109
#endif
106
110
107
111
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);
118
124
119
125
// Copy input audio descriptor structs and data to Wasm (recall, structs
120
126
// first, audio data after). 'inputsPtr' is the start of the C callback's
121
127
// input AudioSampleFrame.
122
- var /*const*/ inputsPtr = dataPtr ;
123
- var structPtr = inputsPtr ;
124
- dataPtr += numInputs * { { { C_STRUCTS . AudioSampleFrame . __size__ } } } ;
128
+ var /*const*/ inputsPtr = structPtr;
125
129
for (entry of inputList) {
126
130
// Write the AudioSampleFrame struct instance
127
131
{{{ makeSetValue('structPtr', C_STRUCTS.AudioSampleFrame.numberOfChannels, 'entry.length', 'u32') }}};
@@ -137,9 +141,7 @@ function createWasmAudioWorkletProcessor(audioParams) {
137
141
138
142
// Copy parameters descriptor structs and data to Wasm. 'paramsPtr' is the
139
143
// 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;
143
145
for (entry = 0; subentry = parameters[entry++];) {
144
146
// Write the AudioParamFrame struct instance
145
147
{{{ makeSetValue('structPtr', C_STRUCTS.AudioParamFrame.length, 'subentry.length', 'u32') }}};
@@ -150,18 +152,10 @@ function createWasmAudioWorkletProcessor(audioParams) {
150
152
dataPtr += subentry.length * {{{ getNativeTypeSize('float') }}};
151
153
}
152
154
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
-
159
155
// 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;
165
159
for (entry of outputList) {
166
160
// Write the AudioSampleFrame struct instance
167
161
{{{ makeSetValue('structPtr', C_STRUCTS.AudioSampleFrame.numberOfChannels, 'entry.length', 'u32') }}};
0 commit comments