summaryrefslogtreecommitdiffstats
path: root/dom/media/webaudio/AudioNodeEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webaudio/AudioNodeEngine.cpp')
-rw-r--r--dom/media/webaudio/AudioNodeEngine.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/dom/media/webaudio/AudioNodeEngine.cpp b/dom/media/webaudio/AudioNodeEngine.cpp
new file mode 100644
index 0000000000..3fba688b8c
--- /dev/null
+++ b/dom/media/webaudio/AudioNodeEngine.cpp
@@ -0,0 +1,437 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AudioNodeEngine.h"
+
+#include "mozilla/AbstractThread.h"
+#ifdef USE_NEON
+# include "mozilla/arm.h"
+# include "AudioNodeEngineGeneric.h"
+#endif
+#ifdef USE_SSE2
+# include "mozilla/SSE.h"
+# include "AudioNodeEngineGeneric.h"
+#endif
+#if defined(USE_SSE42) && defined(USE_FMA3)
+# include "mozilla/SSE.h"
+# include "AudioNodeEngineGeneric.h"
+#endif
+#include "AudioBlock.h"
+#include "Tracing.h"
+
+namespace mozilla {
+
+already_AddRefed<ThreadSharedFloatArrayBufferList>
+ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount, size_t aLength,
+ const mozilla::fallible_t&) {
+ RefPtr<ThreadSharedFloatArrayBufferList> buffer =
+ new ThreadSharedFloatArrayBufferList(aChannelCount);
+
+ for (uint32_t i = 0; i < aChannelCount; ++i) {
+ float* channelData = js_pod_malloc<float>(aLength);
+ if (!channelData) {
+ return nullptr;
+ }
+
+ buffer->SetData(i, channelData, js_free, channelData);
+ }
+
+ return buffer.forget();
+}
+
+void WriteZeroesToAudioBlock(AudioBlock* aChunk, uint32_t aStart,
+ uint32_t aLength) {
+ MOZ_ASSERT(aStart + aLength <= WEBAUDIO_BLOCK_SIZE);
+ MOZ_ASSERT(!aChunk->IsNull(), "You should pass a non-null chunk");
+ if (aLength == 0) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < aChunk->ChannelCount(); ++i) {
+ PodZero(aChunk->ChannelFloatsForWrite(i) + aStart, aLength);
+ }
+}
+
+void AudioBufferCopyWithScale(const float* aInput, float aScale, float* aOutput,
+ uint32_t aSize) {
+ if (aScale == 1.0f) {
+ PodCopy(aOutput, aInput, aSize);
+ } else {
+ for (uint32_t i = 0; i < aSize; ++i) {
+ aOutput[i] = aInput[i] * aScale;
+ }
+ }
+}
+
+void AudioBufferAddWithScale(const float* aInput, float aScale, float* aOutput,
+ uint32_t aSize) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBufferAddWithScale(aInput, aScale, aOutput,
+ aSize);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+# if defined(USE_SSE42) && defined(USE_FMA3)
+ if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
+ Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBufferAddWithScale(
+ aInput, aScale, aOutput, aSize);
+ } else
+# endif
+ {
+ Engine<xsimd::sse2>::AudioBufferAddWithScale(aInput, aScale, aOutput,
+ aSize);
+ }
+ return;
+ }
+#endif
+
+ if (aScale == 1.0f) {
+ for (uint32_t i = 0; i < aSize; ++i) {
+ aOutput[i] += aInput[i];
+ }
+ } else {
+ for (uint32_t i = 0; i < aSize; ++i) {
+ aOutput[i] += aInput[i] * aScale;
+ }
+ }
+}
+
+void AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
+ float aScale,
+ float aOutput[WEBAUDIO_BLOCK_SIZE]) {
+ AudioBufferAddWithScale(aInput, aScale, aOutput, WEBAUDIO_BLOCK_SIZE);
+}
+
+void AudioBlockCopyChannelWithScale(const float* aInput, float aScale,
+ float* aOutput) {
+ if (aScale == 1.0f) {
+ memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE * sizeof(float));
+ } else {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBlockCopyChannelWithScale(aInput, aScale,
+ aOutput);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ Engine<xsimd::sse2>::AudioBlockCopyChannelWithScale(aInput, aScale,
+ aOutput);
+ return;
+ }
+#endif
+
+ for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
+ aOutput[i] = aInput[i] * aScale;
+ }
+ }
+}
+
+void BufferComplexMultiply(const float* aInput, const float* aScale,
+ float* aOutput, uint32_t aSize) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::BufferComplexMultiply(aInput, aScale, aOutput, aSize);
+ return;
+ }
+#endif
+#ifdef USE_SSE2
+ if (mozilla::supports_sse()) {
+# if defined(USE_SSE42) && defined(USE_FMA3)
+ if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
+ Engine<xsimd::fma3<xsimd::sse4_2>>::BufferComplexMultiply(aInput, aScale,
+ aOutput, aSize);
+ } else
+# endif
+ {
+ Engine<xsimd::sse2>::BufferComplexMultiply(aInput, aScale, aOutput,
+ aSize);
+ }
+ return;
+ }
+#endif
+
+ for (uint32_t i = 0; i < aSize * 2; i += 2) {
+ float real1 = aInput[i];
+ float imag1 = aInput[i + 1];
+ float real2 = aScale[i];
+ float imag2 = aScale[i + 1];
+ float realResult = real1 * real2 - imag1 * imag2;
+ float imagResult = real1 * imag2 + imag1 * real2;
+ aOutput[i] = realResult;
+ aOutput[i + 1] = imagResult;
+ }
+}
+
+float AudioBufferPeakValue(const float* aInput, uint32_t aSize) {
+ float max = 0.0f;
+ for (uint32_t i = 0; i < aSize; i++) {
+ float mag = fabs(aInput[i]);
+ if (mag > max) {
+ max = mag;
+ }
+ }
+ return max;
+}
+
+void AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
+ const float aScale[WEBAUDIO_BLOCK_SIZE],
+ float aOutput[WEBAUDIO_BLOCK_SIZE]) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBlockCopyChannelWithScale(aInput, aScale,
+ aOutput);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ Engine<xsimd::sse2>::AudioBlockCopyChannelWithScale(aInput, aScale,
+ aOutput);
+ return;
+ }
+#endif
+
+ for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
+ aOutput[i] = aInput[i] * aScale[i];
+ }
+}
+
+void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE], float aScale) {
+ AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE);
+}
+
+void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
+ float aScale[WEBAUDIO_BLOCK_SIZE]) {
+ AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE);
+}
+
+void AudioBufferInPlaceScale(float* aBlock, float aScale, uint32_t aSize) {
+ if (aScale == 1.0f) {
+ return;
+ }
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ Engine<xsimd::sse2>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
+ return;
+ }
+#endif
+
+ for (uint32_t i = 0; i < aSize; ++i) {
+ *aBlock++ *= aScale;
+ }
+}
+
+void AudioBufferInPlaceScale(float* aBlock, float* aScale, uint32_t aSize) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ Engine<xsimd::sse2>::AudioBufferInPlaceScale(aBlock, aScale, aSize);
+ return;
+ }
+#endif
+
+ for (uint32_t i = 0; i < aSize; ++i) {
+ *aBlock++ *= *aScale++;
+ }
+}
+
+void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
+ float aGainL[WEBAUDIO_BLOCK_SIZE],
+ float aGainR[WEBAUDIO_BLOCK_SIZE],
+ float aOutputL[WEBAUDIO_BLOCK_SIZE],
+ float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
+ AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL);
+ AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR);
+}
+
+void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
+ float aGainL, float aGainR,
+ float aOutputL[WEBAUDIO_BLOCK_SIZE],
+ float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
+ AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL);
+ AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR);
+}
+
+void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
+ const float aInputR[WEBAUDIO_BLOCK_SIZE],
+ float aGainL, float aGainR, bool aIsOnTheLeft,
+ float aOutputL[WEBAUDIO_BLOCK_SIZE],
+ float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBlockPanStereoToStereo(
+ aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+# if defined(USE_SSE42) && defined(USE_FMA3)
+ if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
+ Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBlockPanStereoToStereo(
+ aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
+ } else
+# endif
+ {
+ Engine<xsimd::sse2>::AudioBlockPanStereoToStereo(
+ aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
+ }
+ return;
+ }
+#endif
+
+ uint32_t i;
+
+ if (aIsOnTheLeft) {
+ for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
+ aOutputL[i] = aInputL[i] + aInputR[i] * aGainL;
+ aOutputR[i] = aInputR[i] * aGainR;
+ }
+ } else {
+ for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
+ aOutputL[i] = aInputL[i] * aGainL;
+ aOutputR[i] = aInputR[i] + aInputL[i] * aGainR;
+ }
+ }
+}
+
+void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
+ const float aInputR[WEBAUDIO_BLOCK_SIZE],
+ const float aGainL[WEBAUDIO_BLOCK_SIZE],
+ const float aGainR[WEBAUDIO_BLOCK_SIZE],
+ const bool aIsOnTheLeft[WEBAUDIO_BLOCK_SIZE],
+ float aOutputL[WEBAUDIO_BLOCK_SIZE],
+ float aOutputR[WEBAUDIO_BLOCK_SIZE]) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ Engine<xsimd::neon>::AudioBlockPanStereoToStereo(
+ aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
+ return;
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+# if defined(USE_SSE42) && defined(USE_FMA3)
+ if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
+ Engine<xsimd::fma3<xsimd::sse2>>::AudioBlockPanStereoToStereo(
+ aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
+ } else
+# endif
+ {
+ Engine<xsimd::sse2>::AudioBlockPanStereoToStereo(
+ aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR);
+ }
+ return;
+ }
+#endif
+
+ uint32_t i;
+ for (i = 0; i < WEBAUDIO_BLOCK_SIZE; i++) {
+ if (aIsOnTheLeft[i]) {
+ aOutputL[i] = aInputL[i] + aInputR[i] * aGainL[i];
+ aOutputR[i] = aInputR[i] * aGainR[i];
+ } else {
+ aOutputL[i] = aInputL[i] * aGainL[i];
+ aOutputR[i] = aInputR[i] + aInputL[i] * aGainR[i];
+ }
+ }
+}
+
+float AudioBufferSumOfSquares(const float* aInput, uint32_t aLength) {
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) {
+ return Engine<xsimd::neon>::AudioBufferSumOfSquares(aInput, aLength);
+ }
+#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse()) {
+# if defined(USE_SSE42) && defined(USE_FMA3)
+ if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) {
+ return Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBufferSumOfSquares(
+ aInput, aLength);
+ } else
+# endif
+ {
+ return Engine<xsimd::sse2>::AudioBufferSumOfSquares(aInput, aLength);
+ }
+ }
+#endif
+
+ float sum = 0.f;
+ while (aLength--) {
+ sum += *aInput * *aInput;
+ ++aInput;
+ }
+ return sum;
+}
+
+void NaNToZeroInPlace(float* aSamples, size_t aCount) {
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ Engine<xsimd::sse2>::NaNToZeroInPlace(aSamples, aCount);
+ return;
+ }
+#endif
+ for (size_t i = 0; i < aCount; i++) {
+ if (aSamples[i] != aSamples[i]) {
+ aSamples[i] = 0.0;
+ }
+ }
+}
+
+AudioNodeEngine::AudioNodeEngine(dom::AudioNode* aNode)
+ : mNode(aNode),
+ mNodeType(aNode ? aNode->NodeType() : nullptr),
+ mInputCount(aNode ? aNode->NumberOfInputs() : 1),
+ mOutputCount(aNode ? aNode->NumberOfOutputs() : 0) {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_COUNT_CTOR(AudioNodeEngine);
+}
+
+void AudioNodeEngine::ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom,
+ const AudioBlock& aInput,
+ AudioBlock* aOutput, bool* aFinished) {
+ MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
+ TRACE("AudioNodeEngine::ProcessBlock");
+ *aOutput = aInput;
+}
+
+void AudioNodeEngine::ProcessBlocksOnPorts(AudioNodeTrack* aTrack,
+ GraphTime aFrom,
+ Span<const AudioBlock> aInput,
+ Span<AudioBlock> aOutput,
+ bool* aFinished) {
+ MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1);
+ TRACE("AudioNodeEngine::ProcessBlocksOnPorts");
+ // Only produce one output port, and drop all other input ports.
+ aOutput[0] = aInput[0];
+}
+
+} // namespace mozilla