mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 875277 - Part 2: Implement WaveShaperNode.oversample - speex. r=ehsan
This commit is contained in:
parent
78371426cf
commit
dee2ecf218
@ -10,6 +10,7 @@
|
|||||||
#include "AudioNodeEngine.h"
|
#include "AudioNodeEngine.h"
|
||||||
#include "AudioNodeStream.h"
|
#include "AudioNodeStream.h"
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
|
#include "speex/speex_resampler.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -36,6 +37,121 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
|||||||
NS_IMPL_ADDREF_INHERITED(WaveShaperNode, AudioNode)
|
NS_IMPL_ADDREF_INHERITED(WaveShaperNode, AudioNode)
|
||||||
NS_IMPL_RELEASE_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
|
class WaveShaperNodeEngine : public AudioNodeEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -103,16 +219,24 @@ public:
|
|||||||
for (uint32_t i = 0; i < channelCount; ++i) {
|
for (uint32_t i = 0; i < channelCount; ++i) {
|
||||||
const float* inputBuffer = static_cast<const float*>(aInput.mChannelData[i]);
|
const float* inputBuffer = static_cast<const float*>(aInput.mChannelData[i]);
|
||||||
float* outputBuffer = const_cast<float*> (static_cast<const float*>(aOutput->mChannelData[i]));
|
float* outputBuffer = const_cast<float*> (static_cast<const float*>(aOutput->mChannelData[i]));
|
||||||
|
float* sampleBuffer;
|
||||||
|
|
||||||
switch (mType) {
|
switch (mType) {
|
||||||
case OverSampleType::None:
|
case OverSampleType::None:
|
||||||
|
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::None);
|
||||||
ProcessCurve<1>(inputBuffer, outputBuffer);
|
ProcessCurve<1>(inputBuffer, outputBuffer);
|
||||||
break;
|
break;
|
||||||
case OverSampleType::_2x:
|
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;
|
break;
|
||||||
case OverSampleType::_4x:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
NS_NOTREACHED("We should never reach here");
|
NS_NOTREACHED("We should never reach here");
|
||||||
@ -123,6 +247,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
nsTArray<float> mCurve;
|
nsTArray<float> mCurve;
|
||||||
OverSampleType mType;
|
OverSampleType mType;
|
||||||
|
Resampler mResampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
WaveShaperNode::WaveShaperNode(AudioContext* aContext)
|
WaveShaperNode::WaveShaperNode(AudioContext* aContext)
|
||||||
|
Loading…
Reference in New Issue
Block a user