Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "AudioNodeEngine.h"
8 :
9 : #include "mozilla/AbstractThread.h"
10 : #ifdef BUILD_ARM_NEON
11 : #include "mozilla/arm.h"
12 : #include "AudioNodeEngineNEON.h"
13 : #endif
14 : #ifdef USE_SSE2
15 : #include "mozilla/SSE.h"
16 : #include "AlignmentUtils.h"
17 : #include "AudioNodeEngineSSE2.h"
18 : #endif
19 :
20 : namespace mozilla {
21 :
22 : already_AddRefed<ThreadSharedFloatArrayBufferList>
23 0 : ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount,
24 : size_t aLength,
25 : const mozilla::fallible_t&)
26 : {
27 : RefPtr<ThreadSharedFloatArrayBufferList> buffer =
28 0 : new ThreadSharedFloatArrayBufferList(aChannelCount);
29 :
30 0 : for (uint32_t i = 0; i < aChannelCount; ++i) {
31 0 : float* channelData = js_pod_malloc<float>(aLength);
32 0 : if (!channelData) {
33 0 : return nullptr;
34 : }
35 :
36 0 : buffer->SetData(i, channelData, js_free, channelData);
37 : }
38 :
39 0 : return buffer.forget();
40 : }
41 :
42 : void
43 0 : WriteZeroesToAudioBlock(AudioBlock* aChunk,
44 : uint32_t aStart, uint32_t aLength)
45 : {
46 0 : MOZ_ASSERT(aStart + aLength <= WEBAUDIO_BLOCK_SIZE);
47 0 : MOZ_ASSERT(!aChunk->IsNull(), "You should pass a non-null chunk");
48 0 : if (aLength == 0)
49 0 : return;
50 :
51 0 : for (uint32_t i = 0; i < aChunk->ChannelCount(); ++i) {
52 0 : PodZero(aChunk->ChannelFloatsForWrite(i) + aStart, aLength);
53 : }
54 : }
55 :
56 0 : void AudioBufferCopyWithScale(const float* aInput,
57 : float aScale,
58 : float* aOutput,
59 : uint32_t aSize)
60 : {
61 0 : if (aScale == 1.0f) {
62 0 : PodCopy(aOutput, aInput, aSize);
63 : } else {
64 0 : for (uint32_t i = 0; i < aSize; ++i) {
65 0 : aOutput[i] = aInput[i]*aScale;
66 : }
67 : }
68 0 : }
69 :
70 0 : void AudioBufferAddWithScale(const float* aInput,
71 : float aScale,
72 : float* aOutput,
73 : uint32_t aSize)
74 : {
75 : #ifdef BUILD_ARM_NEON
76 : if (mozilla::supports_neon()) {
77 : AudioBufferAddWithScale_NEON(aInput, aScale, aOutput, aSize);
78 : return;
79 : }
80 : #endif
81 :
82 : #ifdef USE_SSE2
83 0 : if (mozilla::supports_sse2()) {
84 0 : if (aScale == 1.0f) {
85 0 : while (aSize && (!IS_ALIGNED16(aInput) || !IS_ALIGNED16(aOutput))) {
86 0 : *aOutput += *aInput;
87 0 : ++aOutput;
88 0 : ++aInput;
89 0 : --aSize;
90 : }
91 : } else {
92 0 : while (aSize && (!IS_ALIGNED16(aInput) || !IS_ALIGNED16(aOutput))) {
93 0 : *aOutput += *aInput*aScale;
94 0 : ++aOutput;
95 0 : ++aInput;
96 0 : --aSize;
97 : }
98 : }
99 :
100 : // we need to round aSize down to the nearest multiple of 16
101 0 : uint32_t alignedSize = aSize & ~0x0F;
102 0 : if (alignedSize > 0) {
103 0 : AudioBufferAddWithScale_SSE(aInput, aScale, aOutput, alignedSize);
104 :
105 : // adjust parameters for use with scalar operations below
106 0 : aInput += alignedSize;
107 0 : aOutput += alignedSize;
108 0 : aSize -= alignedSize;
109 : }
110 : }
111 : #endif
112 :
113 0 : if (aScale == 1.0f) {
114 0 : for (uint32_t i = 0; i < aSize; ++i) {
115 0 : aOutput[i] += aInput[i];
116 : }
117 : } else {
118 0 : for (uint32_t i = 0; i < aSize; ++i) {
119 0 : aOutput[i] += aInput[i]*aScale;
120 : }
121 : }
122 0 : }
123 :
124 : void
125 0 : AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
126 : float aScale,
127 : float aOutput[WEBAUDIO_BLOCK_SIZE])
128 : {
129 0 : AudioBufferAddWithScale(aInput, aScale, aOutput, WEBAUDIO_BLOCK_SIZE);
130 0 : }
131 :
132 : void
133 0 : AudioBlockCopyChannelWithScale(const float* aInput,
134 : float aScale,
135 : float* aOutput)
136 : {
137 0 : if (aScale == 1.0f) {
138 0 : memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE*sizeof(float));
139 : } else {
140 : #ifdef BUILD_ARM_NEON
141 : if (mozilla::supports_neon()) {
142 : AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
143 : return;
144 : }
145 : #endif
146 :
147 : #ifdef USE_SSE2
148 0 : if (mozilla::supports_sse2()) {
149 0 : AudioBlockCopyChannelWithScale_SSE(aInput, aScale, aOutput);
150 0 : return;
151 : }
152 : #endif
153 :
154 0 : for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
155 0 : aOutput[i] = aInput[i]*aScale;
156 : }
157 : }
158 : }
159 :
160 : void
161 0 : BufferComplexMultiply(const float* aInput,
162 : const float* aScale,
163 : float* aOutput,
164 : uint32_t aSize)
165 : {
166 :
167 : #ifdef USE_SSE2
168 0 : if (mozilla::supports_sse()) {
169 0 : BufferComplexMultiply_SSE(aInput, aScale, aOutput, aSize);
170 0 : return;
171 : }
172 : #endif
173 :
174 0 : for (uint32_t i = 0; i < aSize * 2; i += 2) {
175 0 : float real1 = aInput[i];
176 0 : float imag1 = aInput[i + 1];
177 0 : float real2 = aScale[i];
178 0 : float imag2 = aScale[i + 1];
179 0 : float realResult = real1 * real2 - imag1 * imag2;
180 0 : float imagResult = real1 * imag2 + imag1 * real2;
181 0 : aOutput[i] = realResult;
182 0 : aOutput[i + 1] = imagResult;
183 : }
184 : }
185 :
186 : float
187 0 : AudioBufferPeakValue(const float *aInput, uint32_t aSize)
188 : {
189 0 : float max = 0.0f;
190 0 : for (uint32_t i = 0; i < aSize; i++) {
191 0 : float mag = fabs(aInput[i]);
192 0 : if (mag > max) {
193 0 : max = mag;
194 : }
195 : }
196 0 : return max;
197 : }
198 :
199 : void
200 0 : AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
201 : const float aScale[WEBAUDIO_BLOCK_SIZE],
202 : float aOutput[WEBAUDIO_BLOCK_SIZE])
203 : {
204 : #ifdef BUILD_ARM_NEON
205 : if (mozilla::supports_neon()) {
206 : AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
207 : return;
208 : }
209 : #endif
210 :
211 : #ifdef USE_SSE2
212 0 : if (mozilla::supports_sse2()) {
213 0 : AudioBlockCopyChannelWithScale_SSE(aInput, aScale, aOutput);
214 0 : return;
215 : }
216 : #endif
217 :
218 0 : for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
219 0 : aOutput[i] = aInput[i]*aScale[i];
220 : }
221 : }
222 :
223 : void
224 0 : AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
225 : float aScale)
226 : {
227 0 : AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE);
228 0 : }
229 :
230 : void
231 0 : AudioBufferInPlaceScale(float* aBlock,
232 : float aScale,
233 : uint32_t aSize)
234 : {
235 0 : if (aScale == 1.0f) {
236 0 : return;
237 : }
238 : #ifdef BUILD_ARM_NEON
239 : if (mozilla::supports_neon()) {
240 : AudioBufferInPlaceScale_NEON(aBlock, aScale, aSize);
241 : return;
242 : }
243 : #endif
244 :
245 : #ifdef USE_SSE2
246 0 : if (mozilla::supports_sse2()) {
247 0 : AudioBufferInPlaceScale_SSE(aBlock, aScale, aSize);
248 0 : return;
249 : }
250 : #endif
251 :
252 0 : for (uint32_t i = 0; i < aSize; ++i) {
253 0 : *aBlock++ *= aScale;
254 : }
255 : }
256 :
257 : void
258 0 : AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
259 : float aGainL[WEBAUDIO_BLOCK_SIZE],
260 : float aGainR[WEBAUDIO_BLOCK_SIZE],
261 : float aOutputL[WEBAUDIO_BLOCK_SIZE],
262 : float aOutputR[WEBAUDIO_BLOCK_SIZE])
263 : {
264 0 : AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL);
265 0 : AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR);
266 0 : }
267 :
268 : void
269 0 : AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
270 : float aGainL, float aGainR,
271 : float aOutputL[WEBAUDIO_BLOCK_SIZE],
272 : float aOutputR[WEBAUDIO_BLOCK_SIZE])
273 : {
274 0 : AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL);
275 0 : AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR);
276 0 : }
277 :
278 : void
279 0 : AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
280 : const float aInputR[WEBAUDIO_BLOCK_SIZE],
281 : float aGainL, float aGainR, bool aIsOnTheLeft,
282 : float aOutputL[WEBAUDIO_BLOCK_SIZE],
283 : float aOutputR[WEBAUDIO_BLOCK_SIZE])
284 : {
285 : #ifdef BUILD_ARM_NEON
286 : if (mozilla::supports_neon()) {
287 : AudioBlockPanStereoToStereo_NEON(aInputL, aInputR,
288 : aGainL, aGainR, aIsOnTheLeft,
289 : aOutputL, aOutputR);
290 : return;
291 : }
292 : #endif
293 :
294 : #ifdef USE_SSE2
295 0 : if (mozilla::supports_sse2()) {
296 0 : AudioBlockPanStereoToStereo_SSE(aInputL, aInputR,
297 : aGainL, aGainR, aIsOnTheLeft,
298 0 : aOutputL, aOutputR);
299 0 : return;
300 : }
301 : #endif
302 :
303 : uint32_t i;
304 :
305 0 : if (aIsOnTheLeft) {
306 0 : for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
307 0 : aOutputL[i] = aInputL[i] + aInputR[i] * aGainL;
308 0 : aOutputR[i] = aInputR[i] * aGainR;
309 : }
310 : } else {
311 0 : for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
312 0 : aOutputL[i] = aInputL[i] * aGainL;
313 0 : aOutputR[i] = aInputR[i] + aInputL[i] * aGainR;
314 : }
315 : }
316 : }
317 :
318 : void
319 0 : AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
320 : const float aInputR[WEBAUDIO_BLOCK_SIZE],
321 : float aGainL[WEBAUDIO_BLOCK_SIZE],
322 : float aGainR[WEBAUDIO_BLOCK_SIZE],
323 : bool aIsOnTheLeft[WEBAUDIO_BLOCK_SIZE],
324 : float aOutputL[WEBAUDIO_BLOCK_SIZE],
325 : float aOutputR[WEBAUDIO_BLOCK_SIZE])
326 : {
327 : #ifdef BUILD_ARM_NEON
328 : if (mozilla::supports_neon()) {
329 : AudioBlockPanStereoToStereo_NEON(aInputL, aInputR,
330 : aGainL, aGainR, aIsOnTheLeft,
331 : aOutputL, aOutputR);
332 : return;
333 : }
334 : #endif
335 :
336 : uint32_t i;
337 0 : for (i = 0; i < WEBAUDIO_BLOCK_SIZE; i++) {
338 0 : if (aIsOnTheLeft[i]) {
339 0 : aOutputL[i] = aInputL[i] + aInputR[i] * aGainL[i];
340 0 : aOutputR[i] = aInputR[i] * aGainR[i];
341 : } else {
342 0 : aOutputL[i] = aInputL[i] * aGainL[i];
343 0 : aOutputR[i] = aInputR[i] + aInputL[i] * aGainR[i];
344 : }
345 : }
346 0 : }
347 :
348 : float
349 0 : AudioBufferSumOfSquares(const float* aInput, uint32_t aLength)
350 : {
351 0 : float sum = 0.0f;
352 :
353 : #ifdef USE_SSE2
354 0 : if (mozilla::supports_sse()) {
355 0 : const float* alignedInput = ALIGNED16(aInput);
356 0 : float vLength = (aLength >> 4) << 4;
357 :
358 : // use scalar operations for any unaligned data at the beginning
359 0 : while (aInput != alignedInput) {
360 0 : sum += *aInput * *aInput;
361 0 : ++aInput;
362 : }
363 :
364 0 : sum += AudioBufferSumOfSquares_SSE(alignedInput, vLength);
365 :
366 : // adjust aInput and aLength to use scalar operations for any
367 : // remaining values
368 0 : aInput = alignedInput + 1;
369 0 : aLength -= vLength;
370 : }
371 : #endif
372 :
373 0 : while (aLength--) {
374 0 : sum += *aInput * *aInput;
375 0 : ++aInput;
376 : }
377 0 : return sum;
378 : }
379 :
380 0 : AudioNodeEngine::AudioNodeEngine(dom::AudioNode* aNode)
381 : : mNode(aNode)
382 0 : , mNodeType(aNode ? aNode->NodeType() : nullptr)
383 0 : , mInputCount(aNode ? aNode->NumberOfInputs() : 1)
384 0 : , mOutputCount(aNode ? aNode->NumberOfOutputs() : 0)
385 : , mAbstractMainThread(
386 0 : aNode ? aNode->AbstractMainThread() : AbstractThread::MainThread())
387 : {
388 0 : MOZ_ASSERT(NS_IsMainThread());
389 0 : MOZ_COUNT_CTOR(AudioNodeEngine);
390 0 : }
391 :
392 : void
393 0 : AudioNodeEngine::ProcessBlock(AudioNodeStream* aStream,
394 : GraphTime aFrom,
395 : const AudioBlock& aInput,
396 : AudioBlock* aOutput,
397 : bool* aFinished)
398 : {
399 0 : MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
400 0 : *aOutput = aInput;
401 0 : }
402 :
403 : void
404 0 : AudioNodeEngine::ProcessBlocksOnPorts(AudioNodeStream* aStream,
405 : const OutputChunks& aInput,
406 : OutputChunks& aOutput,
407 : bool* aFinished)
408 : {
409 0 : MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1);
410 : // Only produce one output port, and drop all other input ports.
411 0 : aOutput[0] = aInput[0];
412 0 : }
413 :
414 : } // namespace mozilla
|