michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "AudioNodeEngine.h" michael@0: #ifdef BUILD_ARM_NEON michael@0: #include "mozilla/arm.h" michael@0: #include "AudioNodeEngineNEON.h" michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: void michael@0: AllocateAudioBlock(uint32_t aChannelCount, AudioChunk* aChunk) michael@0: { michael@0: CheckedInt size = WEBAUDIO_BLOCK_SIZE; michael@0: size *= aChannelCount; michael@0: size *= sizeof(float); michael@0: if (!size.isValid()) { michael@0: MOZ_CRASH(); michael@0: } michael@0: // XXX for SIMD purposes we should do something here to make sure the michael@0: // channel buffers are 16-byte aligned. michael@0: nsRefPtr buffer = SharedBuffer::Create(size.value()); michael@0: aChunk->mDuration = WEBAUDIO_BLOCK_SIZE; michael@0: aChunk->mChannelData.SetLength(aChannelCount); michael@0: float* data = static_cast(buffer->Data()); michael@0: for (uint32_t i = 0; i < aChannelCount; ++i) { michael@0: aChunk->mChannelData[i] = data + i*WEBAUDIO_BLOCK_SIZE; michael@0: } michael@0: aChunk->mBuffer = buffer.forget(); michael@0: aChunk->mVolume = 1.0f; michael@0: aChunk->mBufferFormat = AUDIO_FORMAT_FLOAT32; michael@0: } michael@0: michael@0: void michael@0: WriteZeroesToAudioBlock(AudioChunk* aChunk, uint32_t aStart, uint32_t aLength) michael@0: { michael@0: MOZ_ASSERT(aStart + aLength <= WEBAUDIO_BLOCK_SIZE); michael@0: MOZ_ASSERT(!aChunk->IsNull(), "You should pass a non-null chunk"); michael@0: if (aLength == 0) michael@0: return; michael@0: for (uint32_t i = 0; i < aChunk->mChannelData.Length(); ++i) { michael@0: memset(static_cast(const_cast(aChunk->mChannelData[i])) + aStart, michael@0: 0, aLength*sizeof(float)); michael@0: } michael@0: } michael@0: michael@0: void AudioBufferCopyWithScale(const float* aInput, michael@0: float aScale, michael@0: float* aOutput, michael@0: uint32_t aSize) michael@0: { michael@0: if (aScale == 1.0f) { michael@0: PodCopy(aOutput, aInput, aSize); michael@0: } else { michael@0: for (uint32_t i = 0; i < aSize; ++i) { michael@0: aOutput[i] = aInput[i]*aScale; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void AudioBufferAddWithScale(const float* aInput, michael@0: float aScale, michael@0: float* aOutput, michael@0: uint32_t aSize) michael@0: { michael@0: #ifdef BUILD_ARM_NEON michael@0: if (mozilla::supports_neon()) { michael@0: AudioBufferAddWithScale_NEON(aInput, aScale, aOutput, aSize); michael@0: return; michael@0: } michael@0: #endif michael@0: if (aScale == 1.0f) { michael@0: for (uint32_t i = 0; i < aSize; ++i) { michael@0: aOutput[i] += aInput[i]; michael@0: } michael@0: } else { michael@0: for (uint32_t i = 0; i < aSize; ++i) { michael@0: aOutput[i] += aInput[i]*aScale; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE], michael@0: float aScale, michael@0: float aOutput[WEBAUDIO_BLOCK_SIZE]) michael@0: { michael@0: AudioBufferAddWithScale(aInput, aScale, aOutput, WEBAUDIO_BLOCK_SIZE); michael@0: } michael@0: michael@0: void michael@0: AudioBlockCopyChannelWithScale(const float* aInput, michael@0: float aScale, michael@0: float* aOutput) michael@0: { michael@0: if (aScale == 1.0f) { michael@0: memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE*sizeof(float)); michael@0: } else { michael@0: #ifdef BUILD_ARM_NEON michael@0: if (mozilla::supports_neon()) { michael@0: AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput); michael@0: return; michael@0: } michael@0: #endif michael@0: for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { michael@0: aOutput[i] = aInput[i]*aScale; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: BufferComplexMultiply(const float* aInput, michael@0: const float* aScale, michael@0: float* aOutput, michael@0: uint32_t aSize) michael@0: { michael@0: for (uint32_t i = 0; i < aSize * 2; i += 2) { michael@0: float real1 = aInput[i]; michael@0: float imag1 = aInput[i + 1]; michael@0: float real2 = aScale[i]; michael@0: float imag2 = aScale[i + 1]; michael@0: float realResult = real1 * real2 - imag1 * imag2; michael@0: float imagResult = real1 * imag2 + imag1 * real2; michael@0: aOutput[i] = realResult; michael@0: aOutput[i + 1] = imagResult; michael@0: } michael@0: } michael@0: michael@0: float michael@0: AudioBufferPeakValue(const float *aInput, uint32_t aSize) michael@0: { michael@0: float max = 0.0f; michael@0: for (uint32_t i = 0; i < aSize; i++) { michael@0: float mag = fabs(aInput[i]); michael@0: if (mag > max) { michael@0: max = mag; michael@0: } michael@0: } michael@0: return max; michael@0: } michael@0: michael@0: void michael@0: AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE], michael@0: const float aScale[WEBAUDIO_BLOCK_SIZE], michael@0: float aOutput[WEBAUDIO_BLOCK_SIZE]) michael@0: { michael@0: #ifdef BUILD_ARM_NEON michael@0: if (mozilla::supports_neon()) { michael@0: AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput); michael@0: return; michael@0: } michael@0: #endif michael@0: for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { michael@0: aOutput[i] = aInput[i]*aScale[i]; michael@0: } michael@0: } michael@0: michael@0: void michael@0: AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE], michael@0: float aScale) michael@0: { michael@0: AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE); michael@0: } michael@0: michael@0: void michael@0: AudioBufferInPlaceScale(float* aBlock, michael@0: float aScale, michael@0: uint32_t aSize) michael@0: { michael@0: if (aScale == 1.0f) { michael@0: return; michael@0: } michael@0: #ifdef BUILD_ARM_NEON michael@0: if (mozilla::supports_neon()) { michael@0: AudioBufferInPlaceScale_NEON(aBlock, aScale, aSize); michael@0: return; michael@0: } michael@0: #endif michael@0: for (uint32_t i = 0; i < aSize; ++i) { michael@0: *aBlock++ *= aScale; michael@0: } michael@0: } michael@0: michael@0: void michael@0: AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE], michael@0: float aGainL, float aGainR, michael@0: float aOutputL[WEBAUDIO_BLOCK_SIZE], michael@0: float aOutputR[WEBAUDIO_BLOCK_SIZE]) michael@0: { michael@0: AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL); michael@0: AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR); michael@0: } michael@0: michael@0: void michael@0: AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE], michael@0: const float aInputR[WEBAUDIO_BLOCK_SIZE], michael@0: float aGainL, float aGainR, bool aIsOnTheLeft, michael@0: float aOutputL[WEBAUDIO_BLOCK_SIZE], michael@0: float aOutputR[WEBAUDIO_BLOCK_SIZE]) michael@0: { michael@0: #ifdef BUILD_ARM_NEON michael@0: if (mozilla::supports_neon()) { michael@0: AudioBlockPanStereoToStereo_NEON(aInputL, aInputR, michael@0: aGainL, aGainR, aIsOnTheLeft, michael@0: aOutputL, aOutputR); michael@0: return; michael@0: } michael@0: #endif michael@0: michael@0: uint32_t i; michael@0: michael@0: if (aIsOnTheLeft) { michael@0: for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { michael@0: *aOutputL++ = *aInputL++ + *aInputR * aGainL; michael@0: *aOutputR++ = *aInputR++ * aGainR; michael@0: } michael@0: } else { michael@0: for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { michael@0: *aOutputL++ = *aInputL * aGainL; michael@0: *aOutputR++ = *aInputR++ + *aInputL++ * aGainR; michael@0: } michael@0: } michael@0: } michael@0: michael@0: float michael@0: AudioBufferSumOfSquares(const float* aInput, uint32_t aLength) michael@0: { michael@0: float sum = 0.0f; michael@0: while (aLength--) { michael@0: sum += *aInput * *aInput; michael@0: ++aInput; michael@0: } michael@0: return sum; michael@0: } michael@0: michael@0: }