Use proper inheritence for the effect state objects

This commit is contained in:
Chris Robinson
2018-11-19 22:34:26 -08:00
parent 6ac84c7a5f
commit 8472a9d916
18 changed files with 645 additions and 941 deletions
+9 -9
View File
@@ -2256,11 +2256,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(context->DefaultSlot)
{
ALeffectslot *slot = context->DefaultSlot;
ALeffectState *state = slot->Effect.State;
EffectState *state = slot->Effect.State;
state->OutBuffer = device->Dry.Buffer;
state->OutChannels = device->Dry.NumChannels;
if(V(state,deviceUpdate)(device) == AL_FALSE)
state->mOutBuffer = device->Dry.Buffer;
state->mOutChannels = device->Dry.NumChannels;
if(state->deviceUpdate(device) == AL_FALSE)
update_failed = AL_TRUE;
else
UpdateEffectSlotProps(slot, context);
@@ -2270,11 +2270,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
almtx_lock(&context->EffectSlotLock);
for(auto &slot : context->EffectSlotList)
{
ALeffectState *state = slot->Effect.State;
EffectState *state = slot->Effect.State;
state->OutBuffer = device->Dry.Buffer;
state->OutChannels = device->Dry.NumChannels;
if(V(state,deviceUpdate)(device) == AL_FALSE)
state->mOutBuffer = device->Dry.Buffer;
state->mOutChannels = device->Dry.NumChannels;
if(state->deviceUpdate(device) == AL_FALSE)
update_failed = AL_TRUE;
else
UpdateEffectSlotProps(slot, context);
@@ -2603,7 +2603,7 @@ ALCcontext_struct::~ALCcontext_struct()
while(eprops)
{
struct ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)};
if(eprops->State) ALeffectState_DecRef(eprops->State);
if(eprops->State) eprops->State->DecRef();
al_free(eprops);
eprops = next;
++count;
+9 -9
View File
@@ -381,7 +381,7 @@ static bool CalcListenerParams(ALCcontext *Context)
static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force)
{
struct ALeffectslotProps *props;
ALeffectState *state;
EffectState *state;
props = slot->Update.exchange(nullptr, std::memory_order_acq_rel);
if(!props && !force) return false;
@@ -419,8 +419,8 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f
* count safely to remove it from the update object (it can't reach
* 0 refs since the current params also hold a reference).
*/
DecrementRef(&state->Ref);
props->State = NULL;
DecrementRef(&state->mRef);
props->State = nullptr;
}
else
{
@@ -428,7 +428,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f
* event.
*/
AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState);
evt.u.EffectState = slot->Params.EffectState;
evt.u.mEffectState = slot->Params.EffectState;
slot->Params.EffectState = state;
props->State = NULL;
@@ -442,7 +442,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f
* eventually be cleaned up sometime later (not ideal, but
* better than blocking or leaking).
*/
props->State = evt.u.EffectState;
props->State = evt.u.mEffectState;
}
}
@@ -451,7 +451,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f
else
state = slot->Params.EffectState;
V(state,update)(context, slot, &slot->Params.EffectProps);
state->update(context, slot, &slot->Params.EffectProps);
return true;
}
@@ -1749,9 +1749,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
for(i = 0;i < auxslots->count;i++)
{
const ALeffectslot *slot = auxslots->slot[i];
ALeffectState *state = slot->Params.EffectState;
V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer,
state->OutChannels);
EffectState *state = slot->Params.EffectState;
state->process(SamplesToDo, slot->WetBuffer, state->mOutBuffer,
state->mOutChannels);
}
ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed);
+51 -69
View File
@@ -37,7 +37,7 @@
#define MAX_FREQ 2500.0f
#define Q_FACTOR 5.0f
struct ALautowahState final : public ALeffectState {
struct ALautowahState final : public EffectState {
/* Effect parameters */
ALfloat mAttackRate;
ALfloat mReleaseRate;
@@ -66,48 +66,34 @@ struct ALautowahState final : public ALeffectState {
/* Effects buffers */
alignas(16) ALfloat mBufferOut[BUFFERSIZE];
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALautowahState)
};
static ALvoid ALautowahState_Destruct(ALautowahState *state);
static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device);
static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALautowahState)
DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState);
static void ALautowahState_Construct(ALautowahState *state)
{
new (state) ALautowahState{};
ALeffectState_Construct(state);
SET_VTABLE2(ALautowahState, ALeffectState, state);
}
static ALvoid ALautowahState_Destruct(ALautowahState *state)
{
ALeffectState_Destruct(state);
state->~ALautowahState();
}
static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device))
ALboolean ALautowahState::deviceUpdate(ALCdevice *UNUSED(device))
{
/* (Re-)initializing parameters and clear the buffers. */
state->mAttackRate = 1.0f;
state->mReleaseRate = 1.0f;
state->mResonanceGain = 10.0f;
state->mPeakGain = 4.5f;
state->mFreqMinNorm = 4.5e-4f;
state->mBandwidthNorm = 0.05f;
state->mEnvDelay = 0.0f;
mAttackRate = 1.0f;
mReleaseRate = 1.0f;
mResonanceGain = 10.0f;
mPeakGain = 4.5f;
mFreqMinNorm = 4.5e-4f;
mBandwidthNorm = 0.05f;
mEnvDelay = 0.0f;
for(auto &e : state->mEnv)
for(auto &e : mEnv)
{
e.cos_w0 = 0.0f;
e.alpha = 0.0f;
}
for(auto &chan : state->mChans)
for(auto &chan : mChans)
{
std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f);
chan.Filter.z1 = 0.0f;
@@ -117,7 +103,7 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *U
return AL_TRUE;
}
static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat ReleaseTime;
@@ -125,33 +111,33 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con
ReleaseTime = clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f);
state->mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency));
state->mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency));
mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency));
mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency));
/* 0-20dB Resonance Peak gain */
state->mResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f);
state->mPeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN);
state->mFreqMinNorm = MIN_FREQ / device->Frequency;
state->mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency;
mResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f);
mPeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN);
mFreqMinNorm = MIN_FREQ / device->Frequency;
mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency;
state->OutBuffer = device->FOAOut.Buffer;
state->OutChannels = device->FOAOut.NumChannels;
mOutBuffer = device->FOAOut.Buffer;
mOutChannels = device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain,
state->mChans[i].TargetGains);
mChans[i].TargetGains);
}
static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALautowahState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALfloat attack_rate = state->mAttackRate;
const ALfloat release_rate = state->mReleaseRate;
const ALfloat res_gain = state->mResonanceGain;
const ALfloat peak_gain = state->mPeakGain;
const ALfloat freq_min = state->mFreqMinNorm;
const ALfloat bandwidth = state->mBandwidthNorm;
const ALfloat attack_rate = mAttackRate;
const ALfloat release_rate = mReleaseRate;
const ALfloat res_gain = mResonanceGain;
const ALfloat peak_gain = mPeakGain;
const ALfloat freq_min = mFreqMinNorm;
const ALfloat bandwidth = mBandwidthNorm;
ALfloat env_delay;
ALsizei c, i;
env_delay = state->mEnvDelay;
env_delay = mEnvDelay;
for(i = 0;i < SamplesToDo;i++)
{
ALfloat w0, sample, a;
@@ -165,10 +151,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo,
/* Calculate the cos and alpha components for this sample's filter. */
w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU;
state->mEnv[i].cos_w0 = cosf(w0);
state->mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR);
mEnv[i].cos_w0 = cosf(w0);
mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR);
}
state->mEnvDelay = env_delay;
mEnvDelay = env_delay;
for(c = 0;c < MAX_EFFECT_CHANNELS; c++)
{
@@ -178,13 +164,13 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo,
* envelope. Because the filter changes for each sample, the
* coefficients are transient and don't need to be held.
*/
ALfloat z1 = state->mChans[c].Filter.z1;
ALfloat z2 = state->mChans[c].Filter.z2;
ALfloat z1 = mChans[c].Filter.z1;
ALfloat z2 = mChans[c].Filter.z2;
for(i = 0;i < SamplesToDo;i++)
{
const ALfloat alpha = state->mEnv[i].alpha;
const ALfloat cos_w0 = state->mEnv[i].cos_w0;
const ALfloat alpha = mEnv[i].alpha;
const ALfloat cos_w0 = mEnv[i].cos_w0;
ALfloat input, output;
ALfloat a[3], b[3];
@@ -199,27 +185,23 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo,
output = input*(b[0]/a[0]) + z1;
z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2;
z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]);
state->mBufferOut[i] = output;
mBufferOut[i] = output;
}
state->mChans[c].Filter.z1 = z1;
state->mChans[c].Filter.z2 = z2;
mChans[c].Filter.z1 = z1;
mChans[c].Filter.z2 = z2;
/* Now, mix the processed sound data to the output. */
MixSamples(state->mBufferOut, NumChannels, SamplesOut, state->mChans[c].CurrentGains,
state->mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo);
MixSamples(mBufferOut, NumChannels, SamplesOut, mChans[c].CurrentGains,
mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo);
}
}
struct AutowahStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *AutowahStateFactory::create()
{
ALautowahState *state;
NEW_OBJ0(state, ALautowahState)();
return state;
}
EffectState *AutowahStateFactory::create()
{ return new ALautowahState{}; }
EffectStateFactory *AutowahStateFactory_getFactory(void)
{
+55 -84
View File
@@ -42,7 +42,7 @@ enum WaveForm {
WF_Triangle
};
struct ALchorusState final : public ALeffectState {
struct ALchorusState final : public EffectState {
al::vector<ALfloat,16> mSampleBuffer;
ALsizei mOffset{0};
@@ -62,31 +62,16 @@ struct ALchorusState final : public ALeffectState {
ALint mDelay{0};
ALfloat mDepth{0.0f};
ALfloat mFeedback{0.0f};
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALchorusState)
};
static ALvoid ALchorusState_Destruct(ALchorusState *state);
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device);
static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
static void ALchorusState_Construct(ALchorusState *state)
{
new (state) ALchorusState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALchorusState, ALeffectState, state);
}
static ALvoid ALchorusState_Destruct(ALchorusState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALchorusState();
}
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
ALboolean ALchorusState::deviceUpdate(ALCdevice *Device)
{
const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY);
size_t maxlen;
@@ -94,14 +79,14 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev
maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u);
if(maxlen <= 0) return AL_FALSE;
if(maxlen != state->mSampleBuffer.size())
if(maxlen != mSampleBuffer.size())
{
state->mSampleBuffer.resize(maxlen);
state->mSampleBuffer.shrink_to_fit();
mSampleBuffer.resize(maxlen);
mSampleBuffer.shrink_to_fit();
}
std::fill(state->mSampleBuffer.begin(), state->mSampleBuffer.end(), 0.0f);
for(auto &e : state->mGains)
std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f);
for(auto &e : mGains)
{
std::fill(std::begin(e.Current), std::end(e.Current), 0.0f);
std::fill(std::begin(e.Target), std::end(e.Target), 0.0f);
@@ -110,7 +95,7 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev
return AL_TRUE;
}
static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
void ALchorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS;
const ALCdevice *device = Context->Device;
@@ -122,37 +107,35 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte
switch(props->Chorus.Waveform)
{
case AL_CHORUS_WAVEFORM_TRIANGLE:
state->mWaveform = WF_Triangle;
mWaveform = WF_Triangle;
break;
case AL_CHORUS_WAVEFORM_SINUSOID:
state->mWaveform = WF_Sinusoid;
mWaveform = WF_Sinusoid;
break;
}
/* The LFO depth is scaled to be relative to the sample delay. Clamp the
* delay and depth to allow enough padding for resampling.
*/
state->mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f),
mindelay);
state->mDepth = minf(props->Chorus.Depth * state->mDelay,
(ALfloat)(state->mDelay - mindelay));
mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay);
mDepth = minf(props->Chorus.Depth * mDelay, (ALfloat)(mDelay - mindelay));
state->mFeedback = props->Chorus.Feedback;
mFeedback = props->Chorus.Feedback;
/* Gains for left and right sides */
CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->mGains[0].Target);
ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[0].Target);
CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->mGains[1].Target);
ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[1].Target);
phase = props->Chorus.Phase;
rate = props->Chorus.Rate;
if(!(rate > 0.0f))
{
state->mLfoOffset = 0;
state->mLfoRange = 1;
state->mLfoScale = 0.0f;
state->mLfoDisp = 0;
mLfoOffset = 0;
mLfoRange = 1;
mLfoScale = 0.0f;
mLfoDisp = 0;
}
else
{
@@ -161,22 +144,21 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte
*/
ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180)));
state->mLfoOffset = float2int((ALfloat)state->mLfoOffset/state->mLfoRange*
lfo_range + 0.5f) % lfo_range;
state->mLfoRange = lfo_range;
switch(state->mWaveform)
mLfoOffset = float2int((ALfloat)mLfoOffset/mLfoRange*lfo_range + 0.5f) % lfo_range;
mLfoRange = lfo_range;
switch(mWaveform)
{
case WF_Triangle:
state->mLfoScale = 4.0f / state->mLfoRange;
mLfoScale = 4.0f / mLfoRange;
break;
case WF_Sinusoid:
state->mLfoScale = F_TAU / state->mLfoRange;
mLfoScale = F_TAU / mLfoRange;
break;
}
/* Calculate lfo phase displacement */
if(phase < 0) phase = 360 + phase;
state->mLfoDisp = (state->mLfoRange*phase + 180) / 360;
mLfoDisp = (mLfoRange*phase + 180) / 360;
}
}
@@ -204,14 +186,13 @@ static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsi
}
}
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALchorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALsizei bufmask = state->mSampleBuffer.size()-1;
const ALfloat feedback = state->mFeedback;
const ALsizei avgdelay = (state->mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS;
ALfloat *RESTRICT delaybuf = state->mSampleBuffer.data();
ALsizei offset = state->mOffset;
const ALsizei bufmask = mSampleBuffer.size()-1;
const ALfloat feedback = mFeedback;
const ALsizei avgdelay = (mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS;
ALfloat *RESTRICT delaybuf = mSampleBuffer.data();
ALsizei offset = mOffset;
ALsizei i, c;
ALsizei base;
@@ -221,23 +202,21 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c
ALint moddelays[2][256];
alignas(16) ALfloat temps[2][256];
if(state->mWaveform == WF_Sinusoid)
if(mWaveform == WF_Sinusoid)
{
GetSinusoidDelays(moddelays[0], state->mLfoOffset, state->mLfoRange, state->mLfoScale,
state->mDepth, state->mDelay, todo);
GetSinusoidDelays(moddelays[1], (state->mLfoOffset+state->mLfoDisp)%state->mLfoRange,
state->mLfoRange, state->mLfoScale, state->mDepth, state->mDelay,
GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay,
todo);
GetSinusoidDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale,
mDepth, mDelay, todo);
}
else /*if(state->waveform == WF_Triangle)*/
{
GetTriangleDelays(moddelays[0], state->mLfoOffset, state->mLfoRange, state->mLfoScale,
state->mDepth, state->mDelay, todo);
GetTriangleDelays(moddelays[1], (state->mLfoOffset+state->mLfoDisp)%state->mLfoRange,
state->mLfoRange, state->mLfoScale, state->mDepth, state->mDelay,
GetTriangleDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay,
todo);
GetTriangleDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale,
mDepth, mDelay, todo);
}
state->mLfoOffset = (state->mLfoOffset+todo) % state->mLfoRange;
mLfoOffset = (mLfoOffset+todo) % mLfoRange;
for(i = 0;i < todo;i++)
{
@@ -267,26 +246,22 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c
}
for(c = 0;c < 2;c++)
MixSamples(temps[c], NumChannels, SamplesOut, state->mGains[c].Current,
state->mGains[c].Target, SamplesToDo-base, base, todo);
MixSamples(temps[c], NumChannels, SamplesOut, mGains[c].Current,
mGains[c].Target, SamplesToDo-base, base, todo);
base += todo;
}
state->mOffset = offset;
mOffset = offset;
}
struct ChorusStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *ChorusStateFactory::create()
{
ALchorusState *state;
NEW_OBJ0(state, ALchorusState)();
return state;
}
EffectState *ChorusStateFactory::create()
{ return new ALchorusState{}; }
EffectStateFactory *ChorusStateFactory_getFactory(void)
{
@@ -408,15 +383,11 @@ DEFINE_ALEFFECT_VTABLE(ALchorus);
* the same processing functions, so piggyback flanger on the chorus functions.
*/
struct FlangerStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *FlangerStateFactory::create()
{
ALchorusState *state;
NEW_OBJ0(state, ALchorusState)();
return state;
}
EffectState *FlangerStateFactory::create()
{ return new ALchorusState{}; }
EffectStateFactory *FlangerStateFactory_getFactory(void)
{
+29 -50
View File
@@ -37,7 +37,7 @@
#define RELEASE_TIME 0.2f /* 200ms to drop from max to min */
struct ALcompressorState final : public ALeffectState {
struct ALcompressorState final : public EffectState {
/* Effect gains for each channel */
ALfloat mGain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]{};
@@ -46,31 +46,16 @@ struct ALcompressorState final : public ALeffectState {
ALfloat mAttackMult{1.0f};
ALfloat mReleaseMult{1.0f};
ALfloat mEnvFollower{1.0f};
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALcompressorState)
};
static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
static void ALcompressorState_Construct(ALcompressorState *state)
{
new (state) ALcompressorState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALcompressorState, ALeffectState, state);
}
static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALcompressorState();
}
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
ALboolean ALcompressorState::deviceUpdate(ALCdevice *device)
{
/* Number of samples to do a full attack and release (non-integer sample
* counts are okay).
@@ -81,27 +66,25 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev
/* Calculate per-sample multipliers to attack and release at the desired
* rates.
*/
state->mAttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount);
state->mReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount);
mAttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount);
mReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount);
return AL_TRUE;
}
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALcompressorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALuint i;
state->mEnabled = props->Compressor.OnOff;
mEnabled = props->Compressor.OnOff;
state->OutBuffer = device->FOAOut.Buffer;
state->OutChannels = device->FOAOut.NumChannels;
for(i = 0;i < 4;i++)
ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain,
state->mGain[i]);
mOutBuffer = device->FOAOut.Buffer;
mOutChannels = device->FOAOut.NumChannels;
for(ALsizei i{0};i < 4;i++)
ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, mGain[i]);
}
static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALcompressorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALsizei i, j, k;
ALsizei base;
@@ -110,10 +93,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
{
ALfloat gains[256];
ALsizei td = mini(256, SamplesToDo-base);
ALfloat env = state->mEnvFollower;
ALfloat env = mEnvFollower;
/* Generate the per-sample gains from the signal envelope. */
if(state->mEnabled)
if(mEnabled)
{
for(i = 0;i < td;++i)
{
@@ -123,9 +106,9 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
ALfloat amplitude = clampf(fabsf(SamplesIn[0][base+i]),
AMP_ENVELOPE_MIN, AMP_ENVELOPE_MAX);
if(amplitude > env)
env = minf(env*state->mAttackMult, amplitude);
env = minf(env*mAttackMult, amplitude);
else if(amplitude < env)
env = maxf(env*state->mReleaseMult, amplitude);
env = maxf(env*mReleaseMult, amplitude);
/* Apply the reciprocal of the envelope to normalize the volume
* (compress the dynamic range).
@@ -143,21 +126,21 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
{
ALfloat amplitude = 1.0f;
if(amplitude > env)
env = minf(env*state->mAttackMult, amplitude);
env = minf(env*mAttackMult, amplitude);
else if(amplitude < env)
env = maxf(env*state->mReleaseMult, amplitude);
env = maxf(env*mReleaseMult, amplitude);
gains[i] = 1.0f / env;
}
}
state->mEnvFollower = env;
mEnvFollower = env;
/* Now compress the signal amplitude to output. */
for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
{
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->mGain[j][k];
ALfloat gain = mGain[j][k];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
@@ -172,15 +155,11 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
struct CompressorStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *CompressorStateFactory::create()
{
ALcompressorState *state;
NEW_OBJ0(state, ALcompressorState)();
return state;
}
EffectState *CompressorStateFactory::create()
{ return new ALcompressorState{}; }
EffectStateFactory *CompressorStateFactory_getFactory(void)
{
+27 -46
View File
@@ -31,45 +31,30 @@
#include "alu.h"
struct ALdedicatedState final : public ALeffectState {
struct ALdedicatedState final : public EffectState {
ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS];
ALfloat mTargetGains[MAX_OUTPUT_CHANNELS];
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALdedicatedState)
};
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state);
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device);
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
static void ALdedicatedState_Construct(ALdedicatedState *state)
ALboolean ALdedicatedState::deviceUpdate(ALCdevice *UNUSED(device))
{
new (state) ALdedicatedState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
}
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALdedicatedState();
}
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device))
{
std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f);
std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
return AL_TRUE;
}
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat Gain;
std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f);
std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
Gain = slot->Params.Gain * props->Dedicated.Gain;
if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
@@ -77,9 +62,9 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext
int idx;
if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1)
{
state->OutBuffer = device->RealOut.Buffer;
state->OutChannels = device->RealOut.NumChannels;
state->mTargetGains[idx] = Gain;
mOutBuffer = device->RealOut.Buffer;
mOutChannels = device->RealOut.NumChannels;
mTargetGains[idx] = Gain;
}
}
else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
@@ -89,39 +74,35 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext
int idx{GetChannelIdxByName(&device->RealOut, FrontCenter)};
if(idx != -1)
{
state->OutBuffer = device->RealOut.Buffer;
state->OutChannels = device->RealOut.NumChannels;
state->mTargetGains[idx] = Gain;
mOutBuffer = device->RealOut.Buffer;
mOutChannels = device->RealOut.NumChannels;
mTargetGains[idx] = Gain;
}
else
{
ALfloat coeffs[MAX_AMBI_COEFFS];
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
state->OutBuffer = device->Dry.Buffer;
state->OutChannels = device->Dry.NumChannels;
ComputePanGains(&device->Dry, coeffs, Gain, state->mTargetGains);
mOutBuffer = device->Dry.Buffer;
mOutChannels = device->Dry.NumChannels;
ComputePanGains(&device->Dry, coeffs, Gain, mTargetGains);
}
}
}
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALdedicatedState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->mCurrentGains,
state->mTargetGains, SamplesToDo, 0, SamplesToDo);
MixSamples(SamplesIn[0], NumChannels, SamplesOut, mCurrentGains,
mTargetGains, SamplesToDo, 0, SamplesToDo);
}
struct DedicatedStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *DedicatedStateFactory::create()
{
ALdedicatedState *state;
NEW_OBJ0(state, ALdedicatedState)();
return state;
}
EffectState *DedicatedStateFactory::create()
{ return new ALdedicatedState{}; }
EffectStateFactory *DedicatedStateFactory_getFactory(void)
{
+26 -45
View File
@@ -31,7 +31,7 @@
#include "filters/defs.h"
struct ALdistortionState final : public ALeffectState {
struct ALdistortionState final : public EffectState {
/* Effect gains for each channel */
ALfloat mGain[MAX_OUTPUT_CHANNELS]{};
@@ -41,39 +41,24 @@ struct ALdistortionState final : public ALeffectState {
ALfloat mAttenuation{};
ALfloat mEdgeCoeff{};
ALfloat Buffer[2][BUFFERSIZE]{};
ALfloat mBuffer[2][BUFFERSIZE]{};
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALdistortionState)
};
static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
static void ALdistortionState_Construct(ALdistortionState *state)
ALboolean ALdistortionState::deviceUpdate(ALCdevice *UNUSED(device))
{
new (state) ALdistortionState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALdistortionState, ALeffectState, state);
}
static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALdistortionState();
}
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device))
{
BiquadFilter_clear(&state->mLowpass);
BiquadFilter_clear(&state->mBandpass);
BiquadFilter_clear(&mLowpass);
BiquadFilter_clear(&mBandpass);
return AL_TRUE;
}
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat frequency = (ALfloat)device->Frequency;
@@ -85,7 +70,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex
/* Store waveshaper edge settings. */
edge = sinf(props->Distortion.Edge * (F_PI_2));
edge = minf(edge, 0.99f);
state->mEdgeCoeff = 2.0f * edge / (1.0f-edge);
mEdgeCoeff = 2.0f * edge / (1.0f-edge);
cutoff = props->Distortion.LowpassCutoff;
/* Bandwidth value is constant in octaves. */
@@ -93,25 +78,25 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex
/* Multiply sampling frequency by the amount of oversampling done during
* processing.
*/
BiquadFilter_setParams(&state->mLowpass, BiquadType::LowPass, 1.0f,
BiquadFilter_setParams(&mLowpass, BiquadType::LowPass, 1.0f,
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
cutoff = props->Distortion.EQCenter;
/* Convert bandwidth in Hz to octaves. */
bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
BiquadFilter_setParams(&state->mBandpass, BiquadType::BandPass, 1.0f,
BiquadFilter_setParams(&mBandpass, BiquadType::BandPass, 1.0f,
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->mGain);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain);
}
static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALdistortionState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat (*RESTRICT buffer)[BUFFERSIZE] = state->Buffer;
const ALfloat fc = state->mEdgeCoeff;
ALfloat (*RESTRICT buffer)[BUFFERSIZE] = mBuffer;
const ALfloat fc = mEdgeCoeff;
ALsizei base;
ALsizei i, k;
@@ -135,7 +120,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample
* (which is fortunately first step of distortion). So combine three
* operations into the one.
*/
BiquadFilter_process(&state->mLowpass, buffer[1], buffer[0], todo);
BiquadFilter_process(&mLowpass, buffer[1], buffer[0], todo);
/* Second step, do distortion using waveshaper function to emulate
* signal processing during tube overdriving. Three steps of
@@ -154,7 +139,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample
}
/* Third step, do bandpass filtering of distorted signal. */
BiquadFilter_process(&state->mBandpass, buffer[1], buffer[0], todo);
BiquadFilter_process(&mBandpass, buffer[1], buffer[0], todo);
todo >>= 2;
for(k = 0;k < NumChannels;k++)
@@ -162,7 +147,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample
/* Fourth step, final, do attenuation and perform decimation,
* storing only one sample out of four.
*/
ALfloat gain = state->mGain[k];
ALfloat gain = mGain[k];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
@@ -176,15 +161,11 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample
struct DistortionStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *DistortionStateFactory::create()
{
ALdistortionState *state;
NEW_OBJ0(state, ALdistortionState)();
return state;
}
EffectState *DistortionStateFactory::create()
{ return new ALdistortionState{}; }
EffectStateFactory *DistortionStateFactory_getFactory(void)
{
+42 -61
View File
@@ -35,7 +35,7 @@
#include "vector.h"
struct ALechoState final : public ALeffectState {
struct ALechoState final : public EffectState {
al::vector<ALfloat,16> mSampleBuffer;
// The echo is two tap. The delay is the number of samples from before the
@@ -54,31 +54,16 @@ struct ALechoState final : public ALeffectState {
ALfloat mFeedGain{0.0f};
BiquadFilter mFilter;
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALechoState)
};
static ALvoid ALechoState_Destruct(ALechoState *state);
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device);
static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALechoState)
DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
static void ALechoState_Construct(ALechoState *state)
{
new (state) ALechoState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALechoState, ALeffectState, state);
}
static ALvoid ALechoState_Destruct(ALechoState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALechoState();
}
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
ALboolean ALechoState::deviceUpdate(ALCdevice *Device)
{
ALuint maxlen;
@@ -89,14 +74,14 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
maxlen = NextPowerOf2(maxlen);
if(maxlen <= 0) return AL_FALSE;
if(maxlen != state->mSampleBuffer.size())
if(maxlen != mSampleBuffer.size())
{
state->mSampleBuffer.resize(maxlen);
state->mSampleBuffer.shrink_to_fit();
mSampleBuffer.resize(maxlen);
mSampleBuffer.shrink_to_fit();
}
std::fill(state->mSampleBuffer.begin(), state->mSampleBuffer.end(), 0.0f);
for(auto &e : state->mGains)
std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f);
for(auto &e : mGains)
{
std::fill(std::begin(e.Current), std::end(e.Current), 0.0f);
std::fill(std::begin(e.Target), std::end(e.Target), 0.0f);
@@ -105,16 +90,16 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
return AL_TRUE;
}
static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALuint frequency = device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat gainhf, lrpan, spread;
state->mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1);
state->mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f);
state->mTap[1].delay += state->mTap[0].delay;
mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1);
mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f);
mTap[1].delay += mTap[0].delay;
spread = props->Echo.Spread;
if(spread < 0.0f) lrpan = -1.0f;
@@ -124,35 +109,35 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context,
*/
spread = asinf(1.0f - fabsf(spread))*4.0f;
state->mFeedGain = props->Echo.Feedback;
mFeedGain = props->Echo.Feedback;
gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */
BiquadFilter_setParams(&state->mFilter, BiquadType::HighShelf,
BiquadFilter_setParams(&mFilter, BiquadType::HighShelf,
gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f)
);
/* First tap panning */
CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mGains[0].Target);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mGains[0].Target);
/* Second tap panning */
CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mGains[1].Target);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mGains[1].Target);
}
static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALsizei mask = state->mSampleBuffer.size()-1;
const ALsizei tap1 = state->mTap[0].delay;
const ALsizei tap2 = state->mTap[1].delay;
ALfloat *RESTRICT delaybuf = state->mSampleBuffer.data();
ALsizei offset = state->mOffset;
const ALsizei mask = mSampleBuffer.size()-1;
const ALsizei tap1 = mTap[0].delay;
const ALsizei tap2 = mTap[1].delay;
ALfloat *RESTRICT delaybuf = mSampleBuffer.data();
ALsizei offset = mOffset;
ALfloat z1, z2, in, out;
ALsizei base;
ALsizei c, i;
z1 = state->mFilter.z1;
z2 = state->mFilter.z2;
z1 = mFilter.z1;
z2 = mFilter.z2;
for(base = 0;base < SamplesToDo;)
{
alignas(16) ALfloat temps[2][128];
@@ -172,37 +157,33 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const
* feedback attenuation.
*/
in = temps[1][i];
out = in*state->mFilter.b0 + z1;
z1 = in*state->mFilter.b1 - out*state->mFilter.a1 + z2;
z2 = in*state->mFilter.b2 - out*state->mFilter.a2;
out = in*mFilter.b0 + z1;
z1 = in*mFilter.b1 - out*mFilter.a1 + z2;
z2 = in*mFilter.b2 - out*mFilter.a2;
delaybuf[offset&mask] += out * state->mFeedGain;
delaybuf[offset&mask] += out * mFeedGain;
offset++;
}
for(c = 0;c < 2;c++)
MixSamples(temps[c], NumChannels, SamplesOut, state->mGains[c].Current,
state->mGains[c].Target, SamplesToDo-base, base, td);
MixSamples(temps[c], NumChannels, SamplesOut, mGains[c].Current,
mGains[c].Target, SamplesToDo-base, base, td);
base += td;
}
state->mFilter.z1 = z1;
state->mFilter.z2 = z2;
mFilter.z1 = z1;
mFilter.z2 = z2;
state->mOffset = offset;
mOffset = offset;
}
struct EchoStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *EchoStateFactory::create()
{
ALechoState *state;
NEW_OBJ0(state, ALechoState)();
return state;
}
EffectState *EchoStateFactory::create()
{ return new ALechoState{}; }
EffectStateFactory *EchoStateFactory_getFactory(void)
{
+35 -60
View File
@@ -76,7 +76,7 @@
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
struct ALequalizerState final : public ALeffectState {
struct ALequalizerState final : public EffectState {
struct {
/* Effect parameters */
BiquadFilter filter[4];
@@ -87,33 +87,18 @@ struct ALequalizerState final : public ALeffectState {
} mChans[MAX_EFFECT_CHANNELS];
ALfloat mSampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]{};
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALequalizerState)
};
static ALvoid ALequalizerState_Destruct(ALequalizerState *state);
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device);
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
static void ALequalizerState_Construct(ALequalizerState *state)
ALboolean ALequalizerState::deviceUpdate(ALCdevice *UNUSED(device))
{
new (state) ALequalizerState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALequalizerState, ALeffectState, state);
}
static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALequalizerState();
}
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device))
{
for(auto &e : state->mChans)
for(auto &e : mChans)
{
std::for_each(std::begin(e.filter), std::end(e.filter),
[](BiquadFilter &f) -> void
@@ -124,7 +109,7 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevic
return AL_TRUE;
}
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat frequency = (ALfloat)device->Frequency;
@@ -137,78 +122,68 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext
*/
gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */
f0norm = props->Equalizer.LowCutoff/frequency;
BiquadFilter_setParams(&state->mChans[0].filter[0], BiquadType::LowShelf,
BiquadFilter_setParams(&mChans[0].filter[0], BiquadType::LowShelf,
gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f)
);
gain = maxf(props->Equalizer.Mid1Gain, 0.0625f);
f0norm = props->Equalizer.Mid1Center/frequency;
BiquadFilter_setParams(&state->mChans[0].filter[1], BiquadType::Peaking,
gain, f0norm, calc_rcpQ_from_bandwidth(
f0norm, props->Equalizer.Mid1Width
)
BiquadFilter_setParams(&mChans[0].filter[1], BiquadType::Peaking,
gain, f0norm, calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid1Width)
);
gain = maxf(props->Equalizer.Mid2Gain, 0.0625f);
f0norm = props->Equalizer.Mid2Center/frequency;
BiquadFilter_setParams(&state->mChans[0].filter[2], BiquadType::Peaking,
gain, f0norm, calc_rcpQ_from_bandwidth(
f0norm, props->Equalizer.Mid2Width
)
BiquadFilter_setParams(&mChans[0].filter[2], BiquadType::Peaking,
gain, f0norm, calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid2Width)
);
gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f);
f0norm = props->Equalizer.HighCutoff/frequency;
BiquadFilter_setParams(&state->mChans[0].filter[3], BiquadType::HighShelf,
BiquadFilter_setParams(&mChans[0].filter[3], BiquadType::HighShelf,
gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f)
);
/* Copy the filter coefficients for the other input channels. */
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
{
BiquadFilter_copyParams(&state->mChans[i].filter[0], &state->mChans[0].filter[0]);
BiquadFilter_copyParams(&state->mChans[i].filter[1], &state->mChans[0].filter[1]);
BiquadFilter_copyParams(&state->mChans[i].filter[2], &state->mChans[0].filter[2]);
BiquadFilter_copyParams(&state->mChans[i].filter[3], &state->mChans[0].filter[3]);
BiquadFilter_copyParams(&mChans[i].filter[0], &mChans[0].filter[0]);
BiquadFilter_copyParams(&mChans[i].filter[1], &mChans[0].filter[1]);
BiquadFilter_copyParams(&mChans[i].filter[2], &mChans[0].filter[2]);
BiquadFilter_copyParams(&mChans[i].filter[3], &mChans[0].filter[3]);
}
state->OutBuffer = device->FOAOut.Buffer;
state->OutChannels = device->FOAOut.NumChannels;
mOutBuffer = device->FOAOut.Buffer;
mOutChannels = device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain,
state->mChans[i].TargetGains);
mChans[i].TargetGains);
}
static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALequalizerState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->mSampleBuffer;
ALfloat (*RESTRICT temps)[BUFFERSIZE] = mSampleBuffer;
ALsizei c;
for(c = 0;c < MAX_EFFECT_CHANNELS;c++)
{
BiquadFilter_process(&state->mChans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo);
BiquadFilter_process(&state->mChans[c].filter[1], temps[1], temps[0], SamplesToDo);
BiquadFilter_process(&state->mChans[c].filter[2], temps[2], temps[1], SamplesToDo);
BiquadFilter_process(&state->mChans[c].filter[3], temps[3], temps[2], SamplesToDo);
BiquadFilter_process(&mChans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo);
BiquadFilter_process(&mChans[c].filter[1], temps[1], temps[0], SamplesToDo);
BiquadFilter_process(&mChans[c].filter[2], temps[2], temps[1], SamplesToDo);
BiquadFilter_process(&mChans[c].filter[3], temps[3], temps[2], SamplesToDo);
MixSamples(temps[3], NumChannels, SamplesOut,
state->mChans[c].CurrentGains, state->mChans[c].TargetGains,
SamplesToDo, 0, SamplesToDo
);
MixSamples(temps[3], NumChannels, SamplesOut, mChans[c].CurrentGains,
mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo);
}
}
struct EqualizerStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *EqualizerStateFactory::create()
{
ALequalizerState *state;
NEW_OBJ0(state, ALequalizerState)();
return state;
}
EffectState *EqualizerStateFactory::create()
{ return new ALequalizerState{}; }
EffectStateFactory *EqualizerStateFactory_getFactory(void)
{
+52 -70
View File
@@ -60,7 +60,7 @@ std::array<ALdouble,HIL_SIZE> InitHannWindow(void)
alignas(16) const std::array<ALdouble,HIL_SIZE> HannWindow = InitHannWindow();
struct ALfshifterState final : public ALeffectState {
struct ALfshifterState final : public EffectState {
/* Effect parameters */
ALsizei mCount{};
ALsizei mPhaseStep{};
@@ -79,152 +79,134 @@ struct ALfshifterState final : public ALeffectState {
/* Effect gains for each output channel */
ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]{};
ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{};
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALfshifterState)
};
ALvoid ALfshifterState_Destruct(ALfshifterState *state);
ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device);
ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALfshifterState)
DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState);
void ALfshifterState_Construct(ALfshifterState *state)
{
new (state) ALfshifterState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALfshifterState, ALeffectState, state);
}
ALvoid ALfshifterState_Destruct(ALfshifterState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALfshifterState();
}
ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device))
ALboolean ALfshifterState::deviceUpdate(ALCdevice *UNUSED(device))
{
/* (Re-)initializing parameters and clear the buffers. */
state->mCount = FIFO_LATENCY;
state->mPhaseStep = 0;
state->mPhase = 0;
state->mLdSign = 1.0;
mCount = FIFO_LATENCY;
mPhaseStep = 0;
mPhase = 0;
mLdSign = 1.0;
std::fill(std::begin(state->mInFIFO), std::end(state->mInFIFO), 0.0f);
std::fill(std::begin(state->mOutFIFO), std::end(state->mOutFIFO), complex_d{});
std::fill(std::begin(state->mOutputAccum), std::end(state->mOutputAccum), complex_d{});
std::fill(std::begin(state->mAnalytic), std::end(state->mAnalytic), complex_d{});
std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f);
std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{});
std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{});
std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{});
std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f);
std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f);
std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
return AL_TRUE;
}
ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALfshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device{context->Device};
ALfloat step{props->Fshifter.Frequency / (ALfloat)device->Frequency};
state->mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE);
mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE);
switch(props->Fshifter.LeftDirection)
{
case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN:
state->mLdSign = -1.0;
mLdSign = -1.0;
break;
case AL_FREQUENCY_SHIFTER_DIRECTION_UP:
state->mLdSign = 1.0;
mLdSign = 1.0;
break;
case AL_FREQUENCY_SHIFTER_DIRECTION_OFF:
state->mPhase = 0;
state->mPhaseStep = 0;
mPhase = 0;
mPhaseStep = 0;
break;
}
ALfloat coeffs[MAX_AMBI_COEFFS];
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mTargetGains);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains);
}
ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALfshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
static const complex_d complex_zero{0.0, 0.0};
ALfloat *RESTRICT BufferOut = state->mBufferOut;
ALfloat *RESTRICT BufferOut = mBufferOut;
ALsizei j, k, base;
for(base = 0;base < SamplesToDo;)
{
ALsizei todo = mini(HIL_SIZE-state->mCount, SamplesToDo-base);
ALsizei todo = mini(HIL_SIZE-mCount, SamplesToDo-base);
ASSUME(todo > 0);
/* Fill FIFO buffer with samples data */
k = state->mCount;
k = mCount;
for(j = 0;j < todo;j++,k++)
{
state->mInFIFO[k] = SamplesIn[0][base+j];
state->mOutdata[base+j] = state->mOutFIFO[k-FIFO_LATENCY];
mInFIFO[k] = SamplesIn[0][base+j];
mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY];
}
state->mCount += todo;
mCount += todo;
base += todo;
/* Check whether FIFO buffer is filled */
if(state->mCount < HIL_SIZE) continue;
state->mCount = FIFO_LATENCY;
if(mCount < HIL_SIZE) continue;
mCount = FIFO_LATENCY;
/* Real signal windowing and store in Analytic buffer */
for(k = 0;k < HIL_SIZE;k++)
{
state->mAnalytic[k].real(state->mInFIFO[k] * HannWindow[k]);
state->mAnalytic[k].imag(0.0);
mAnalytic[k].real(mInFIFO[k] * HannWindow[k]);
mAnalytic[k].imag(0.0);
}
/* Processing signal by Discrete Hilbert Transform (analytical signal). */
complex_hilbert(state->mAnalytic, HIL_SIZE);
complex_hilbert(mAnalytic, HIL_SIZE);
/* Windowing and add to output accumulator */
for(k = 0;k < HIL_SIZE;k++)
state->mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*state->mAnalytic[k];
mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];
/* Shift accumulator, input & output FIFO */
for(k = 0;k < HIL_STEP;k++) state->mOutFIFO[k] = state->mOutputAccum[k];
for(j = 0;k < HIL_SIZE;k++,j++) state->mOutputAccum[j] = state->mOutputAccum[k];
for(;j < HIL_SIZE;j++) state->mOutputAccum[j] = complex_zero;
for(k = 0;k < HIL_STEP;k++) mOutFIFO[k] = mOutputAccum[k];
for(j = 0;k < HIL_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k];
for(;j < HIL_SIZE;j++) mOutputAccum[j] = complex_zero;
for(k = 0;k < FIFO_LATENCY;k++)
state->mInFIFO[k] = state->mInFIFO[k+HIL_STEP];
mInFIFO[k] = mInFIFO[k+HIL_STEP];
}
/* Process frequency shifter using the analytic signal obtained. */
for(k = 0;k < SamplesToDo;k++)
{
double phase = state->mPhase * ((1.0/FRACTIONONE) * 2.0*M_PI);
BufferOut[k] = (float)(state->mOutdata[k].real()*std::cos(phase) +
state->mOutdata[k].imag()*std::sin(phase)*state->mLdSign);
double phase = mPhase * ((1.0/FRACTIONONE) * 2.0*M_PI);
BufferOut[k] = (float)(mOutdata[k].real()*std::cos(phase) +
mOutdata[k].imag()*std::sin(phase)*mLdSign);
state->mPhase += state->mPhaseStep;
state->mPhase &= FRACTIONMASK;
mPhase += mPhaseStep;
mPhase &= FRACTIONMASK;
}
/* Now, mix the processed sound data to the output. */
MixSamples(BufferOut, NumChannels, SamplesOut, state->mCurrentGains, state->mTargetGains,
MixSamples(BufferOut, NumChannels, SamplesOut, mCurrentGains, mTargetGains,
maxi(SamplesToDo, 512), 0, SamplesToDo);
}
} // namespace
struct FshifterStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *FshifterStateFactory::create()
{
ALfshifterState *state;
NEW_OBJ0(state, ALfshifterState)();
return state;
}
EffectState *FshifterStateFactory::create()
{ return new ALfshifterState{}; }
EffectStateFactory *FshifterStateFactory_getFactory(void)
{
+34 -53
View File
@@ -37,7 +37,7 @@
#define MAX_UPDATE_SAMPLES 128
struct ALmodulatorState final : public ALeffectState {
struct ALmodulatorState final : public EffectState {
void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){};
ALsizei mIndex{0};
@@ -49,16 +49,15 @@ struct ALmodulatorState final : public ALeffectState {
ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{};
ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{};
} mChans[MAX_EFFECT_CHANNELS];
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALmodulatorState)
};
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state);
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device);
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
#define WAVEFORM_FRACBITS 24
#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
@@ -105,22 +104,9 @@ DECL_TEMPLATE(One)
#undef DECL_TEMPLATE
static void ALmodulatorState_Construct(ALmodulatorState *state)
ALboolean ALmodulatorState::deviceUpdate(ALCdevice *UNUSED(device))
{
new (state) ALmodulatorState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALmodulatorState, ALeffectState, state);
}
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALmodulatorState();
}
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device))
{
for(auto &e : state->mChans)
for(auto &e : mChans)
{
BiquadFilter_clear(&e.Filter);
std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f);
@@ -128,43 +114,42 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevic
return AL_TRUE;
}
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat f0norm;
ALsizei i;
state->mStep = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency *
WAVEFORM_FRACONE);
state->mStep = clampi(state->mStep, 0, WAVEFORM_FRACONE-1);
mStep = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * WAVEFORM_FRACONE);
mStep = clampi(mStep, 0, WAVEFORM_FRACONE-1);
if(state->mStep == 0)
state->mGetSamples = ModulateOne;
if(mStep == 0)
mGetSamples = ModulateOne;
else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
state->mGetSamples = ModulateSin;
mGetSamples = ModulateSin;
else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
state->mGetSamples = ModulateSaw;
mGetSamples = ModulateSaw;
else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
state->mGetSamples = ModulateSquare;
mGetSamples = ModulateSquare;
f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency;
f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f);
/* Bandwidth value is constant in octaves. */
BiquadFilter_setParams(&state->mChans[0].Filter, BiquadType::HighPass, 1.0f,
BiquadFilter_setParams(&mChans[0].Filter, BiquadType::HighPass, 1.0f,
f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f));
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
BiquadFilter_copyParams(&state->mChans[i].Filter, &state->mChans[0].Filter);
BiquadFilter_copyParams(&mChans[i].Filter, &mChans[0].Filter);
state->OutBuffer = device->FOAOut.Buffer;
state->OutChannels = device->FOAOut.NumChannels;
mOutBuffer = device->FOAOut.Buffer;
mOutChannels = device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain,
state->mChans[i].TargetGains);
mChans[i].TargetGains);
}
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALmodulatorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALsizei step = state->mStep;
const ALsizei step = mStep;
ALsizei base;
for(base = 0;base < SamplesToDo;)
@@ -173,20 +158,20 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT
ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base);
ALsizei c, i;
state->mGetSamples(modsamples, state->mIndex, step, td);
state->mIndex += (step*td) & WAVEFORM_FRACMASK;
state->mIndex &= WAVEFORM_FRACMASK;
mGetSamples(modsamples, mIndex, step, td);
mIndex += (step*td) & WAVEFORM_FRACMASK;
mIndex &= WAVEFORM_FRACMASK;
for(c = 0;c < MAX_EFFECT_CHANNELS;c++)
{
alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES];
BiquadFilter_process(&state->mChans[c].Filter, temps, &SamplesIn[c][base], td);
BiquadFilter_process(&mChans[c].Filter, temps, &SamplesIn[c][base], td);
for(i = 0;i < td;i++)
temps[i] *= modsamples[i];
MixSamples(temps, NumChannels, SamplesOut, state->mChans[c].CurrentGains,
state->mChans[c].TargetGains, SamplesToDo-base, base, td);
MixSamples(temps, NumChannels, SamplesOut, mChans[c].CurrentGains,
mChans[c].TargetGains, SamplesToDo-base, base, td);
}
base += td;
@@ -195,15 +180,11 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT
struct ModulatorStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *ModulatorStateFactory::create()
{
ALmodulatorState *state;
NEW_OBJ0(state, ALmodulatorState)();
return state;
}
EffectState *ModulatorStateFactory::create()
{ return new ALmodulatorState{}; }
EffectStateFactory *ModulatorStateFactory_getFactory(void)
{
+20 -51
View File
@@ -11,47 +11,36 @@
#include "alError.h"
struct ALnullState final : public ALeffectState {
struct ALnullState final : public EffectState {
ALnullState();
~ALnullState() override;
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALnullState)
};
/* Forward-declare "virtual" functions to define the vtable with. */
static ALvoid ALnullState_Destruct(ALnullState *state);
static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device);
static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei mumChannels);
static void *ALnullState_New(size_t size);
static void ALnullState_Delete(void *ptr);
/* Define the ALeffectState vtable for this type. */
DEFINE_ALEFFECTSTATE_VTABLE(ALnullState);
/* This constructs the effect state. It's called when the object is first
* created. Make sure to call the parent Construct function first, and set the
* vtable!
* created.
*/
static void ALnullState_Construct(ALnullState *state)
ALnullState::ALnullState()
{
new (state) ALnullState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALnullState, ALeffectState, state);
}
/* This destructs (not free!) the effect state. It's called only when the
* effect slot is no longer used. Make sure to call the parent Destruct
* function before returning!
/* This destructs the effect state. It's called only when the effect slot is no
* longer used prior to being freed.
*/
static ALvoid ALnullState_Destruct(ALnullState *state)
ALnullState::~ALnullState()
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALnullState();
}
/* This updates the device-dependant effect state. This is called on
* initialization and any time the device parameters (eg. playback frequency,
* format) have been changed.
*/
static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device))
ALboolean ALnullState::deviceUpdate(ALCdevice* UNUSED(device))
{
return AL_TRUE;
}
@@ -59,7 +48,7 @@ static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice*
/* This updates the effect state. This is called any time the effect is
* (re)loaded into a slot.
*/
static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
void ALnullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
{
}
@@ -67,38 +56,18 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* U
* input to the output buffer. The result should be added to the output buffer,
* not replace it.
*/
static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesIn), ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesOut), ALsizei UNUSED(numChannels))
void ALnullState::process(ALsizei UNUSED(samplesToDo), const ALfloat (*RESTRICT UNUSED(samplesIn))[BUFFERSIZE], ALfloat (*RESTRICT UNUSED(samplesOut))[BUFFERSIZE], ALsizei UNUSED(numChannels))
{
}
/* This allocates memory to store the object, before it gets constructed.
* DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method.
*/
static void *ALnullState_New(size_t size)
{
return al_calloc(16, size);
}
/* This frees the memory used by the object, after it has been destructed.
* DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method.
*/
static void ALnullState_Delete(void *ptr)
{
al_free(ptr);
}
struct NullStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
/* Creates ALeffectState objects of the appropriate type. */
ALeffectState *NullStateFactory::create()
{
ALnullState *state;
NEW_OBJ0(state, ALnullState)();
return state;
}
EffectState *NullStateFactory::create()
{ return new ALnullState{}; }
EffectStateFactory *NullStateFactory_getFactory(void)
{
+64 -83
View File
@@ -117,7 +117,7 @@ inline complex_d polar2rect(const ALphasor &number)
{ return std::polar<double>(number.Amplitude, number.Phase); }
struct ALpshifterState final : public ALeffectState {
struct ALpshifterState final : public EffectState {
/* Effect parameters */
ALsizei mCount;
ALsizei mPitchShiftI;
@@ -141,53 +141,39 @@ struct ALpshifterState final : public ALeffectState {
/* Effect gains for each output channel */
ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS];
ALfloat mTargetGains[MAX_OUTPUT_CHANNELS];
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ALpshifterState)
};
static ALvoid ALpshifterState_Destruct(ALpshifterState *state);
static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device);
static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALpshifterState)
DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState);
void ALpshifterState_Construct(ALpshifterState *state)
{
new (state) ALpshifterState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALpshifterState, ALeffectState, state);
}
ALvoid ALpshifterState_Destruct(ALpshifterState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
state->~ALpshifterState();
}
ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device)
ALboolean ALpshifterState::deviceUpdate(ALCdevice *device)
{
/* (Re-)initializing parameters and clear the buffers. */
state->mCount = FIFO_LATENCY;
state->mPitchShiftI = FRACTIONONE;
state->mPitchShift = 1.0f;
state->mFreqPerBin = device->Frequency / (ALfloat)STFT_SIZE;
mCount = FIFO_LATENCY;
mPitchShiftI = FRACTIONONE;
mPitchShift = 1.0f;
mFreqPerBin = device->Frequency / (ALfloat)STFT_SIZE;
std::fill(std::begin(state->mInFIFO), std::end(state->mInFIFO), 0.0f);
std::fill(std::begin(state->mOutFIFO), std::end(state->mOutFIFO), 0.0f);
std::fill(std::begin(state->mLastPhase), std::end(state->mLastPhase), 0.0);
std::fill(std::begin(state->mSumPhase), std::end(state->mSumPhase), 0.0);
std::fill(std::begin(state->mOutputAccum), std::end(state->mOutputAccum), 0.0);
std::fill(std::begin(state->mFFTbuffer), std::end(state->mFFTbuffer), complex_d{});
std::fill(std::begin(state->mAnalysis_buffer), std::end(state->mAnalysis_buffer), ALfrequencyDomain{});
std::fill(std::begin(state->mSyntesis_buffer), std::end(state->mSyntesis_buffer), ALfrequencyDomain{});
std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f);
std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), 0.0f);
std::fill(std::begin(mLastPhase), std::end(mLastPhase), 0.0);
std::fill(std::begin(mSumPhase), std::end(mSumPhase), 0.0);
std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), 0.0);
std::fill(std::begin(mFFTbuffer), std::end(mFFTbuffer), complex_d{});
std::fill(std::begin(mAnalysis_buffer), std::end(mAnalysis_buffer), ALfrequencyDomain{});
std::fill(std::begin(mSyntesis_buffer), std::end(mSyntesis_buffer), ALfrequencyDomain{});
std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f);
std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f);
std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
return AL_TRUE;
}
ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
void ALpshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat coeffs[MAX_AMBI_COEFFS];
@@ -196,30 +182,30 @@ ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context,
pitch = std::pow(2.0f,
(ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f
);
state->mPitchShiftI = fastf2i(pitch*FRACTIONONE);
state->mPitchShift = state->mPitchShiftI * (1.0f/FRACTIONONE);
mPitchShiftI = fastf2i(pitch*FRACTIONONE);
mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE);
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mTargetGains);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains);
}
ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ALpshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
/* Pitch shifter engine based on the work of Stephan Bernsee.
* http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
*/
static constexpr ALdouble expected{M_PI*2.0 / OVERSAMP};
const ALdouble freq_per_bin{state->mFreqPerBin};
ALfloat *RESTRICT bufferOut{state->mBufferOut};
ALsizei count{state->mCount};
const ALdouble freq_per_bin{mFreqPerBin};
ALfloat *RESTRICT bufferOut{mBufferOut};
ALsizei count{mCount};
for(ALsizei i{0};i < SamplesToDo;)
{
do {
/* Fill FIFO buffer with samples data */
state->mInFIFO[count] = SamplesIn[0][i];
bufferOut[i] = state->mOutFIFO[count - FIFO_LATENCY];
mInFIFO[count] = SamplesIn[0][i];
bufferOut[i] = mOutFIFO[count - FIFO_LATENCY];
count++;
} while(++i < SamplesToDo && count < STFT_SIZE);
@@ -231,13 +217,13 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons
/* Real signal windowing and store in FFTbuffer */
for(ALsizei k{0};k < STFT_SIZE;k++)
{
state->mFFTbuffer[k].real(state->mInFIFO[k] * HannWindow[k]);
state->mFFTbuffer[k].imag(0.0);
mFFTbuffer[k].real(mInFIFO[k] * HannWindow[k]);
mFFTbuffer[k].imag(0.0);
}
/* ANALYSIS */
/* Apply FFT to FFTbuffer data */
complex_fft(state->mFFTbuffer, STFT_SIZE, -1.0);
complex_fft(mFFTbuffer, STFT_SIZE, -1.0);
/* Analyze the obtained data. Since the real FFT is symmetric, only
* STFT_HALF_SIZE+1 samples are needed.
@@ -245,10 +231,10 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons
for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++)
{
/* Compute amplitude and phase */
ALphasor component{rect2polar(state->mFFTbuffer[k])};
ALphasor component{rect2polar(mFFTbuffer[k])};
/* Compute phase difference and subtract expected phase difference */
double tmp{(component.Phase - state->mLastPhase[k]) - k*expected};
double tmp{(component.Phase - mLastPhase[k]) - k*expected};
/* Map delta phase into +/- Pi interval */
int qpd{double2int(tmp / M_PI)};
@@ -261,29 +247,28 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons
* for maintain the gain (because half of bins are used) and store
* amplitude and true frequency in analysis buffer.
*/
state->mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude;
state->mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin;
mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude;
mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin;
/* Store actual phase[k] for the calculations in the next frame*/
state->mLastPhase[k] = component.Phase;
mLastPhase[k] = component.Phase;
}
/* PROCESSING */
/* pitch shifting */
for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++)
{
state->mSyntesis_buffer[k].Amplitude = 0.0;
state->mSyntesis_buffer[k].Frequency = 0.0;
mSyntesis_buffer[k].Amplitude = 0.0;
mSyntesis_buffer[k].Frequency = 0.0;
}
for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++)
{
ALsizei j{(k*state->mPitchShiftI) >> FRACTIONBITS};
ALsizei j{(k*mPitchShiftI) >> FRACTIONBITS};
if(j >= STFT_HALF_SIZE+1) break;
state->mSyntesis_buffer[j].Amplitude += state->mAnalysis_buffer[k].Amplitude;
state->mSyntesis_buffer[j].Frequency = state->mAnalysis_buffer[k].Frequency *
state->mPitchShift;
mSyntesis_buffer[j].Amplitude += mAnalysis_buffer[k].Amplitude;
mSyntesis_buffer[j].Frequency = mAnalysis_buffer[k].Frequency * mPitchShift;
}
/* SYNTHESIS */
@@ -294,56 +279,52 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons
ALdouble tmp;
/* Compute bin deviation from scaled freq */
tmp = state->mSyntesis_buffer[k].Frequency/freq_per_bin - k;
tmp = mSyntesis_buffer[k].Frequency/freq_per_bin - k;
/* Calculate actual delta phase and accumulate it to get bin phase */
state->mSumPhase[k] += (k + tmp) * expected;
mSumPhase[k] += (k + tmp) * expected;
component.Amplitude = state->mSyntesis_buffer[k].Amplitude;
component.Phase = state->mSumPhase[k];
component.Amplitude = mSyntesis_buffer[k].Amplitude;
component.Phase = mSumPhase[k];
/* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/
state->mFFTbuffer[k] = polar2rect(component);
mFFTbuffer[k] = polar2rect(component);
}
/* zero negative frequencies for recontruct a real signal */
for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++)
state->mFFTbuffer[k] = complex_d{};
mFFTbuffer[k] = complex_d{};
/* Apply iFFT to buffer data */
complex_fft(state->mFFTbuffer, STFT_SIZE, 1.0);
complex_fft(mFFTbuffer, STFT_SIZE, 1.0);
/* Windowing and add to output */
for(ALsizei k{0};k < STFT_SIZE;k++)
state->mOutputAccum[k] += HannWindow[k] * state->mFFTbuffer[k].real() /
(0.5 * STFT_HALF_SIZE * OVERSAMP);
mOutputAccum[k] += HannWindow[k] * mFFTbuffer[k].real() /
(0.5 * STFT_HALF_SIZE * OVERSAMP);
/* Shift accumulator, input & output FIFO */
ALsizei j, k;
for(k = 0;k < STFT_STEP;k++) state->mOutFIFO[k] = (ALfloat)state->mOutputAccum[k];
for(j = 0;k < STFT_SIZE;k++,j++) state->mOutputAccum[j] = state->mOutputAccum[k];
for(;j < STFT_SIZE;j++) state->mOutputAccum[j] = 0.0;
for(k = 0;k < STFT_STEP;k++) mOutFIFO[k] = (ALfloat)mOutputAccum[k];
for(j = 0;k < STFT_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k];
for(;j < STFT_SIZE;j++) mOutputAccum[j] = 0.0;
for(k = 0;k < FIFO_LATENCY;k++)
state->mInFIFO[k] = state->mInFIFO[k+STFT_STEP];
mInFIFO[k] = mInFIFO[k+STFT_STEP];
}
state->mCount = count;
mCount = count;
/* Now, mix the processed sound data to the output. */
MixSamples(bufferOut, NumChannels, SamplesOut, state->mCurrentGains, state->mTargetGains,
MixSamples(bufferOut, NumChannels, SamplesOut, mCurrentGains, mTargetGains,
maxi(SamplesToDo, 512), 0, SamplesToDo);
}
} // namespace
struct PshifterStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *PshifterStateFactory::create()
{
ALpshifterState *state;
NEW_OBJ0(state, ALpshifterState)();
return state;
}
EffectState *PshifterStateFactory::create()
{ return new ALpshifterState{}; }
EffectStateFactory *PshifterStateFactory_getFactory(void)
{
+152 -168
View File
@@ -280,7 +280,7 @@ typedef struct LateReverb {
ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS];
} LateReverb;
struct ReverbState final : public ALeffectState {
struct ReverbState final : public EffectState {
/* All delay lines are allocated as a single buffer to reduce memory
* fragmentation and management code.
*/
@@ -332,116 +332,106 @@ struct ReverbState final : public ALeffectState {
/* Temporary storage used when processing. */
alignas(16) ALfloat mTempSamples[NUM_LINES][MAX_UPDATE_SAMPLES];
alignas(16) ALfloat mMixBuffer[NUM_LINES][MAX_UPDATE_SAMPLES];
ReverbState();
ALboolean deviceUpdate(ALCdevice *device) override;
void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override;
void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override;
DEF_NEWDEL(ReverbState)
};
static ALvoid ReverbState_Destruct(ReverbState *State);
static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device);
static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ReverbState)
DEFINE_ALEFFECTSTATE_VTABLE(ReverbState);
static void ReverbState_Construct(ReverbState *state)
ReverbState::ReverbState()
{
new (state) ReverbState{};
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ReverbState, ALeffectState, state);
state->mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY;
state->mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
state->mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
state->mParams.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
state->mParams.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
state->mParams.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
state->mParams.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY;
mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
mParams.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
mParams.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
mParams.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
mParams.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
for(ALsizei i{0};i < NUM_LINES;i++)
{
BiquadFilter_clear(&state->mFilter[i].Lp);
BiquadFilter_clear(&state->mFilter[i].Hp);
BiquadFilter_clear(&mFilter[i].Lp);
BiquadFilter_clear(&mFilter[i].Hp);
}
state->mDelay.Mask = 0;
state->mDelay.Line = NULL;
mDelay.Mask = 0;
mDelay.Line = NULL;
for(ALsizei i{0};i < NUM_LINES;i++)
{
state->mEarlyDelayTap[i][0] = 0;
state->mEarlyDelayTap[i][1] = 0;
state->mEarlyDelayCoeff[i][0] = 0.0f;
state->mEarlyDelayCoeff[i][1] = 0.0f;
mEarlyDelayTap[i][0] = 0;
mEarlyDelayTap[i][1] = 0;
mEarlyDelayCoeff[i][0] = 0.0f;
mEarlyDelayCoeff[i][1] = 0.0f;
}
state->mLateFeedTap = 0;
mLateFeedTap = 0;
for(ALsizei i{0};i < NUM_LINES;i++)
{
state->mLateDelayTap[i][0] = 0;
state->mLateDelayTap[i][1] = 0;
mLateDelayTap[i][0] = 0;
mLateDelayTap[i][1] = 0;
}
state->mMixX = 0.0f;
state->mMixY = 0.0f;
mMixX = 0.0f;
mMixY = 0.0f;
state->mEarly.VecAp.Delay.Mask = 0;
state->mEarly.VecAp.Delay.Line = NULL;
state->mEarly.VecAp.Coeff = 0.0f;
state->mEarly.Delay.Mask = 0;
state->mEarly.Delay.Line = NULL;
mEarly.VecAp.Delay.Mask = 0;
mEarly.VecAp.Delay.Line = NULL;
mEarly.VecAp.Coeff = 0.0f;
mEarly.Delay.Mask = 0;
mEarly.Delay.Line = NULL;
for(ALsizei i{0};i < NUM_LINES;i++)
{
state->mEarly.VecAp.Offset[i][0] = 0;
state->mEarly.VecAp.Offset[i][1] = 0;
state->mEarly.Offset[i][0] = 0;
state->mEarly.Offset[i][1] = 0;
state->mEarly.Coeff[i][0] = 0.0f;
state->mEarly.Coeff[i][1] = 0.0f;
mEarly.VecAp.Offset[i][0] = 0;
mEarly.VecAp.Offset[i][1] = 0;
mEarly.Offset[i][0] = 0;
mEarly.Offset[i][1] = 0;
mEarly.Coeff[i][0] = 0.0f;
mEarly.Coeff[i][1] = 0.0f;
}
state->mLate.DensityGain[0] = 0.0f;
state->mLate.DensityGain[1] = 0.0f;
state->mLate.Delay.Mask = 0;
state->mLate.Delay.Line = NULL;
state->mLate.VecAp.Delay.Mask = 0;
state->mLate.VecAp.Delay.Line = NULL;
state->mLate.VecAp.Coeff = 0.0f;
mLate.DensityGain[0] = 0.0f;
mLate.DensityGain[1] = 0.0f;
mLate.Delay.Mask = 0;
mLate.Delay.Line = NULL;
mLate.VecAp.Delay.Mask = 0;
mLate.VecAp.Delay.Line = NULL;
mLate.VecAp.Coeff = 0.0f;
for(ALsizei i{0};i < NUM_LINES;i++)
{
state->mLate.Offset[i][0] = 0;
state->mLate.Offset[i][1] = 0;
mLate.Offset[i][0] = 0;
mLate.Offset[i][1] = 0;
state->mLate.VecAp.Offset[i][0] = 0;
state->mLate.VecAp.Offset[i][1] = 0;
mLate.VecAp.Offset[i][0] = 0;
mLate.VecAp.Offset[i][1] = 0;
state->mLate.T60[i].MidGain[0] = 0.0f;
state->mLate.T60[i].MidGain[1] = 0.0f;
BiquadFilter_clear(&state->mLate.T60[i].HFFilter);
BiquadFilter_clear(&state->mLate.T60[i].LFFilter);
mLate.T60[i].MidGain[0] = 0.0f;
mLate.T60[i].MidGain[1] = 0.0f;
BiquadFilter_clear(&mLate.T60[i].HFFilter);
BiquadFilter_clear(&mLate.T60[i].LFFilter);
}
for(ALsizei i{0};i < NUM_LINES;i++)
{
for(ALsizei j{0};j < MAX_OUTPUT_CHANNELS;j++)
{
state->mEarly.CurrentGain[i][j] = 0.0f;
state->mEarly.PanGain[i][j] = 0.0f;
state->mLate.CurrentGain[i][j] = 0.0f;
state->mLate.PanGain[i][j] = 0.0f;
mEarly.CurrentGain[i][j] = 0.0f;
mEarly.PanGain[i][j] = 0.0f;
mLate.CurrentGain[i][j] = 0.0f;
mLate.PanGain[i][j] = 0.0f;
}
}
state->mFadeCount = 0;
state->mMaxUpdate[0] = MAX_UPDATE_SAMPLES;
state->mMaxUpdate[1] = MAX_UPDATE_SAMPLES;
state->mOffset = 0;
}
static ALvoid ReverbState_Destruct(ReverbState *State)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,State));
State->~ReverbState();
mFadeCount = 0;
mMaxUpdate[0] = MAX_UPDATE_SAMPLES;
mMaxUpdate[1] = MAX_UPDATE_SAMPLES;
mOffset = 0;
}
/**************************************
@@ -555,70 +545,70 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State)
return AL_TRUE;
}
static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device)
ALboolean ReverbState::deviceUpdate(ALCdevice *Device)
{
ALuint frequency = Device->Frequency;
ALfloat multiplier;
ALsizei i, j;
/* Allocate the delay lines. */
if(!AllocLines(frequency, State))
if(!AllocLines(frequency, this))
return AL_FALSE;
multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY);
/* The late feed taps are set a fixed position past the latest delay tap. */
State->mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) *
frequency);
mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) *
frequency);
/* Clear filters and gain coefficients since the delay lines were all just
* cleared (if not reallocated).
*/
for(i = 0;i < NUM_LINES;i++)
{
BiquadFilter_clear(&State->mFilter[i].Lp);
BiquadFilter_clear(&State->mFilter[i].Hp);
BiquadFilter_clear(&mFilter[i].Lp);
BiquadFilter_clear(&mFilter[i].Hp);
}
for(i = 0;i < NUM_LINES;i++)
{
State->mEarlyDelayCoeff[i][0] = 0.0f;
State->mEarlyDelayCoeff[i][1] = 0.0f;
mEarlyDelayCoeff[i][0] = 0.0f;
mEarlyDelayCoeff[i][1] = 0.0f;
}
for(i = 0;i < NUM_LINES;i++)
{
State->mEarly.Coeff[i][0] = 0.0f;
State->mEarly.Coeff[i][1] = 0.0f;
mEarly.Coeff[i][0] = 0.0f;
mEarly.Coeff[i][1] = 0.0f;
}
State->mLate.DensityGain[0] = 0.0f;
State->mLate.DensityGain[1] = 0.0f;
mLate.DensityGain[0] = 0.0f;
mLate.DensityGain[1] = 0.0f;
for(i = 0;i < NUM_LINES;i++)
{
State->mLate.T60[i].MidGain[0] = 0.0f;
State->mLate.T60[i].MidGain[1] = 0.0f;
BiquadFilter_clear(&State->mLate.T60[i].HFFilter);
BiquadFilter_clear(&State->mLate.T60[i].LFFilter);
mLate.T60[i].MidGain[0] = 0.0f;
mLate.T60[i].MidGain[1] = 0.0f;
BiquadFilter_clear(&mLate.T60[i].HFFilter);
BiquadFilter_clear(&mLate.T60[i].LFFilter);
}
for(i = 0;i < NUM_LINES;i++)
{
for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
{
State->mEarly.CurrentGain[i][j] = 0.0f;
State->mEarly.PanGain[i][j] = 0.0f;
State->mLate.CurrentGain[i][j] = 0.0f;
State->mLate.PanGain[i][j] = 0.0f;
mEarly.CurrentGain[i][j] = 0.0f;
mEarly.PanGain[i][j] = 0.0f;
mLate.CurrentGain[i][j] = 0.0f;
mLate.PanGain[i][j] = 0.0f;
}
}
/* Reset counters and offset base. */
State->mFadeCount = 0;
State->mMaxUpdate[0] = MAX_UPDATE_SAMPLES;
State->mMaxUpdate[1] = MAX_UPDATE_SAMPLES;
State->mOffset = 0;
mFadeCount = 0;
mMaxUpdate[0] = MAX_UPDATE_SAMPLES;
mMaxUpdate[1] = MAX_UPDATE_SAMPLES;
mOffset = 0;
return AL_TRUE;
}
@@ -902,8 +892,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
aluMatrixf transform, rot;
ALsizei i;
STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels;
State->mOutBuffer = Device->FOAOut.Buffer;
State->mOutChannels = Device->FOAOut.NumChannels;
/* Note: _res is transposed. */
#define MATRIX_MULT(_res, _m1, _m2) do { \
@@ -934,7 +924,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
#undef MATRIX_MULT
}
static void ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALCdevice *Device = Context->Device;
const ALlistener &Listener = Context->Listener;
@@ -950,29 +940,29 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co
* killing most of the signal.
*/
gainhf = maxf(props->Reverb.GainHF, 0.001f);
BiquadFilter_setParams(&State->mFilter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm,
BiquadFilter_setParams(&mFilter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm,
calc_rcpQ_from_slope(gainhf, 1.0f));
lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f);
gainlf = maxf(props->Reverb.GainLF, 0.001f);
BiquadFilter_setParams(&State->mFilter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm,
BiquadFilter_setParams(&mFilter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm,
calc_rcpQ_from_slope(gainlf, 1.0f));
for(i = 1;i < NUM_LINES;i++)
{
BiquadFilter_copyParams(&State->mFilter[i].Lp, &State->mFilter[0].Lp);
BiquadFilter_copyParams(&State->mFilter[i].Hp, &State->mFilter[0].Hp);
BiquadFilter_copyParams(&mFilter[i].Lp, &mFilter[0].Lp);
BiquadFilter_copyParams(&mFilter[i].Hp, &mFilter[0].Hp);
}
/* Update the main effect delay and associated taps. */
UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
props->Reverb.Density, props->Reverb.DecayTime, frequency,
State);
this);
/* Update the early lines. */
UpdateEarlyLines(props->Reverb.Density, props->Reverb.Diffusion,
props->Reverb.DecayTime, frequency, &State->mEarly);
props->Reverb.DecayTime, frequency, &mEarly);
/* Get the mixing matrix coefficients. */
CalcMatrixCoeffs(props->Reverb.Diffusion, &State->mMixX, &State->mMixY);
CalcMatrixCoeffs(props->Reverb.Diffusion, &mMixX, &mMixY);
/* If the HF limit parameter is flagged, calculate an appropriate limit
* based on the air absorption parameter.
@@ -992,45 +982,43 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co
/* Update the late lines. */
UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion,
lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm,
frequency, &State->mLate
frequency, &mLate
);
/* Update early and late 3D panning. */
gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost;
Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan,
props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain,
State);
this);
/* Calculate the max update size from the smallest relevant delay. */
State->mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES,
mini(State->mEarly.Offset[0][1], State->mLate.Offset[0][1])
);
mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1]));
/* Determine if delay-line cross-fading is required. Density is essentially
* a master control for the feedback delays, so changes the offsets of many
* delay lines.
*/
if(State->mParams.Density != props->Reverb.Density ||
if(mParams.Density != props->Reverb.Density ||
/* Diffusion and decay times influences the decay rate (gain) of the
* late reverb T60 filter.
*/
State->mParams.Diffusion != props->Reverb.Diffusion ||
State->mParams.DecayTime != props->Reverb.DecayTime ||
State->mParams.HFDecayTime != hfDecayTime ||
State->mParams.LFDecayTime != lfDecayTime ||
mParams.Diffusion != props->Reverb.Diffusion ||
mParams.DecayTime != props->Reverb.DecayTime ||
mParams.HFDecayTime != hfDecayTime ||
mParams.LFDecayTime != lfDecayTime ||
/* HF/LF References control the weighting used to calculate the density
* gain.
*/
State->mParams.HFReference != props->Reverb.HFReference ||
State->mParams.LFReference != props->Reverb.LFReference)
State->mFadeCount = 0;
State->mParams.Density = props->Reverb.Density;
State->mParams.Diffusion = props->Reverb.Diffusion;
State->mParams.DecayTime = props->Reverb.DecayTime;
State->mParams.HFDecayTime = hfDecayTime;
State->mParams.LFDecayTime = lfDecayTime;
State->mParams.HFReference = props->Reverb.HFReference;
State->mParams.LFReference = props->Reverb.LFReference;
mParams.HFReference != props->Reverb.HFReference ||
mParams.LFReference != props->Reverb.LFReference)
mFadeCount = 0;
mParams.Density = props->Reverb.Density;
mParams.Diffusion = props->Reverb.Diffusion;
mParams.DecayTime = props->Reverb.DecayTime;
mParams.HFDecayTime = hfDecayTime;
mParams.LFDecayTime = lfDecayTime;
mParams.HFReference = props->Reverb.HFReference;
mParams.LFReference = props->Reverb.LFReference;
}
@@ -1454,12 +1442,12 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t
VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo);
}
static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->mTempSamples;
ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->mMixBuffer;
ALsizei fadeCount = State->mFadeCount;
ALsizei offset = State->mOffset;
ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = mTempSamples;
ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = mMixBuffer;
ALsizei fadeCount = mFadeCount;
ALsizei offset = mOffset;
ALsizei base, c;
/* Process reverb for these samples. */
@@ -1470,9 +1458,9 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const
if(FADE_SAMPLES-fadeCount > 0)
{
todo = mini(todo, FADE_SAMPLES-fadeCount);
todo = mini(todo, State->mMaxUpdate[0]);
todo = mini(todo, mMaxUpdate[0]);
}
todo = mini(todo, State->mMaxUpdate[1]);
todo = mini(todo, mMaxUpdate[1]);
/* If this is not the final update, ensure the update size is a
* multiple of 4 for the SIMD mixers.
*/
@@ -1490,11 +1478,11 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const
for(c = 0;c < NUM_LINES;c++)
{
/* Band-pass the incoming samples. */
BiquadFilter_process(&State->mFilter[c].Lp, samples[0], afmt[c], todo);
BiquadFilter_process(&State->mFilter[c].Hp, samples[1], samples[0], todo);
BiquadFilter_process(&mFilter[c].Lp, samples[0], afmt[c], todo);
BiquadFilter_process(&mFilter[c].Hp, samples[1], samples[0], todo);
/* Feed the initial delay line. */
DelayLineIn(&State->mDelay, offset, c, samples[1], todo);
DelayLineIn(&mDelay, offset, c, samples[1], todo);
}
if(UNLIKELY(fadeCount < FADE_SAMPLES))
@@ -1502,21 +1490,21 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const
ALfloat fade = (ALfloat)fadeCount;
/* Generate early reflections. */
EarlyReflection_Faded(State, offset, todo, fade, samples);
EarlyReflection_Faded(this, offset, todo, fade, samples);
/* Mix the A-Format results to output, implicitly converting back
* to B-Format.
*/
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->mEarly.CurrentGain[c], State->mEarly.PanGain[c],
mEarly.CurrentGain[c], mEarly.PanGain[c],
SamplesToDo-base, base, todo
);
/* Generate and mix late reverb. */
LateReverb_Faded(State, offset, todo, fade, samples);
LateReverb_Faded(this, offset, todo, fade, samples);
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->mLate.CurrentGain[c], State->mLate.PanGain[c],
mLate.CurrentGain[c], mLate.PanGain[c],
SamplesToDo-base, base, todo
);
@@ -1528,35 +1516,35 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const
fadeCount = FADE_SAMPLES;
for(c = 0;c < NUM_LINES;c++)
{
State->mEarlyDelayTap[c][0] = State->mEarlyDelayTap[c][1];
State->mEarlyDelayCoeff[c][0] = State->mEarlyDelayCoeff[c][1];
State->mEarly.VecAp.Offset[c][0] = State->mEarly.VecAp.Offset[c][1];
State->mEarly.Offset[c][0] = State->mEarly.Offset[c][1];
State->mEarly.Coeff[c][0] = State->mEarly.Coeff[c][1];
State->mLateDelayTap[c][0] = State->mLateDelayTap[c][1];
State->mLate.VecAp.Offset[c][0] = State->mLate.VecAp.Offset[c][1];
State->mLate.Offset[c][0] = State->mLate.Offset[c][1];
State->mLate.T60[c].MidGain[0] = State->mLate.T60[c].MidGain[1];
mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1];
mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1];
mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1];
mEarly.Offset[c][0] = mEarly.Offset[c][1];
mEarly.Coeff[c][0] = mEarly.Coeff[c][1];
mLateDelayTap[c][0] = mLateDelayTap[c][1];
mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1];
mLate.Offset[c][0] = mLate.Offset[c][1];
mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1];
}
State->mLate.DensityGain[0] = State->mLate.DensityGain[1];
State->mMaxUpdate[0] = State->mMaxUpdate[1];
mLate.DensityGain[0] = mLate.DensityGain[1];
mMaxUpdate[0] = mMaxUpdate[1];
}
}
else
{
/* Generate and mix early reflections. */
EarlyReflection_Unfaded(State, offset, todo, samples);
EarlyReflection_Unfaded(this, offset, todo, samples);
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->mEarly.CurrentGain[c], State->mEarly.PanGain[c],
mEarly.CurrentGain[c], mEarly.PanGain[c],
SamplesToDo-base, base, todo
);
/* Generate and mix late reverb. */
LateReverb_Unfaded(State, offset, todo, samples);
LateReverb_Unfaded(this, offset, todo, samples);
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->mLate.CurrentGain[c], State->mLate.PanGain[c],
mLate.CurrentGain[c], mLate.PanGain[c],
SamplesToDo-base, base, todo
);
}
@@ -1566,21 +1554,17 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const
base += todo;
}
State->mOffset = offset;
State->mFadeCount = fadeCount;
mOffset = offset;
mFadeCount = fadeCount;
}
struct ReverbStateFactory final : public EffectStateFactory {
ALeffectState *create() override;
EffectState *create() override;
};
ALeffectState *ReverbStateFactory::create()
{
ReverbState *state;
NEW_OBJ0(state, ReverbState)();
return state;
}
EffectState *ReverbStateFactory::create()
{ return new ReverbState{}; }
EffectStateFactory *ReverbStateFactory_getFactory(void)
{
+15 -44
View File
@@ -8,58 +8,31 @@
#include "atomic.h"
struct ALeffectStateVtable;
struct ALeffectslot;
typedef struct ALeffectState {
RefCount Ref;
const struct ALeffectStateVtable *vtbl;
ALfloat (*OutBuffer)[BUFFERSIZE];
ALsizei OutChannels;
} ALeffectState;
struct EffectState {
RefCount mRef{1u};
void ALeffectState_Construct(ALeffectState *state);
void ALeffectState_Destruct(ALeffectState *state);
ALfloat (*mOutBuffer)[BUFFERSIZE]{nullptr};
ALsizei mOutChannels{0};
struct ALeffectStateVtable {
void (*const Destruct)(ALeffectState *state);
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props);
void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels);
virtual ~EffectState() = default;
void (*const Delete)(void *ptr);
virtual ALboolean deviceUpdate(ALCdevice *device) = 0;
virtual void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) = 0;
virtual void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) = 0;
void IncRef() noexcept;
void DecRef() noexcept;
};
/* Small hack to use a pointer-to-array types as a normal argument type.
* Shouldn't be used directly.
*/
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \
DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*RESTRICT, ALfloatBUFFERSIZE*RESTRICT, ALsizei) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
T##_ALeffectState_Destruct, \
\
T##_ALeffectState_deviceUpdate, \
T##_ALeffectState_update, \
T##_ALeffectState_process, \
\
T##_ALeffectState_Delete, \
}
struct EffectStateFactory {
virtual ~EffectStateFactory() { }
virtual ALeffectState *create() = 0;
virtual EffectState *create() = 0;
};
@@ -79,7 +52,7 @@ struct ALeffectslotProps {
ALenum Type;
ALeffectProps Props;
ALeffectState *State;
EffectState *State;
ATOMIC(struct ALeffectslotProps*) next;
};
@@ -93,7 +66,7 @@ struct ALeffectslot {
ALenum Type{AL_EFFECT_NULL};
ALeffectProps Props{};
ALeffectState *State{nullptr};
EffectState *State{nullptr};
} Effect;
ATOMIC(ALenum) PropsClean{AL_TRUE};
@@ -108,7 +81,7 @@ struct ALeffectslot {
ALenum EffectType{AL_EFFECT_NULL};
ALeffectProps EffectProps{};
ALeffectState *EffectState{nullptr};
EffectState *EffectState{nullptr};
ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */
ALfloat DecayTime{0.0f};
@@ -167,6 +140,4 @@ EffectStateFactory *DedicatedStateFactory_getFactory(void);
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
void ALeffectState_DecRef(ALeffectState *state);
#endif
+2 -1
View File
@@ -206,6 +206,7 @@ struct ALCbackend;
struct ALbuffer;
struct ALeffect;
struct ALfilter;
struct EffectState;
#define DEFAULT_OUTPUT_RATE (44100)
@@ -755,7 +756,7 @@ typedef struct AsyncEvent {
ALuint param;
ALchar msg[1008];
} user;
struct ALeffectState *EffectState;
EffectState *mEffectState;
} u;
} AsyncEvent;
#define ASYNC_EVENT(t) { t, { 0 } }
+22 -37
View File
@@ -74,8 +74,6 @@ static inline EffectStateFactory *getFactoryByType(ALenum type)
return nullptr;
}
static void ALeffectState_IncRef(ALeffectState *state);
static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
{
@@ -483,7 +481,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
ALCdevice *Device = Context->Device;
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
struct ALeffectslotProps *props;
ALeffectState *State;
EffectState *State;
if(newtype != EffectSlot->Effect.Type)
{
@@ -498,13 +496,13 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
START_MIXER_MODE();
almtx_lock(&Device->BackendLock);
State->OutBuffer = Device->Dry.Buffer;
State->OutChannels = Device->Dry.NumChannels;
if(V(State,deviceUpdate)(Device) == AL_FALSE)
State->mOutBuffer = Device->Dry.Buffer;
State->mOutChannels = Device->Dry.NumChannels;
if(State->deviceUpdate(Device) == AL_FALSE)
{
almtx_unlock(&Device->BackendLock);
LEAVE_MIXER_MODE();
ALeffectState_DecRef(State);
State->DecRef();
return AL_OUT_OF_MEMORY;
}
almtx_unlock(&Device->BackendLock);
@@ -521,7 +519,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
EffectSlot->Effect.Props = effect->Props;
}
ALeffectState_DecRef(EffectSlot->Effect.State);
EffectSlot->Effect.State->DecRef();
EffectSlot->Effect.State = State;
}
else if(effect)
@@ -532,7 +530,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
while(props)
{
if(props->State)
ALeffectState_DecRef(props->State);
props->State->DecRef();
props->State = nullptr;
props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
}
@@ -541,30 +539,17 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
}
static void ALeffectState_IncRef(ALeffectState *state)
void EffectState::IncRef() noexcept
{
auto ref = IncrementRef(&state->Ref);
TRACEREF("%p increasing refcount to %u\n", state, ref);
auto ref = IncrementRef(&mRef);
TRACEREF("%p increasing refcount to %u\n", this, ref);
}
void ALeffectState_DecRef(ALeffectState *state)
{
auto ref = DecrementRef(&state->Ref);
TRACEREF("%p decreasing refcount to %u\n", state, ref);
if(ref == 0) DELETE_OBJ(state);
}
void ALeffectState_Construct(ALeffectState *state)
{
InitRef(&state->Ref, 1);
state->OutBuffer = nullptr;
state->OutChannels = 0;
}
void ALeffectState_Destruct(ALeffectState *UNUSED(state))
void EffectState::DecRef() noexcept
{
auto ref = DecrementRef(&mRef);
TRACEREF("%p decreasing refcount to %u\n", this, ref);
if(ref == 0) delete this;
}
@@ -664,7 +649,7 @@ ALenum InitEffectSlot(ALeffectslot *slot)
slot->Effect.State = factory->create();
if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
ALeffectState_IncRef(slot->Effect.State);
slot->Effect.State->IncRef();
slot->Params.EffectState = slot->Effect.State;
return AL_NO_ERROR;
}
@@ -674,21 +659,21 @@ ALeffectslot::~ALeffectslot()
struct ALeffectslotProps *props{Update.load()};
if(props)
{
if(props->State) ALeffectState_DecRef(props->State);
if(props->State) props->State->DecRef();
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
if(Effect.State)
ALeffectState_DecRef(Effect.State);
Effect.State->DecRef();
if(Params.EffectState)
ALeffectState_DecRef(Params.EffectState);
Params.EffectState->DecRef();
}
void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
{
struct ALeffectslotProps *props;
ALeffectState *oldstate;
EffectState *oldstate;
/* Get an unused property container, or allocate a new one as needed. */
props = context->FreeEffectslotProps.load(std::memory_order_relaxed);
@@ -712,7 +697,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
/* Swap out any stale effect state object there may be in the container, to
* delete it.
*/
ALeffectState_IncRef(slot->Effect.State);
slot->Effect.State->IncRef();
oldstate = props->State;
props->State = slot->Effect.State;
@@ -724,13 +709,13 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
* freelist.
*/
if(props->State)
ALeffectState_DecRef(props->State);
props->State->DecRef();
props->State = nullptr;
AtomicReplaceHead(context->FreeEffectslotProps, props);
}
if(oldstate)
ALeffectState_DecRef(oldstate);
oldstate->DecRef();
}
void UpdateAllEffectSlotProps(ALCcontext *context)
+1 -1
View File
@@ -34,7 +34,7 @@ static int EventThread(ALCcontext *context)
if(evt.EnumType == EventType_ReleaseEffectState)
{
ALeffectState_DecRef(evt.u.EffectState);
evt.u.mEffectState->DecRef();
continue;
}