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"
11 # include "mozilla/arm.h"
12 # include "AudioNodeEngineGeneric.h"
15 # include "mozilla/SSE.h"
16 # include "AudioNodeEngineGeneric.h"
18 #if defined(USE_SSE42) && defined(USE_FMA3)
19 # include "mozilla/SSE.h"
20 # include "AudioNodeEngineGeneric.h"
22 #include "AudioBlock.h"
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
);
39 buffer
->SetData(i
, channelData
, js_free
, channelData
);
42 return buffer
.forget();
45 void WriteZeroesToAudioBlock(AudioBlock
* aChunk
, uint32_t aStart
,
47 MOZ_ASSERT(aStart
+ aLength
<= WEBAUDIO_BLOCK_SIZE
);
48 MOZ_ASSERT(!aChunk
->IsNull(), "You should pass a non-null chunk");
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
,
61 PodCopy(aOutput
, aInput
, aSize
);
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
,
72 if (mozilla::supports_neon()) {
73 Engine
<xsimd::neon
>::AudioBufferAddWithScale(aInput
, aScale
, aOutput
,
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
);
88 Engine
<xsimd::sse2
>::AudioBufferAddWithScale(aInput
, aScale
, aOutput
,
96 for (uint32_t i
= 0; i
< aSize
; ++i
) {
97 aOutput
[i
] += aInput
[i
];
100 for (uint32_t i
= 0; i
< aSize
; ++i
) {
101 aOutput
[i
] += aInput
[i
] * aScale
;
106 void AudioBlockAddChannelWithScale(const float aInput
[WEBAUDIO_BLOCK_SIZE
],
108 float aOutput
[WEBAUDIO_BLOCK_SIZE
]) {
109 AudioBufferAddWithScale(aInput
, aScale
, aOutput
, WEBAUDIO_BLOCK_SIZE
);
112 void AudioBlockCopyChannelWithScale(const float* aInput
, float aScale
,
114 if (aScale
== 1.0f
) {
115 memcpy(aOutput
, aInput
, WEBAUDIO_BLOCK_SIZE
* sizeof(float));
118 if (mozilla::supports_neon()) {
119 Engine
<xsimd::neon
>::AudioBlockCopyChannelWithScale(aInput
, aScale
,
126 if (mozilla::supports_sse2()) {
127 Engine
<xsimd::sse2
>::AudioBlockCopyChannelWithScale(aInput
, aScale
,
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
) {
142 if (mozilla::supports_neon()) {
143 Engine
<xsimd::neon
>::BufferComplexMultiply(aInput
, aScale
, aOutput
, aSize
);
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
,
156 Engine
<xsimd::sse2
>::BufferComplexMultiply(aInput
, aScale
, aOutput
,
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
) {
177 for (uint32_t i
= 0; i
< aSize
; i
++) {
178 float mag
= fabs(aInput
[i
]);
186 void AudioBlockCopyChannelWithScale(const float aInput
[WEBAUDIO_BLOCK_SIZE
],
187 const float aScale
[WEBAUDIO_BLOCK_SIZE
],
188 float aOutput
[WEBAUDIO_BLOCK_SIZE
]) {
190 if (mozilla::supports_neon()) {
191 Engine
<xsimd::neon
>::AudioBlockCopyChannelWithScale(aInput
, aScale
,
198 if (mozilla::supports_sse2()) {
199 Engine
<xsimd::sse2
>::AudioBlockCopyChannelWithScale(aInput
, aScale
,
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
) {
224 if (mozilla::supports_neon()) {
225 Engine
<xsimd::neon
>::AudioBufferInPlaceScale(aBlock
, aScale
, aSize
);
231 if (mozilla::supports_sse2()) {
232 Engine
<xsimd::sse2
>::AudioBufferInPlaceScale(aBlock
, aScale
, aSize
);
237 for (uint32_t i
= 0; i
< aSize
; ++i
) {
242 void AudioBufferInPlaceScale(float* aBlock
, float* aScale
, uint32_t aSize
) {
244 if (mozilla::supports_neon()) {
245 Engine
<xsimd::neon
>::AudioBufferInPlaceScale(aBlock
, aScale
, aSize
);
251 if (mozilla::supports_sse2()) {
252 Engine
<xsimd::sse2
>::AudioBufferInPlaceScale(aBlock
, aScale
, aSize
);
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
]) {
285 if (mozilla::supports_neon()) {
286 Engine
<xsimd::neon
>::AudioBlockPanStereoToStereo(
287 aInputL
, aInputR
, aGainL
, aGainR
, aIsOnTheLeft
, aOutputL
, aOutputR
);
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
);
301 Engine
<xsimd::sse2
>::AudioBlockPanStereoToStereo(
302 aInputL
, aInputR
, aGainL
, aGainR
, aIsOnTheLeft
, aOutputL
, aOutputR
);
311 for (i
= 0; i
< WEBAUDIO_BLOCK_SIZE
; ++i
) {
312 aOutputL
[i
] = aInputL
[i
] + aInputR
[i
] * aGainL
;
313 aOutputR
[i
] = aInputR
[i
] * aGainR
;
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
]) {
331 if (mozilla::supports_neon()) {
332 Engine
<xsimd::neon
>::AudioBlockPanStereoToStereo(
333 aInputL
, aInputR
, aGainL
, aGainR
, aIsOnTheLeft
, aOutputL
, aOutputR
);
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
);
347 Engine
<xsimd::sse2
>::AudioBlockPanStereoToStereo(
348 aInputL
, aInputR
, aGainL
, aGainR
, aIsOnTheLeft
, aOutputL
, aOutputR
);
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
];
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
) {
368 if (mozilla::supports_neon()) {
369 return Engine
<xsimd::neon
>::AudioBufferSumOfSquares(aInput
, aLength
);
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(
382 return Engine
<xsimd::sse2
>::AudioBufferSumOfSquares(aInput
, aLength
);
389 sum
+= *aInput
* *aInput
;
395 void NaNToZeroInPlace(float* aSamples
, size_t aCount
) {
397 if (mozilla::supports_sse2()) {
398 Engine
<xsimd::sse2
>::NaNToZeroInPlace(aSamples
, aCount
);
402 for (size_t i
= 0; i
< aCount
; i
++) {
403 if (aSamples
[i
] != aSamples
[i
]) {
409 AudioNodeEngine::AudioNodeEngine(dom::AudioNode
* 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");
426 void AudioNodeEngine::ProcessBlocksOnPorts(AudioNodeTrack
* aTrack
,
428 Span
<const AudioBlock
> aInput
,
429 Span
<AudioBlock
> aOutput
,
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