Bug 875277 - Part 2: Implement WaveShaperNode.oversample - speex. r=ehsan

This commit is contained in:
JW Wang 2013-08-06 14:11:32 +08:00
parent 6d8256114d
commit ce885c443c

View File

@ -10,6 +10,7 @@
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "mozilla/PodOperations.h"
#include "speex/speex_resampler.h"
namespace mozilla {
namespace dom {
@ -36,6 +37,121 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(WaveShaperNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(WaveShaperNode, AudioNode)
static uint32_t ValueOf(OverSampleType aType)
{
switch (aType) {
case OverSampleType::None: return 1;
case OverSampleType::_2x: return 2;
case OverSampleType::_4x: return 4;
default:
NS_NOTREACHED("We should never reach here");
return 1;
}
}
class Resampler
{
public:
Resampler()
: mType(OverSampleType::None)
, mUpSampler(nullptr)
, mDownSampler(nullptr)
, mChannels(0)
, mSampleRate(0)
{
}
~Resampler()
{
Destroy();
}
void Reset(uint32_t aChannels, TrackRate aSampleRate, OverSampleType aType)
{
if (aChannels == mChannels &&
aSampleRate == mSampleRate &&
aType == mType) {
return;
}
mChannels = aChannels;
mSampleRate = aSampleRate;
mType = aType;
Destroy();
if (aType == OverSampleType::None) {
mBuffer.Clear();
return;
}
mUpSampler = speex_resampler_init(aChannels,
aSampleRate,
aSampleRate * ValueOf(aType),
SPEEX_RESAMPLER_QUALITY_DEFAULT,
nullptr);
mDownSampler = speex_resampler_init(aChannels,
aSampleRate * ValueOf(aType),
aSampleRate,
SPEEX_RESAMPLER_QUALITY_DEFAULT,
nullptr);
mBuffer.SetLength(WEBAUDIO_BLOCK_SIZE*ValueOf(aType));
}
float* UpSample(uint32_t aChannel, const float* aInputData, uint32_t aBlocks)
{
uint32_t inSamples = WEBAUDIO_BLOCK_SIZE;
uint32_t outSamples = WEBAUDIO_BLOCK_SIZE*aBlocks;
float* outputData = mBuffer.Elements();
MOZ_ASSERT(mBuffer.Length() == outSamples);
speex_resampler_process_float(mUpSampler, aChannel,
aInputData, &inSamples,
outputData, &outSamples);
MOZ_ASSERT(inSamples == WEBAUDIO_BLOCK_SIZE && outSamples == WEBAUDIO_BLOCK_SIZE*aBlocks);
return outputData;
}
void DownSample(uint32_t aChannel, float* aOutputData, uint32_t aBlocks)
{
uint32_t inSamples = WEBAUDIO_BLOCK_SIZE*aBlocks;
uint32_t outSamples = WEBAUDIO_BLOCK_SIZE;
const float* inputData = mBuffer.Elements();
MOZ_ASSERT(mBuffer.Length() == inSamples);
speex_resampler_process_float(mDownSampler, aChannel,
inputData, &inSamples,
aOutputData, &outSamples);
MOZ_ASSERT(inSamples == WEBAUDIO_BLOCK_SIZE*aBlocks && outSamples == WEBAUDIO_BLOCK_SIZE);
}
private:
void Destroy()
{
if (mUpSampler) {
speex_resampler_destroy(mUpSampler);
mUpSampler = nullptr;
}
if (mDownSampler) {
speex_resampler_destroy(mDownSampler);
mDownSampler = nullptr;
}
}
private:
OverSampleType mType;
SpeexResamplerState* mUpSampler;
SpeexResamplerState* mDownSampler;
uint32_t mChannels;
TrackRate mSampleRate;
nsTArray<float> mBuffer;
};
class WaveShaperNodeEngine : public AudioNodeEngine
{
public:
@ -103,16 +219,24 @@ public:
for (uint32_t i = 0; i < channelCount; ++i) {
const float* inputBuffer = static_cast<const float*>(aInput.mChannelData[i]);
float* outputBuffer = const_cast<float*> (static_cast<const float*>(aOutput->mChannelData[i]));
float* sampleBuffer;
switch (mType) {
case OverSampleType::None:
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::None);
ProcessCurve<1>(inputBuffer, outputBuffer);
break;
case OverSampleType::_2x:
/* TODO: to be implemented */
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::_2x);
sampleBuffer = mResampler.UpSample(i, inputBuffer, 2);
ProcessCurve<2>(sampleBuffer, sampleBuffer);
mResampler.DownSample(i, outputBuffer, 2);
break;
case OverSampleType::_4x:
/* TODO: to be implemented */
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::_4x);
sampleBuffer = mResampler.UpSample(i, inputBuffer, 4);
ProcessCurve<4>(sampleBuffer, sampleBuffer);
mResampler.DownSample(i, outputBuffer, 4);
break;
default:
NS_NOTREACHED("We should never reach here");
@ -123,6 +247,7 @@ public:
private:
nsTArray<float> mCurve;
OverSampleType mType;
Resampler mResampler;
};
WaveShaperNode::WaveShaperNode(AudioContext* aContext)