aboutsummaryrefslogtreecommitdiffstats
path: root/alc/effects
diff options
context:
space:
mode:
Diffstat (limited to 'alc/effects')
-rw-r--r--alc/effects/autowah.cpp45
-rw-r--r--alc/effects/compressor.cpp33
-rw-r--r--alc/effects/equalizer.cpp56
-rw-r--r--alc/effects/modulator.cpp46
-rw-r--r--alc/effects/vmorpher.cpp43
5 files changed, 140 insertions, 83 deletions
diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp
index b5e259f4..8dfee45d 100644
--- a/alc/effects/autowah.cpp
+++ b/alc/effects/autowah.cpp
@@ -65,14 +65,16 @@ struct AutowahState final : public EffectState {
} mEnv[BufferLineSize];
struct {
+ uint mTargetChannel{INVALID_CHANNEL_INDEX};
+
/* Effect filters' history. */
struct {
float z1, z2;
- } Filter;
+ } mFilter;
/* Effect gains for each output channel */
- float CurrentGains[MaxAmbiChannels];
- float TargetGains[MaxAmbiChannels];
+ float mCurrentGain;
+ float mTargetGain;
} mChans[MaxAmbiChannels];
/* Effects buffers */
@@ -108,9 +110,10 @@ void AutowahState::deviceUpdate(const DeviceBase*, const Buffer&)
for(auto &chan : mChans)
{
- std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f);
- chan.Filter.z1 = 0.0f;
- chan.Filter.z2 = 0.0f;
+ chan.mTargetChannel = INVALID_CHANNEL_INDEX;
+ chan.mFilter.z1 = 0.0f;
+ chan.mFilter.z2 = 0.0f;
+ chan.mCurrentGain = 0.0f;
}
}
@@ -131,9 +134,12 @@ void AutowahState::update(const ContextBase *context, const EffectSlot *slot,
mBandwidthNorm = (MaxFreq-MinFreq) / frequency;
mOutTarget = target.Main->Buffer;
- auto set_gains = [slot,target](auto &chan, al::span<const float,MaxAmbiChannels> coeffs)
- { ComputePanGains(target.Main, coeffs.data(), slot->Gain, chan.TargetGains); };
- SetAmbiPanIdentity(std::begin(mChans), slot->Wet.Buffer.size(), set_gains);
+ auto set_channel = [this](size_t idx, uint target, float gain)
+ {
+ mChans[idx].mTargetChannel = target;
+ mChans[idx].mTargetGain = gain;
+ };
+ target.Main->setAmbiMixParams(slot->Wet, slot->Gain, set_channel);
}
void AutowahState::process(const size_t samplesToDo,
@@ -165,17 +171,24 @@ void AutowahState::process(const size_t samplesToDo,
}
mEnvDelay = env_delay;
- auto chandata = std::addressof(mChans[0]);
+ auto chandata = std::begin(mChans);
for(const auto &insamples : samplesIn)
{
+ const size_t outidx{chandata->mTargetChannel};
+ if(outidx == INVALID_CHANNEL_INDEX)
+ {
+ ++chandata;
+ continue;
+ }
+
/* This effectively inlines BiquadFilter_setParams for a peaking
* filter and BiquadFilter_processC. The alpha and cosine components
* for the filter coefficients were previously calculated with the
* envelope. Because the filter changes for each sample, the
* coefficients are transient and don't need to be held.
*/
- float z1{chandata->Filter.z1};
- float z2{chandata->Filter.z2};
+ float z1{chandata->mFilter.z1};
+ float z2{chandata->mFilter.z2};
for(size_t i{0u};i < samplesToDo;i++)
{
@@ -197,12 +210,12 @@ void AutowahState::process(const size_t samplesToDo,
z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]);
mBufferOut[i] = output;
}
- chandata->Filter.z1 = z1;
- chandata->Filter.z2 = z2;
+ chandata->mFilter.z1 = z1;
+ chandata->mFilter.z2 = z2;
/* Now, mix the processed sound data to the output. */
- MixSamples({mBufferOut, samplesToDo}, samplesOut, chandata->CurrentGains,
- chandata->TargetGains, samplesToDo, 0);
+ MixSamples({mBufferOut, samplesToDo}, {&samplesOut[outidx], 1}, &chandata->mCurrentGain,
+ &chandata->mTargetGain, samplesToDo, 0);
++chandata;
}
}
diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp
index 6202e58e..a4333539 100644
--- a/alc/effects/compressor.cpp
+++ b/alc/effects/compressor.cpp
@@ -64,7 +64,10 @@ namespace {
struct CompressorState final : public EffectState {
/* Effect gains for each channel */
- float mGain[MaxAmbiChannels][MaxAmbiChannels]{};
+ struct {
+ uint mTarget{INVALID_CHANNEL_INDEX};
+ float mGain{1.0f};
+ } mChans[MaxAmbiChannels];
/* Effect parameters */
bool mEnabled{true};
@@ -103,9 +106,12 @@ void CompressorState::update(const ContextBase*, const EffectSlot *slot,
mEnabled = props->Compressor.OnOff;
mOutTarget = target.Main->Buffer;
- auto set_gains = [slot,target](auto &gains, al::span<const float,MaxAmbiChannels> coeffs)
- { ComputePanGains(target.Main, coeffs.data(), slot->Gain, gains); };
- SetAmbiPanIdentity(std::begin(mGain), slot->Wet.Buffer.size(), set_gains);
+ auto set_channel = [this](size_t idx, uint target, float gain)
+ {
+ mChans[idx].mTarget = target;
+ mChans[idx].mGain = gain;
+ };
+ target.Main->setAmbiMixParams(slot->Wet, slot->Gain, set_channel);
}
void CompressorState::process(const size_t samplesToDo,
@@ -158,19 +164,22 @@ void CompressorState::process(const size_t samplesToDo,
mEnvFollower = env;
/* Now compress the signal amplitude to output. */
- auto changains = std::addressof(mGain[0]);
+ auto chan = std::cbegin(mChans);
for(const auto &input : samplesIn)
{
- const float *outgains{*(changains++)};
- for(FloatBufferLine &output : samplesOut)
+ const size_t outidx{chan->mTarget};
+ if(outidx != INVALID_CHANNEL_INDEX)
{
- const float gain{*(outgains++)};
+ const float *RESTRICT src{input.data() + base};
+ float *RESTRICT dst{samplesOut[outidx].data() + base};
+ const float gain{chan->mGain};
if(!(std::fabs(gain) > GainSilenceThreshold))
- continue;
-
- for(size_t i{0u};i < td;i++)
- output[base+i] += input[base+i] * gains[i] * gain;
+ {
+ for(size_t i{0u};i < td;i++)
+ dst[i] += src[i] * gains[i] * gain;
+ }
}
+ ++chan;
}
base += td;
diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp
index 4bce34a2..de067911 100644
--- a/alc/effects/equalizer.cpp
+++ b/alc/effects/equalizer.cpp
@@ -87,12 +87,14 @@ namespace {
struct EqualizerState final : public EffectState {
struct {
+ uint mTargetChannel{INVALID_CHANNEL_INDEX};
+
/* Effect parameters */
- BiquadFilter filter[4];
+ BiquadFilter mFilter[4];
/* Effect gains for each channel */
- float CurrentGains[MaxAmbiChannels]{};
- float TargetGains[MaxAmbiChannels]{};
+ float mCurrentGain{};
+ float mTargetGain{};
} mChans[MaxAmbiChannels];
alignas(16) FloatBufferLine mSampleBuffer{};
@@ -111,8 +113,10 @@ void EqualizerState::deviceUpdate(const DeviceBase*, const Buffer&)
{
for(auto &e : mChans)
{
- std::for_each(std::begin(e.filter), std::end(e.filter), std::mem_fn(&BiquadFilter::clear));
- std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f);
+ e.mTargetChannel = INVALID_CHANNEL_INDEX;
+ std::for_each(std::begin(e.mFilter), std::end(e.mFilter),
+ std::mem_fn(&BiquadFilter::clear));
+ e.mCurrentGain = 0.0f;
}
}
@@ -131,48 +135,56 @@ void EqualizerState::update(const ContextBase *context, const EffectSlot *slot,
*/
gain = std::sqrt(props->Equalizer.LowGain);
f0norm = props->Equalizer.LowCutoff / frequency;
- mChans[0].filter[0].setParamsFromSlope(BiquadType::LowShelf, f0norm, gain, 0.75f);
+ mChans[0].mFilter[0].setParamsFromSlope(BiquadType::LowShelf, f0norm, gain, 0.75f);
gain = std::sqrt(props->Equalizer.Mid1Gain);
f0norm = props->Equalizer.Mid1Center / frequency;
- mChans[0].filter[1].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
+ mChans[0].mFilter[1].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
props->Equalizer.Mid1Width);
gain = std::sqrt(props->Equalizer.Mid2Gain);
f0norm = props->Equalizer.Mid2Center / frequency;
- mChans[0].filter[2].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
+ mChans[0].mFilter[2].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
props->Equalizer.Mid2Width);
gain = std::sqrt(props->Equalizer.HighGain);
f0norm = props->Equalizer.HighCutoff / frequency;
- mChans[0].filter[3].setParamsFromSlope(BiquadType::HighShelf, f0norm, gain, 0.75f);
+ mChans[0].mFilter[3].setParamsFromSlope(BiquadType::HighShelf, f0norm, gain, 0.75f);
/* Copy the filter coefficients for the other input channels. */
for(size_t i{1u};i < slot->Wet.Buffer.size();++i)
{
- mChans[i].filter[0].copyParamsFrom(mChans[0].filter[0]);
- mChans[i].filter[1].copyParamsFrom(mChans[0].filter[1]);
- mChans[i].filter[2].copyParamsFrom(mChans[0].filter[2]);
- mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]);
+ mChans[i].mFilter[0].copyParamsFrom(mChans[0].mFilter[0]);
+ mChans[i].mFilter[1].copyParamsFrom(mChans[0].mFilter[1]);
+ mChans[i].mFilter[2].copyParamsFrom(mChans[0].mFilter[2]);
+ mChans[i].mFilter[3].copyParamsFrom(mChans[0].mFilter[3]);
}
mOutTarget = target.Main->Buffer;
- auto set_gains = [slot,target](auto &chan, al::span<const float,MaxAmbiChannels> coeffs)
- { ComputePanGains(target.Main, coeffs.data(), slot->Gain, chan.TargetGains); };
- SetAmbiPanIdentity(std::begin(mChans), slot->Wet.Buffer.size(), set_gains);
+ auto set_channel = [this](size_t idx, uint target, float gain)
+ {
+ mChans[idx].mTargetChannel = target;
+ mChans[idx].mTargetGain = gain;
+ };
+ target.Main->setAmbiMixParams(slot->Wet, slot->Gain, set_channel);
}
void EqualizerState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
{
const al::span<float> buffer{mSampleBuffer.data(), samplesToDo};
- auto chan = std::addressof(mChans[0]);
+ auto chan = std::begin(mChans);
for(const auto &input : samplesIn)
{
- const al::span<const float> inbuf{input.data(), samplesToDo};
- DualBiquad{chan->filter[0], chan->filter[1]}.process(inbuf, buffer.begin());
- DualBiquad{chan->filter[2], chan->filter[3]}.process(buffer, buffer.begin());
-
- MixSamples(buffer, samplesOut, chan->CurrentGains, chan->TargetGains, samplesToDo, 0u);
+ const size_t outidx{chan->mTargetChannel};
+ if(outidx != INVALID_CHANNEL_INDEX)
+ {
+ const al::span<const float> inbuf{input.data(), samplesToDo};
+ DualBiquad{chan->mFilter[0], chan->mFilter[1]}.process(inbuf, buffer.begin());
+ DualBiquad{chan->mFilter[2], chan->mFilter[3]}.process(buffer, buffer.begin());
+
+ MixSamples(buffer, {&samplesOut[outidx], 1}, &chan->mCurrentGain, &chan->mTargetGain,
+ samplesToDo, 0u);
+ }
++chan;
}
}
diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp
index c854f1e9..29009247 100644
--- a/alc/effects/modulator.cpp
+++ b/alc/effects/modulator.cpp
@@ -84,10 +84,12 @@ struct ModulatorState final : public EffectState {
uint mStep{1};
struct {
- BiquadFilter Filter;
+ uint mTargetChannel{INVALID_CHANNEL_INDEX};
- float CurrentGains[MaxAmbiChannels]{};
- float TargetGains[MaxAmbiChannels]{};
+ BiquadFilter mFilter;
+
+ float mCurrentGain{};
+ float mTargetGain{};
} mChans[MaxAmbiChannels];
@@ -104,8 +106,9 @@ void ModulatorState::deviceUpdate(const DeviceBase*, const Buffer&)
{
for(auto &e : mChans)
{
- e.Filter.clear();
- std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f);
+ e.mTargetChannel = INVALID_CHANNEL_INDEX;
+ e.mFilter.clear();
+ e.mCurrentGain = 0.0f;
}
}
@@ -129,14 +132,17 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
float f0norm{props->Modulator.HighPassCutoff / static_cast<float>(device->Frequency)};
f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f);
/* Bandwidth value is constant in octaves. */
- mChans[0].Filter.setParamsFromBandwidth(BiquadType::HighPass, f0norm, 1.0f, 0.75f);
+ mChans[0].mFilter.setParamsFromBandwidth(BiquadType::HighPass, f0norm, 1.0f, 0.75f);
for(size_t i{1u};i < slot->Wet.Buffer.size();++i)
- mChans[i].Filter.copyParamsFrom(mChans[0].Filter);
+ mChans[i].mFilter.copyParamsFrom(mChans[0].mFilter);
mOutTarget = target.Main->Buffer;
- auto set_gains = [slot,target](auto &chan, al::span<const float,MaxAmbiChannels> coeffs)
- { ComputePanGains(target.Main, coeffs.data(), slot->Gain, chan.TargetGains); };
- SetAmbiPanIdentity(std::begin(mChans), slot->Wet.Buffer.size(), set_gains);
+ auto set_channel = [this](size_t idx, uint target, float gain)
+ {
+ mChans[idx].mTargetChannel = target;
+ mChans[idx].mTargetGain = gain;
+ };
+ target.Main->setAmbiMixParams(slot->Wet, slot->Gain, set_channel);
}
void ModulatorState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
@@ -153,14 +159,18 @@ void ModulatorState::process(const size_t samplesToDo, const al::span<const Floa
auto chandata = std::begin(mChans);
for(const auto &input : samplesIn)
{
- alignas(16) float temps[MAX_UPDATE_SAMPLES];
-
- chandata->Filter.process({&input[base], td}, temps);
- for(size_t i{0u};i < td;i++)
- temps[i] *= modsamples[i];
-
- MixSamples({temps, td}, samplesOut, chandata->CurrentGains, chandata->TargetGains,
- samplesToDo-base, base);
+ const size_t outidx{chandata->mTargetChannel};
+ if(outidx != INVALID_CHANNEL_INDEX)
+ {
+ alignas(16) float temps[MAX_UPDATE_SAMPLES];
+
+ chandata->mFilter.process({&input[base], td}, temps);
+ for(size_t i{0u};i < td;i++)
+ temps[i] *= modsamples[i];
+
+ MixSamples({temps, td}, {&samplesOut[outidx], 1}, &chandata->mCurrentGain,
+ &chandata->mTargetGain, samplesToDo-base, base);
+ }
++chandata;
}
diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp
index 9834c335..869c004e 100644
--- a/alc/effects/vmorpher.cpp
+++ b/alc/effects/vmorpher.cpp
@@ -143,12 +143,14 @@ struct FormantFilter
struct VmorpherState final : public EffectState {
struct {
+ uint mTargetChannel{INVALID_CHANNEL_INDEX};
+
/* Effect parameters */
- FormantFilter Formants[NUM_FILTERS][NUM_FORMANTS];
+ FormantFilter mFormants[NUM_FILTERS][NUM_FORMANTS];
/* Effect gains for each channel */
- float CurrentGains[MaxAmbiChannels]{};
- float TargetGains[MaxAmbiChannels]{};
+ float mCurrentGain{};
+ float mTargetGain{};
} mChans[MaxAmbiChannels];
void (*mGetSamples)(float*RESTRICT, uint, const uint, size_t){};
@@ -229,11 +231,12 @@ void VmorpherState::deviceUpdate(const DeviceBase*, const Buffer&)
{
for(auto &e : mChans)
{
- std::for_each(std::begin(e.Formants[VOWEL_A_INDEX]), std::end(e.Formants[VOWEL_A_INDEX]),
+ e.mTargetChannel = INVALID_CHANNEL_INDEX;
+ std::for_each(std::begin(e.mFormants[VOWEL_A_INDEX]), std::end(e.mFormants[VOWEL_A_INDEX]),
std::mem_fn(&FormantFilter::clear));
- std::for_each(std::begin(e.Formants[VOWEL_B_INDEX]), std::end(e.Formants[VOWEL_B_INDEX]),
+ std::for_each(std::begin(e.mFormants[VOWEL_B_INDEX]), std::end(e.mFormants[VOWEL_B_INDEX]),
std::mem_fn(&FormantFilter::clear));
- std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f);
+ e.mCurrentGain = 0.0f;
}
}
@@ -265,14 +268,17 @@ void VmorpherState::update(const ContextBase *context, const EffectSlot *slot,
/* Copy the filter coefficients to the input channels. */
for(size_t i{0u};i < slot->Wet.Buffer.size();++i)
{
- std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].Formants[VOWEL_A_INDEX]));
- std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].Formants[VOWEL_B_INDEX]));
+ std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].mFormants[VOWEL_A_INDEX]));
+ std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].mFormants[VOWEL_B_INDEX]));
}
mOutTarget = target.Main->Buffer;
- auto set_gains = [slot,target](auto &chan, al::span<const float,MaxAmbiChannels> coeffs)
- { ComputePanGains(target.Main, coeffs.data(), slot->Gain, chan.TargetGains); };
- SetAmbiPanIdentity(std::begin(mChans), slot->Wet.Buffer.size(), set_gains);
+ auto set_channel = [this](size_t idx, uint target, float gain)
+ {
+ mChans[idx].mTargetChannel = target;
+ mChans[idx].mTargetGain = gain;
+ };
+ target.Main->setAmbiMixParams(slot->Wet, slot->Gain, set_channel);
}
void VmorpherState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
@@ -291,8 +297,15 @@ void VmorpherState::process(const size_t samplesToDo, const al::span<const Float
auto chandata = std::begin(mChans);
for(const auto &input : samplesIn)
{
- auto& vowelA = chandata->Formants[VOWEL_A_INDEX];
- auto& vowelB = chandata->Formants[VOWEL_B_INDEX];
+ const size_t outidx{chandata->mTargetChannel};
+ if(outidx == INVALID_CHANNEL_INDEX)
+ {
+ ++chandata;
+ continue;
+ }
+
+ auto& vowelA = chandata->mFormants[VOWEL_A_INDEX];
+ auto& vowelB = chandata->mFormants[VOWEL_B_INDEX];
/* Process first vowel. */
std::fill_n(std::begin(mSampleBufferA), td, 0.0f);
@@ -313,8 +326,8 @@ void VmorpherState::process(const size_t samplesToDo, const al::span<const Float
blended[i] = lerpf(mSampleBufferA[i], mSampleBufferB[i], mLfo[i]);
/* Now, mix the processed sound data to the output. */
- MixSamples({blended, td}, samplesOut, chandata->CurrentGains, chandata->TargetGains,
- samplesToDo-base, base);
+ MixSamples({blended, td}, {&samplesOut[outidx], 1}, &chandata->mCurrentGain,
+ &chandata->mTargetGain, samplesToDo-base, base);
++chandata;
}