зеркало из https://github.com/mozilla/gecko-dev.git
415 строки
11 KiB
C++
415 строки
11 KiB
C++
/* -*- 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 BUILD_ARM_NEON
|
|
#include "mozilla/arm.h"
|
|
#include "AudioNodeEngineNEON.h"
|
|
#endif
|
|
#ifdef USE_SSE2
|
|
#include "mozilla/SSE.h"
|
|
#include "AlignmentUtils.h"
|
|
#include "AudioNodeEngineSSE2.h"
|
|
#endif
|
|
|
|
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 BUILD_ARM_NEON
|
|
if (mozilla::supports_neon()) {
|
|
AudioBufferAddWithScale_NEON(aInput, aScale, aOutput, aSize);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SSE2
|
|
if (mozilla::supports_sse2()) {
|
|
if (aScale == 1.0f) {
|
|
while (aSize && (!IS_ALIGNED16(aInput) || !IS_ALIGNED16(aOutput))) {
|
|
*aOutput += *aInput;
|
|
++aOutput;
|
|
++aInput;
|
|
--aSize;
|
|
}
|
|
} else {
|
|
while (aSize && (!IS_ALIGNED16(aInput) || !IS_ALIGNED16(aOutput))) {
|
|
*aOutput += *aInput*aScale;
|
|
++aOutput;
|
|
++aInput;
|
|
--aSize;
|
|
}
|
|
}
|
|
|
|
// we need to round aSize down to the nearest multiple of 16
|
|
uint32_t alignedSize = aSize & ~0x0F;
|
|
if (alignedSize > 0) {
|
|
AudioBufferAddWithScale_SSE(aInput, aScale, aOutput, alignedSize);
|
|
|
|
// adjust parameters for use with scalar operations below
|
|
aInput += alignedSize;
|
|
aOutput += alignedSize;
|
|
aSize -= alignedSize;
|
|
}
|
|
}
|
|
#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 BUILD_ARM_NEON
|
|
if (mozilla::supports_neon()) {
|
|
AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SSE2
|
|
if (mozilla::supports_sse2()) {
|
|
AudioBlockCopyChannelWithScale_SSE(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_SSE2
|
|
if (mozilla::supports_sse()) {
|
|
BufferComplexMultiply_SSE(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 BUILD_ARM_NEON
|
|
if (mozilla::supports_neon()) {
|
|
AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SSE2
|
|
if (mozilla::supports_sse2()) {
|
|
AudioBlockCopyChannelWithScale_SSE(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
|
|
AudioBufferInPlaceScale(float* aBlock,
|
|
float aScale,
|
|
uint32_t aSize)
|
|
{
|
|
if (aScale == 1.0f) {
|
|
return;
|
|
}
|
|
#ifdef BUILD_ARM_NEON
|
|
if (mozilla::supports_neon()) {
|
|
AudioBufferInPlaceScale_NEON(aBlock, aScale, aSize);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SSE2
|
|
if (mozilla::supports_sse2()) {
|
|
AudioBufferInPlaceScale_SSE(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 BUILD_ARM_NEON
|
|
if (mozilla::supports_neon()) {
|
|
AudioBlockPanStereoToStereo_NEON(aInputL, aInputR,
|
|
aGainL, aGainR, aIsOnTheLeft,
|
|
aOutputL, aOutputR);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SSE2
|
|
if (mozilla::supports_sse2()) {
|
|
AudioBlockPanStereoToStereo_SSE(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],
|
|
float aGainL[WEBAUDIO_BLOCK_SIZE],
|
|
float aGainR[WEBAUDIO_BLOCK_SIZE],
|
|
bool aIsOnTheLeft[WEBAUDIO_BLOCK_SIZE],
|
|
float aOutputL[WEBAUDIO_BLOCK_SIZE],
|
|
float aOutputR[WEBAUDIO_BLOCK_SIZE])
|
|
{
|
|
#ifdef BUILD_ARM_NEON
|
|
if (mozilla::supports_neon()) {
|
|
AudioBlockPanStereoToStereo_NEON(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)
|
|
{
|
|
float sum = 0.0f;
|
|
|
|
#ifdef USE_SSE2
|
|
if (mozilla::supports_sse()) {
|
|
const float* alignedInput = ALIGNED16(aInput);
|
|
float vLength = (aLength >> 4) << 4;
|
|
|
|
// use scalar operations for any unaligned data at the beginning
|
|
while (aInput != alignedInput) {
|
|
sum += *aInput * *aInput;
|
|
++aInput;
|
|
}
|
|
|
|
sum += AudioBufferSumOfSquares_SSE(alignedInput, vLength);
|
|
|
|
// adjust aInput and aLength to use scalar operations for any
|
|
// remaining values
|
|
aInput = alignedInput + 1;
|
|
aLength -= vLength;
|
|
}
|
|
#endif
|
|
|
|
while (aLength--) {
|
|
sum += *aInput * *aInput;
|
|
++aInput;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
AudioNodeEngine::AudioNodeEngine(dom::AudioNode* aNode)
|
|
: mNode(aNode)
|
|
, mNodeType(aNode ? aNode->NodeType() : nullptr)
|
|
, mInputCount(aNode ? aNode->NumberOfInputs() : 1)
|
|
, mOutputCount(aNode ? aNode->NumberOfOutputs() : 0)
|
|
, mAbstractMainThread(
|
|
aNode ? aNode->AbstractMainThread() : AbstractThread::MainThread())
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_COUNT_CTOR(AudioNodeEngine);
|
|
}
|
|
|
|
void
|
|
AudioNodeEngine::ProcessBlock(AudioNodeStream* aStream,
|
|
GraphTime aFrom,
|
|
const AudioBlock& aInput,
|
|
AudioBlock* aOutput,
|
|
bool* aFinished)
|
|
{
|
|
MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
|
|
*aOutput = aInput;
|
|
}
|
|
|
|
void
|
|
AudioNodeEngine::ProcessBlocksOnPorts(AudioNodeStream* aStream,
|
|
const OutputChunks& aInput,
|
|
OutputChunks& aOutput,
|
|
bool* aFinished)
|
|
{
|
|
MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1);
|
|
// Only produce one output port, and drop all other input ports.
|
|
aOutput[0] = aInput[0];
|
|
}
|
|
|
|
} // namespace mozilla
|