@@ -40,10 +40,16 @@ function createWasmAudioWorkletProcessor(audioParams) {
40
40
this . samplesPerChannel = opts [ 'sc' ] ;
41
41
42
42
// Create up-front as many typed views for marshalling the output data as
43
- // may be required (with an arbitrary maximum of 16 , for the case where a
43
+ // may be required (with an arbitrary maximum of 10 , for the case where a
44
44
// multi-MB stack is passed), allocated at the *top* of the worklet's
45
- // stack (and whose addresses are fixed).
46
- this . maxBuffers = Math . min ( ( ( Module [ 'sz' ] - /*stack guards?*/ 16 ) / ( this . samplesPerChannel * 4 ) ) | 0 , /*sensible limit*/ 16 ) ;
45
+ // stack (and whose addresses are fixed). The 'minimum alloc' firstly
46
+ // stops STACK_OVERFLOW_CHECK failing (since the stack will be full, and
47
+ // 16 being the minimum allocation size due to alignments) and leaves room
48
+ // for a single AudioSampleFrame as a minumum.
49
+ this . maxBuffers = Math . min ( ( ( Module [ 'sz' ] - /*minimum alloc*/ 16 ) / ( this . samplesPerChannel * 4 ) ) | 0 , /*sensible limit*/ 10 ) ;
50
+ #if ASSERTIONS
51
+ console . assert ( this . maxBuffers > 0 , `AudioWorklet needs more stack allocating (at least ${ this . samplesPerChannel * 4 } )` ) ;
52
+ #endif
47
53
// These are still alloc'd to take advantage of the overflow checks, etc.
48
54
var oldStackPtr = stackSave ( ) ;
49
55
var viewDataIdx = stackAlloc ( this . maxBuffers * this . samplesPerChannel * 4 ) >> 2 ;
@@ -77,7 +83,6 @@ function createWasmAudioWorkletProcessor(audioParams) {
77
83
stackMemoryNeeded = ( numInputs + numOutputs ) * { { { C_STRUCTS . AudioSampleFrame . __size__ } } } ,
78
84
oldStackPtr = stackSave ( ) ,
79
85
inputsPtr , outputsPtr , paramsPtr ,
80
- outputDataPtr ,
81
86
didProduceAudio , paramArray ;
82
87
83
88
// Calculate how much stack space is needed
@@ -91,14 +96,18 @@ function createWasmAudioWorkletProcessor(audioParams) {
91
96
#endif
92
97
93
98
// Allocate the necessary stack space (dataPtr is always in bytes, and
94
- // advances as space for structs as data is taken, but note the switching
95
- // between bytes and indices into the various heaps, usually in 'k').
96
- dataPtr = stackAlloc ( stackMemoryNeeded ) ;
99
+ // advances as space for structs and data is taken, but note the switching
100
+ // between bytes and indices into the various heaps, usually in 'k'). This
101
+ // will be 16-byte aligned (from _emscripten_stack_alloc()), as were the
102
+ // output views, so we round up and advance the required bytes to ensure
103
+ // the addresses all work out at the end.
104
+ i = ( stackMemoryNeeded + 15 ) & ~ 15 ;
105
+ dataPtr = stackAlloc ( i ) + ( i - stackMemoryNeeded ) ;
97
106
98
107
// Copy input audio descriptor structs and data to Wasm
99
108
inputsPtr = dataPtr ;
100
- k = inputsPtr >> 2 ;
101
109
dataPtr += numInputs * { { { C_STRUCTS . AudioSampleFrame . __size__ } } } ;
110
+ k = inputsPtr >> 2 ;
102
111
for ( i of inputList ) {
103
112
// Write the AudioSampleFrame struct instance
104
113
HEAPU32 [ k + { { { C_STRUCTS . AudioSampleFrame . numberOfChannels / 4 } } } ] = i . length ;
@@ -114,8 +123,8 @@ function createWasmAudioWorkletProcessor(audioParams) {
114
123
115
124
// Copy parameters descriptor structs and data to Wasm
116
125
paramsPtr = dataPtr ;
117
- k = paramsPtr >> 2 ;
118
126
dataPtr += numParams * { { { C_STRUCTS . AudioParamFrame . __size__ } } } ;
127
+ k = paramsPtr >> 2 ;
119
128
for ( i = 0 ; paramArray = parameters [ i ++ ] ; ) {
120
129
// Write the AudioParamFrame struct instance
121
130
HEAPU32 [ k + { { { C_STRUCTS . AudioParamFrame . length / 4 } } } ] = paramArray . length ;
@@ -126,13 +135,11 @@ function createWasmAudioWorkletProcessor(audioParams) {
126
135
dataPtr += paramArray . length * 4 ;
127
136
}
128
137
129
- // Copy output audio descriptor structs to Wasm
138
+ // Copy output audio descriptor structs to Wasm (not that dataPtr after
139
+ // the struct offsets should now be 16-byte aligned).
130
140
outputsPtr = dataPtr ;
131
- k = outputsPtr >> 2 ;
132
141
dataPtr += numOutputs * { { { C_STRUCTS . AudioSampleFrame . __size__ } } } ;
133
- #if ASSERTIONS
134
- outputDataPtr = dataPtr ;
135
- #endif
142
+ k = outputsPtr >> 2 ;
136
143
for ( i of outputList ) {
137
144
// Write the AudioSampleFrame struct instance
138
145
HEAPU32 [ k + { { { C_STRUCTS . AudioSampleFrame . numberOfChannels / 4 } } } ] = i . length ;
@@ -144,23 +151,27 @@ function createWasmAudioWorkletProcessor(audioParams) {
144
151
}
145
152
146
153
#if ASSERTIONS
147
- // TODO: addresses are now wrong
148
- k = outputDataPtr ;
149
- for ( i = outputViewsNeeded - 1 ; i >= 0 ; i -- ) {
150
- console . assert ( this . outputViews [ i ] . byteOffset == k , 'Internal error in addresses of the output array views' ) ;
151
- k += bytesPerChannel ;
154
+ // If all the maths worked out, we arrived at the original stack address
155
+ console . assert ( dataPtr == oldStackPtr , `AudioWorklet stack missmatch (audio data finishes at ${ dataPtr } instead of ${ oldStackPtr } )` ) ;
156
+ // Sanity check the output view addresses
157
+ if ( numOutputs ) {
158
+ k = dataPtr - bytesPerChannel ;
159
+ for ( i = 0 ; i < outputViewsNeeded ; i ++ ) {
160
+ console . assert ( k == this . outputViews [ i ] . byteOffset , 'AudioWorklet internal error in addresses of the output array views' ) ;
161
+ k -= bytesPerChannel ;
162
+ }
152
163
}
153
164
#endif
154
165
155
166
// Call out to Wasm callback to perform audio processing
156
167
if ( didProduceAudio = this . callbackFunction ( numInputs , inputsPtr , numOutputs , outputsPtr , numParams , paramsPtr , this . userData ) ) {
157
168
// Read back the produced audio data to all outputs and their channels.
158
- // The 'outputViews' are subarray views into the heap, each with the
159
- // correct offset and size to be copied directly into the output .
160
- k = 0 ;
169
+ // The preallocated 'outputViews' already have the correct offsets and
170
+ // sizes into the stack (recall from the ctor that they run backwards) .
171
+ k = outputViewsNeeded - 1 ;
161
172
for ( i of outputList ) {
162
173
for ( j of i ) {
163
- j . set ( this . outputViews [ k ++ ] ) ;
174
+ j . set ( this . outputViews [ k -- ] ) ;
164
175
}
165
176
}
166
177
}
0 commit comments