Backed out changeset 06f41c22f3a6 (bug 1888460) for causing linux xpcshell failures...
[gecko.git] / dom / media / webaudio / AudioNodeEngine.cpp
blob3fba688b8cc073fcd15a884917e0c5638aa9a243
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/. */
7 #include "AudioNodeEngine.h"
9 #include "mozilla/AbstractThread.h"
10 #ifdef USE_NEON
11 # include "mozilla/arm.h"
12 # include "AudioNodeEngineGeneric.h"
13 #endif
14 #ifdef USE_SSE2
15 # include "mozilla/SSE.h"
16 # include "AudioNodeEngineGeneric.h"
17 #endif
18 #if defined(USE_SSE42) && defined(USE_FMA3)
19 # include "mozilla/SSE.h"
20 # include "AudioNodeEngineGeneric.h"
21 #endif
22 #include "AudioBlock.h"
23 #include "Tracing.h"
25 namespace mozilla {
27 already_AddRefed<ThreadSharedFloatArrayBufferList>
28 ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount, size_t aLength,
29 const mozilla::fallible_t&) {
30 RefPtr<ThreadSharedFloatArrayBufferList> buffer =
31 new ThreadSharedFloatArrayBufferList(aChannelCount);
33 for (uint32_t i = 0; i < aChannelCount; ++i) {
34 float* channelData = js_pod_malloc<float>(aLength);
35 if (!channelData) {
36 return nullptr;
39 buffer->SetData(i, channelData, js_free, channelData);
42 return buffer.forget();
45 void WriteZeroesToAudioBlock(AudioBlock* aChunk, uint32_t aStart,
46 uint32_t aLength) {
47 MOZ_ASSERT(aStart + aLength <= WEBAUDIO_BLOCK_SIZE);
48 MOZ_ASSERT(!aChunk->IsNull(), "You should pass a non-null chunk");
49 if (aLength == 0) {
50 return;
53 for (uint32_t i = 0; i < aChunk->ChannelCount(); ++i) {
54 PodZero(aChunk->ChannelFloatsForWrite(i) + aStart, aLength);
58 void AudioBufferCopyWithScale(const float* aInput, float aScale, float* aOutput,
59 uint32_t aSize) {
60 if (aScale == 1.0f) {
61 PodCopy(aOutput, aInput, aSize);
62 } else {
63 for (uint32_t i = 0; i < aSize; ++i) {
64 aOutput[i] = aInput[i] * aScale;
69 void AudioBufferAddWithScale(const float* aInput, float aScale, float* aOutput,
70 uint32_t aSize) {
71 #ifdef USE_NEON
72 if (mozilla::supports_neon()) {
73 Engine<xsimd::neon>::AudioBufferAddWithScale(aInput, aScale, aOutput,
74 aSize);
75 return;
77 #endif
79 #ifdef USE_SSE2
80 if (mozilla::supports_sse2()) {
81 # if defined(USE_SSE42) && defined(USE_FMA3)
82 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
83 Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBufferAddWithScale(
84 aInput, aScale, aOutput, aSize);
85 } else
86 # endif
88 Engine<xsimd::sse2>::AudioBufferAddWithScale(aInput, aScale, aOutput,
89 aSize);
91 return;
93 #endif
95 if (aScale == 1.0f) {
96 for (uint32_t i = 0; i < aSize; ++i) {
97 aOutput[i] += aInput[i];
99 } else {
100 for (uint32_t i = 0; i < aSize; ++i) {
101 aOutput[i] += aInput[i] * aScale;
106 void AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
107 float aScale,
108 float aOutput[WEBAUDIO_BLOCK_SIZE]) {
109 AudioBufferAddWithScale(aInput, aScale, aOutput, WEBAUDIO_BLOCK_SIZE);
112 void AudioBlockCopyChannelWithScale(const float* aInput, float aScale,
113 float* aOutput) {
114 if (aScale == 1.0f) {
115 memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE * sizeof(float));
116 } else {
117 #ifdef USE_NEON
118 if (mozilla::supports_neon()) {
119 Engine<xsimd::neon>::AudioBlockCopyChannelWithScale(aInput, aScale,
120 aOutput);
121 return;
123 #endif
125 #ifdef USE_SSE2
126 if (mozilla::supports_sse2()) {
127 Engine<xsimd::sse2>::AudioBlockCopyChannelWithScale(aInput, aScale,
128 aOutput);
129 return;
131 #endif
133 for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
134 aOutput[i] = aInput[i] * aScale;
139 void BufferComplexMultiply(const float* aInput, const float* aScale,
140 float* aOutput, uint32_t aSize) {
141 #ifdef USE_NEON
142 if (mozilla::supports_neon()) {
143 Engine<xsimd::neon>::BufferComplexMultiply(aInput, aScale, aOutput, aSize);
144 return;
146 #endif
147 #ifdef USE_SSE2
148 if (mozilla::supports_sse()) {
149 # if defined(USE_SSE42) && defined(USE_FMA3)
150 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
151 Engine<xsimd::fma3<xsimd::sse4_2>>::BufferComplexMultiply(aInput, aScale,
152 aOutput, aSize);
153 } else
154 # endif
156 Engine<xsimd::sse2>::BufferComplexMultiply(aInput, aScale, aOutput,
157 aSize);
159 return;
161 #endif
163 for (uint32_t i = 0; i < aSize * 2; i += 2) {
164 float real1 = aInput[i];
165 float imag1 = aInput[i + 1];
166 float real2 = aScale[i];
167 float imag2 = aScale[i + 1];
168 float realResult = real1 * real2 - imag1 * imag2;
169 float imagResult = real1 * imag2 + imag1 * real2;
170 aOutput[i] = realResult;
171 aOutput[i + 1] = imagResult;
175 float AudioBufferPeakValue(const float* aInput, uint32_t aSize) {
176 float max = 0.0f;
177 for (uint32_t i = 0; i < aSize; i++) {
178 float mag = fabs(aInput[i]);
179 if (mag > max) {
180 max = mag;
183 return max;
186 void AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
187 const float aScale[WEBAUDIO_BLOCK_SIZE],
188 float aOutput[WEBAUDIO_BLOCK_SIZE]) {
189 #ifdef USE_NEON
190 if (mozilla::supports_neon()) {
191 Engine<xsimd::neon>::AudioBlockCopyChannelWithScale(aInput, aScale,
192 aOutput);
193 return;
195 #endif
197 #ifdef USE_SSE2
198 if (mozilla::supports_sse2()) {
199 Engine<xsimd::sse2>::AudioBlockCopyChannelWithScale(aInput, aScale,
200 aOutput);
201 return;
203 #endif
205 for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
206 aOutput[i] = aInput[i] * aScale[i];
210 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE], float aScale) {
211 AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE);
214 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
215 float aScale[WEBAUDIO_BLOCK_SIZE]) {
216 AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE);
219 void AudioBufferInPlaceScale(float* aBlock, float aScale, uint32_t aSize) {
220 if (aScale == 1.0f) {
221 return;
223 #ifdef USE_NEON
224 if (mozilla::supports_neon()) {
225 Engine<xsimd::neon>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
226 return;
228 #endif
230 #ifdef USE_SSE2
231 if (mozilla::supports_sse2()) {
232 Engine<xsimd::sse2>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
233 return;
235 #endif
237 for (uint32_t i = 0; i < aSize; ++i) {
238 *aBlock++ *= aScale;
242 void AudioBufferInPlaceScale(float* aBlock, float* aScale, uint32_t aSize) {
243 #ifdef USE_NEON
244 if (mozilla::supports_neon()) {
245 Engine<xsimd::neon>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
246 return;
248 #endif
250 #ifdef USE_SSE2
251 if (mozilla::supports_sse2()) {
252 Engine<xsimd::sse2>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
253 return;
255 #endif
257 for (uint32_t i = 0; i < aSize; ++i) {
258 *aBlock++ *= *aScale++;
262 void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
263 float aGainL[WEBAUDIO_BLOCK_SIZE],
264 float aGainR[WEBAUDIO_BLOCK_SIZE],
265 float aOutputL[WEBAUDIO_BLOCK_SIZE],
266 float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
267 AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL);
268 AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR);
271 void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
272 float aGainL, float aGainR,
273 float aOutputL[WEBAUDIO_BLOCK_SIZE],
274 float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
275 AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL);
276 AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR);
279 void 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 #ifdef USE_NEON
285 if (mozilla::supports_neon()) {
286 Engine<xsimd::neon>::AudioBlockPanStereoToStereo(
287 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
288 return;
290 #endif
292 #ifdef USE_SSE2
293 if (mozilla::supports_sse2()) {
294 # if defined(USE_SSE42) && defined(USE_FMA3)
295 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
296 Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBlockPanStereoToStereo(
297 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
298 } else
299 # endif
301 Engine<xsimd::sse2>::AudioBlockPanStereoToStereo(
302 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
304 return;
306 #endif
308 uint32_t i;
310 if (aIsOnTheLeft) {
311 for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
312 aOutputL[i] = aInputL[i] + aInputR[i] * aGainL;
313 aOutputR[i] = aInputR[i] * aGainR;
315 } else {
316 for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
317 aOutputL[i] = aInputL[i] * aGainL;
318 aOutputR[i] = aInputR[i] + aInputL[i] * aGainR;
323 void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
324 const float aInputR[WEBAUDIO_BLOCK_SIZE],
325 const float aGainL[WEBAUDIO_BLOCK_SIZE],
326 const float aGainR[WEBAUDIO_BLOCK_SIZE],
327 const bool aIsOnTheLeft[WEBAUDIO_BLOCK_SIZE],
328 float aOutputL[WEBAUDIO_BLOCK_SIZE],
329 float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
330 #ifdef USE_NEON
331 if (mozilla::supports_neon()) {
332 Engine<xsimd::neon>::AudioBlockPanStereoToStereo(
333 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
334 return;
336 #endif
338 #ifdef USE_SSE2
339 if (mozilla::supports_sse2()) {
340 # if defined(USE_SSE42) && defined(USE_FMA3)
341 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
342 Engine<xsimd::fma3<xsimd::sse2>>::AudioBlockPanStereoToStereo(
343 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
344 } else
345 # endif
347 Engine<xsimd::sse2>::AudioBlockPanStereoToStereo(
348 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
350 return;
352 #endif
354 uint32_t i;
355 for (i = 0; i < WEBAUDIO_BLOCK_SIZE; i++) {
356 if (aIsOnTheLeft[i]) {
357 aOutputL[i] = aInputL[i] + aInputR[i] * aGainL[i];
358 aOutputR[i] = aInputR[i] * aGainR[i];
359 } else {
360 aOutputL[i] = aInputL[i] * aGainL[i];
361 aOutputR[i] = aInputR[i] + aInputL[i] * aGainR[i];
366 float AudioBufferSumOfSquares(const float* aInput, uint32_t aLength) {
367 #ifdef USE_NEON
368 if (mozilla::supports_neon()) {
369 return Engine<xsimd::neon>::AudioBufferSumOfSquares(aInput, aLength);
371 #endif
373 #ifdef USE_SSE2
374 if (mozilla::supports_sse()) {
375 # if defined(USE_SSE42) && defined(USE_FMA3)
376 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
377 return Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBufferSumOfSquares(
378 aInput, aLength);
379 } else
380 # endif
382 return Engine<xsimd::sse2>::AudioBufferSumOfSquares(aInput, aLength);
385 #endif
387 float sum = 0.f;
388 while (aLength--) {
389 sum += *aInput * *aInput;
390 ++aInput;
392 return sum;
395 void NaNToZeroInPlace(float* aSamples, size_t aCount) {
396 #ifdef USE_SSE2
397 if (mozilla::supports_sse2()) {
398 Engine<xsimd::sse2>::NaNToZeroInPlace(aSamples, aCount);
399 return;
401 #endif
402 for (size_t i = 0; i < aCount; i++) {
403 if (aSamples[i] != aSamples[i]) {
404 aSamples[i] = 0.0;
409 AudioNodeEngine::AudioNodeEngine(dom::AudioNode* aNode)
410 : mNode(aNode),
411 mNodeType(aNode ? aNode->NodeType() : nullptr),
412 mInputCount(aNode ? aNode->NumberOfInputs() : 1),
413 mOutputCount(aNode ? aNode->NumberOfOutputs() : 0) {
414 MOZ_ASSERT(NS_IsMainThread());
415 MOZ_COUNT_CTOR(AudioNodeEngine);
418 void AudioNodeEngine::ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom,
419 const AudioBlock& aInput,
420 AudioBlock* aOutput, bool* aFinished) {
421 MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
422 TRACE("AudioNodeEngine::ProcessBlock");
423 *aOutput = aInput;
426 void AudioNodeEngine::ProcessBlocksOnPorts(AudioNodeTrack* aTrack,
427 GraphTime aFrom,
428 Span<const AudioBlock> aInput,
429 Span<AudioBlock> aOutput,
430 bool* aFinished) {
431 MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1);
432 TRACE("AudioNodeEngine::ProcessBlocksOnPorts");
433 // Only produce one output port, and drop all other input ports.
434 aOutput[0] = aInput[0];
437 } // namespace mozilla