Pass a span for the biquad filter input
This commit is contained in:
parent
36c745a514
commit
f153def941
@ -20,11 +20,10 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "al/auxeffectslot.h"
|
#include "al/auxeffectslot.h"
|
||||||
#include "alcmain.h"
|
#include "alcmain.h"
|
||||||
#include "alcontext.h"
|
#include "alcontext.h"
|
||||||
@ -114,26 +113,25 @@ void DistortionState::process(const size_t samplesToDo, const al::span<const Flo
|
|||||||
* (which is fortunately first step of distortion). So combine three
|
* (which is fortunately first step of distortion). So combine three
|
||||||
* operations into the one.
|
* operations into the one.
|
||||||
*/
|
*/
|
||||||
mLowpass.process(mBuffer[1], mBuffer[0], todo);
|
mLowpass.process({mBuffer[0], todo}, mBuffer[1]);
|
||||||
|
|
||||||
/* Second step, do distortion using waveshaper function to emulate
|
/* Second step, do distortion using waveshaper function to emulate
|
||||||
* signal processing during tube overdriving. Three steps of
|
* signal processing during tube overdriving. Three steps of
|
||||||
* waveshaping are intended to modify waveform without boost/clipping/
|
* waveshaping are intended to modify waveform without boost/clipping/
|
||||||
* attenuation process.
|
* attenuation process.
|
||||||
*/
|
*/
|
||||||
for(size_t i{0u};i < todo;i++)
|
auto proc_sample = [fc](float smp) -> float
|
||||||
{
|
{
|
||||||
ALfloat smp{mBuffer[1][i]};
|
smp = (1.0f + fc) * smp/(1.0f + fc*std::abs(smp));
|
||||||
|
smp = (1.0f + fc) * smp/(1.0f + fc*std::abs(smp)) * -1.0f;
|
||||||
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
|
smp = (1.0f + fc) * smp/(1.0f + fc*std::abs(smp));
|
||||||
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
|
return smp;
|
||||||
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
|
};
|
||||||
|
std::transform(std::begin(mBuffer[1]), std::begin(mBuffer[1])+todo, std::begin(mBuffer[0]),
|
||||||
mBuffer[0][i] = smp;
|
proc_sample);
|
||||||
}
|
|
||||||
|
|
||||||
/* Third step, do bandpass filtering of distorted signal. */
|
/* Third step, do bandpass filtering of distorted signal. */
|
||||||
mBandpass.process(mBuffer[1], mBuffer[0], todo);
|
mBandpass.process({mBuffer[0], todo}, mBuffer[1]);
|
||||||
|
|
||||||
todo >>= 2;
|
todo >>= 2;
|
||||||
const ALfloat *outgains{mGain};
|
const ALfloat *outgains{mGain};
|
||||||
|
@ -117,25 +117,26 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot,
|
|||||||
|
|
||||||
/* Calculate coefficients for the each type of filter. Note that the shelf
|
/* Calculate coefficients for the each type of filter. Note that the shelf
|
||||||
* and peaking filters' gain is for the centerpoint of the transition band,
|
* and peaking filters' gain is for the centerpoint of the transition band,
|
||||||
* meaning its dB needs to be doubled for the shelf or peak to reach the
|
* while the effect property gains are for the shelf/peak itself. So the
|
||||||
* provided gain.
|
* property gains need their dB halved (sqrt of linear gain) for the
|
||||||
|
* shelf/peak to reach the provided gain.
|
||||||
*/
|
*/
|
||||||
gain = maxf(std::sqrt(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */
|
gain = std::sqrt(props->Equalizer.LowGain);
|
||||||
f0norm = props->Equalizer.LowCutoff/frequency;
|
f0norm = props->Equalizer.LowCutoff / frequency;
|
||||||
mChans[0].filter[0].setParamsFromSlope(BiquadType::LowShelf, f0norm, gain, 0.75f);
|
mChans[0].filter[0].setParamsFromSlope(BiquadType::LowShelf, f0norm, gain, 0.75f);
|
||||||
|
|
||||||
gain = maxf(std::sqrt(props->Equalizer.Mid1Gain), 0.0625f);
|
gain = std::sqrt(props->Equalizer.Mid1Gain);
|
||||||
f0norm = props->Equalizer.Mid1Center/frequency;
|
f0norm = props->Equalizer.Mid1Center / frequency;
|
||||||
mChans[0].filter[1].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
|
mChans[0].filter[1].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
|
||||||
props->Equalizer.Mid1Width);
|
props->Equalizer.Mid1Width);
|
||||||
|
|
||||||
gain = maxf(std::sqrt(props->Equalizer.Mid2Gain), 0.0625f);
|
gain = std::sqrt(props->Equalizer.Mid2Gain);
|
||||||
f0norm = props->Equalizer.Mid2Center/frequency;
|
f0norm = props->Equalizer.Mid2Center / frequency;
|
||||||
mChans[0].filter[2].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
|
mChans[0].filter[2].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
|
||||||
props->Equalizer.Mid2Width);
|
props->Equalizer.Mid2Width);
|
||||||
|
|
||||||
gain = maxf(std::sqrt(props->Equalizer.HighGain), 0.0625f);
|
gain = std::sqrt(props->Equalizer.HighGain);
|
||||||
f0norm = props->Equalizer.HighCutoff/frequency;
|
f0norm = props->Equalizer.HighCutoff / frequency;
|
||||||
mChans[0].filter[3].setParamsFromSlope(BiquadType::HighShelf, f0norm, gain, 0.75f);
|
mChans[0].filter[3].setParamsFromSlope(BiquadType::HighShelf, f0norm, gain, 0.75f);
|
||||||
|
|
||||||
/* Copy the filter coefficients for the other input channels. */
|
/* Copy the filter coefficients for the other input channels. */
|
||||||
@ -157,16 +158,17 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot,
|
|||||||
|
|
||||||
void EqualizerState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
|
void EqualizerState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
|
||||||
{
|
{
|
||||||
|
const al::span<float> buffer{mSampleBuffer, samplesToDo};
|
||||||
auto chandata = std::addressof(mChans[0]);
|
auto chandata = std::addressof(mChans[0]);
|
||||||
for(const auto &input : samplesIn)
|
for(const auto &input : samplesIn)
|
||||||
{
|
{
|
||||||
chandata->filter[0].process(mSampleBuffer, input.data(), samplesToDo);
|
chandata->filter[0].process({input.data(), samplesToDo}, buffer.begin());
|
||||||
chandata->filter[1].process(mSampleBuffer, mSampleBuffer, samplesToDo);
|
chandata->filter[1].process(buffer, buffer.begin());
|
||||||
chandata->filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo);
|
chandata->filter[2].process(buffer, buffer.begin());
|
||||||
chandata->filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo);
|
chandata->filter[3].process(buffer, buffer.begin());
|
||||||
|
|
||||||
MixSamples({mSampleBuffer, samplesToDo}, samplesOut, chandata->CurrentGains,
|
MixSamples(buffer, samplesOut, chandata->CurrentGains, chandata->TargetGains, samplesToDo,
|
||||||
chandata->TargetGains, samplesToDo, 0);
|
0u);
|
||||||
++chandata;
|
++chandata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ void ModulatorState::process(const size_t samplesToDo, const al::span<const Floa
|
|||||||
{
|
{
|
||||||
alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES];
|
alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES];
|
||||||
|
|
||||||
chandata->Filter.process(temps, &input[base], td);
|
chandata->Filter.process({&input[base], td}, temps);
|
||||||
for(size_t i{0u};i < td;i++)
|
for(size_t i{0u};i < td;i++)
|
||||||
temps[i] *= modsamples[i];
|
temps[i] *= modsamples[i];
|
||||||
|
|
||||||
|
@ -286,10 +286,10 @@ struct T60Filter {
|
|||||||
const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm);
|
const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm);
|
||||||
|
|
||||||
/* Applies the two T60 damping filter sections. */
|
/* Applies the two T60 damping filter sections. */
|
||||||
void process(ALfloat *samples, const size_t todo)
|
void process(const al::span<float> samples)
|
||||||
{
|
{
|
||||||
HFFilter.process(samples, samples, todo);
|
HFFilter.process(samples, samples.begin());
|
||||||
LFFilter.process(samples, samples, todo);
|
LFFilter.process(samples, samples.begin());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1359,7 +1359,7 @@ void ReverbState::lateUnfaded(const size_t offset, const size_t todo)
|
|||||||
late_delay.Line[late_feedb_tap++][j]*midGain;
|
late_delay.Line[late_feedb_tap++][j]*midGain;
|
||||||
} while(--td);
|
} while(--td);
|
||||||
}
|
}
|
||||||
mLate.T60[j].process(mTempSamples[j].data(), todo);
|
mLate.T60[j].process({mTempSamples[j].data(), todo});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply a vector all-pass to improve micro-surface diffusion, and write
|
/* Apply a vector all-pass to improve micro-surface diffusion, and write
|
||||||
@ -1420,7 +1420,7 @@ void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloa
|
|||||||
late_delay.Line[late_feedb_tap1++][j]*gfade1;
|
late_delay.Line[late_feedb_tap1++][j]*gfade1;
|
||||||
} while(--td);
|
} while(--td);
|
||||||
}
|
}
|
||||||
mLate.T60[j].process(mTempSamples[j].data(), todo);
|
mLate.T60[j].process({mTempSamples[j].data(), todo});
|
||||||
}
|
}
|
||||||
|
|
||||||
mLate.VecAp.processFaded(mTempSamples, offset, mixX, mixY, fade, fadeStep, todo);
|
mLate.VecAp.processFaded(mTempSamples, offset, mixX, mixY, fade, fadeStep, todo);
|
||||||
@ -1445,9 +1445,9 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
|
|||||||
MixRowSamples(tmpspan, {B2A[c], numInput}, samplesIn[0].data(), samplesIn[0].size());
|
MixRowSamples(tmpspan, {B2A[c], numInput}, samplesIn[0].data(), samplesIn[0].size());
|
||||||
|
|
||||||
/* Band-pass the incoming samples and feed the initial delay line. */
|
/* Band-pass the incoming samples and feed the initial delay line. */
|
||||||
mFilter[c].Lp.process(mTempLine.data(), mTempLine.data(), samplesToDo);
|
mFilter[c].Lp.process(tmpspan, tmpspan.begin());
|
||||||
mFilter[c].Hp.process(mTempLine.data(), mTempLine.data(), samplesToDo);
|
mFilter[c].Hp.process(tmpspan, tmpspan.begin());
|
||||||
mDelay.write(offset, c, mTempLine.data(), samplesToDo);
|
mDelay.write(offset, c, tmpspan.cbegin(), samplesToDo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process reverb for these samples. */
|
/* Process reverb for these samples. */
|
||||||
|
@ -89,10 +89,8 @@ void BiquadFilterR<Real>::setParams(BiquadType type, Real f0norm, Real gain, Rea
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Real>
|
template<typename Real>
|
||||||
void BiquadFilterR<Real>::process(Real *dst, const Real *src, const size_t numsamples)
|
void BiquadFilterR<Real>::process(const al::span<const Real> src, Real *dst)
|
||||||
{
|
{
|
||||||
ASSUME(numsamples > 0);
|
|
||||||
|
|
||||||
const Real b0{mB0};
|
const Real b0{mB0};
|
||||||
const Real b1{mB1};
|
const Real b1{mB1};
|
||||||
const Real b2{mB2};
|
const Real b2{mB2};
|
||||||
@ -111,12 +109,12 @@ void BiquadFilterR<Real>::process(Real *dst, const Real *src, const size_t numsa
|
|||||||
*/
|
*/
|
||||||
auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real
|
auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real
|
||||||
{
|
{
|
||||||
Real output = input*b0 + z1;
|
const Real output{input*b0 + z1};
|
||||||
z1 = input*b1 - output*a1 + z2;
|
z1 = input*b1 - output*a1 + z2;
|
||||||
z2 = input*b2 - output*a2;
|
z2 = input*b2 - output*a2;
|
||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
std::transform(src, src+numsamples, dst, proc_sample);
|
std::transform(src.cbegin(), src.cend(), dst, proc_sample);
|
||||||
|
|
||||||
mZ1 = z1;
|
mZ1 = z1;
|
||||||
mZ2 = z2;
|
mZ2 = z2;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "alspan.h"
|
||||||
#include "math_defs.h"
|
#include "math_defs.h"
|
||||||
|
|
||||||
|
|
||||||
@ -114,14 +115,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void process(Real *dst, const Real *src, const size_t numsamples);
|
void process(const al::span<const Real> src, Real *dst);
|
||||||
|
|
||||||
/* Rather hacky. It's just here to support "manual" processing. */
|
/* Rather hacky. It's just here to support "manual" processing. */
|
||||||
std::pair<Real,Real> getComponents() const noexcept { return {mZ1, mZ2}; }
|
std::pair<Real,Real> getComponents() const noexcept { return {mZ1, mZ2}; }
|
||||||
void setComponents(Real z1, Real z2) noexcept { mZ1 = z1; mZ2 = z2; }
|
void setComponents(Real z1, Real z2) noexcept { mZ1 = z1; mZ2 = z2; }
|
||||||
Real processOne(const Real in, Real &z1, Real &z2) const noexcept
|
Real processOne(const Real in, Real &z1, Real &z2) const noexcept
|
||||||
{
|
{
|
||||||
Real out{in*mB0 + z1};
|
const Real out{in*mB0 + z1};
|
||||||
z1 = in*mB1 - out*mA1 + z2;
|
z1 = in*mB1 - out*mA1 + z2;
|
||||||
z2 = in*mB2 - out*mA2;
|
z2 = in*mB2 - out*mA2;
|
||||||
return out;
|
return out;
|
||||||
|
@ -284,31 +284,31 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst,
|
const float *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, float *dst,
|
||||||
const ALfloat *src, const size_t numsamples, int type)
|
const al::span<const float> src, int type)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case AF_None:
|
case AF_None:
|
||||||
lpfilter->clear();
|
lpfilter->clear();
|
||||||
hpfilter->clear();
|
hpfilter->clear();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AF_LowPass:
|
case AF_LowPass:
|
||||||
lpfilter->process(dst, src, numsamples);
|
lpfilter->process(src, dst);
|
||||||
hpfilter->clear();
|
hpfilter->clear();
|
||||||
return dst;
|
return dst;
|
||||||
case AF_HighPass:
|
case AF_HighPass:
|
||||||
lpfilter->clear();
|
lpfilter->clear();
|
||||||
hpfilter->process(dst, src, numsamples);
|
hpfilter->process(src, dst);
|
||||||
return dst;
|
return dst;
|
||||||
|
|
||||||
case AF_BandPass:
|
case AF_BandPass:
|
||||||
lpfilter->process(dst, src, numsamples);
|
lpfilter->process(src, dst);
|
||||||
hpfilter->process(dst, dst, numsamples);
|
hpfilter->process({dst, src.size()}, dst);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
return src;
|
return src.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -694,7 +694,7 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
|
|||||||
{
|
{
|
||||||
DirectParams &parms = chandata.mDryParams;
|
DirectParams &parms = chandata.mDryParams;
|
||||||
const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf,
|
const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf,
|
||||||
ResampledData, DstBufferSize, mDirect.FilterType)};
|
{ResampledData, DstBufferSize}, mDirect.FilterType)};
|
||||||
|
|
||||||
if((mFlags&VOICE_HAS_HRTF))
|
if((mFlags&VOICE_HAS_HRTF))
|
||||||
{
|
{
|
||||||
@ -726,7 +726,7 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
|
|||||||
|
|
||||||
SendParams &parms = chandata.mWetParams[send];
|
SendParams &parms = chandata.mWetParams[send];
|
||||||
const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf,
|
const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf,
|
||||||
ResampledData, DstBufferSize, mSend[send].FilterType)};
|
{ResampledData, DstBufferSize}, mSend[send].FilterType)};
|
||||||
|
|
||||||
const float *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ?
|
const float *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ?
|
||||||
SilentTarget.data() : parms.Gains.Target.data()};
|
SilentTarget.data() : parms.Gains.Target.data()};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user