aboutsummaryrefslogtreecommitdiffstats
path: root/alc/effects
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-01-05 13:52:12 +0100
committerSven Göthel <[email protected]>2024-01-05 13:52:12 +0100
commitec98cdacc85ff0202852472c7756586437912f22 (patch)
tree42414746a27ab35cb8cdbc95af521d74821e57f4 /alc/effects
parentfd5269bec9a5fe4815974b1786a037e6a247bfd2 (diff)
parentb82cd2e60edb8fbe5fdd3567105ae76a016a554c (diff)
Merge remote-tracking branch 'upstream/master'HEADmaster
Diffstat (limited to 'alc/effects')
-rw-r--r--alc/effects/autowah.cpp86
-rw-r--r--alc/effects/base.h43
-rw-r--r--alc/effects/chorus.cpp117
-rw-r--r--alc/effects/compressor.cpp13
-rw-r--r--alc/effects/convolution.cpp160
-rw-r--r--alc/effects/dedicated.cpp94
-rw-r--r--alc/effects/distortion.cpp29
-rw-r--r--alc/effects/echo.cpp45
-rw-r--r--alc/effects/equalizer.cpp36
-rw-r--r--alc/effects/fshifter.cpp30
-rw-r--r--alc/effects/modulator.cpp24
-rw-r--r--alc/effects/null.cpp4
-rw-r--r--alc/effects/pshifter.cpp65
-rw-r--r--alc/effects/reverb.cpp368
-rw-r--r--alc/effects/vmorpher.cpp127
15 files changed, 638 insertions, 603 deletions
diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp
index 4f874ef2..424230e8 100644
--- a/alc/effects/autowah.cpp
+++ b/alc/effects/autowah.cpp
@@ -50,35 +50,37 @@ constexpr float QFactor{5.0f};
struct AutowahState final : public EffectState {
/* Effect parameters */
- float mAttackRate;
- float mReleaseRate;
- float mResonanceGain;
- float mPeakGain;
- float mFreqMinNorm;
- float mBandwidthNorm;
- float mEnvDelay;
+ float mAttackRate{};
+ float mReleaseRate{};
+ float mResonanceGain{};
+ float mPeakGain{};
+ float mFreqMinNorm{};
+ float mBandwidthNorm{};
+ float mEnvDelay{};
/* Filter components derived from the envelope. */
- struct {
- float cos_w0;
- float alpha;
- } mEnv[BufferLineSize];
+ struct FilterParam {
+ float cos_w0{};
+ float alpha{};
+ };
+ std::array<FilterParam,BufferLineSize> mEnv;
- struct {
+ struct ChannelData {
uint mTargetChannel{InvalidChannelIndex};
/* Effect filters' history. */
struct {
- float z1, z2;
+ float z1{}, z2{};
} mFilter;
/* Effect gains for each output channel */
- float mCurrentGain;
- float mTargetGain;
- } mChans[MaxAmbiChannels];
+ float mCurrentGain{};
+ float mTargetGain{};
+ };
+ std::array<ChannelData,MaxAmbiChannels> mChans;
/* Effects buffers */
- alignas(16) float mBufferOut[BufferLineSize];
+ alignas(16) FloatBufferLine mBufferOut{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -86,8 +88,6 @@ struct AutowahState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(AutowahState)
};
void AutowahState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -118,18 +118,19 @@ void AutowahState::deviceUpdate(const DeviceBase*, const BufferStorage*)
}
void AutowahState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<AutowahProps>(*props_);
const DeviceBase *device{context->mDevice};
const auto frequency = static_cast<float>(device->Frequency);
- const float ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)};
+ const float ReleaseTime{clampf(props.ReleaseTime, 0.001f, 1.0f)};
- mAttackRate = std::exp(-1.0f / (props->Autowah.AttackTime*frequency));
+ mAttackRate = std::exp(-1.0f / (props.AttackTime*frequency));
mReleaseRate = std::exp(-1.0f / (ReleaseTime*frequency));
/* 0-20dB Resonance Peak gain */
- mResonanceGain = std::sqrt(std::log10(props->Autowah.Resonance)*10.0f / 3.0f);
- mPeakGain = 1.0f - std::log10(props->Autowah.PeakGain / GainScale);
+ mResonanceGain = std::sqrt(std::log10(props.Resonance)*10.0f / 3.0f);
+ mPeakGain = 1.0f - std::log10(props.PeakGain / GainScale);
mFreqMinNorm = MinFreq / frequency;
mBandwidthNorm = (MaxFreq-MinFreq) / frequency;
@@ -155,17 +156,16 @@ void AutowahState::process(const size_t samplesToDo,
float env_delay{mEnvDelay};
for(size_t i{0u};i < samplesToDo;i++)
{
- float w0, sample, a;
-
/* Envelope follower described on the book: Audio Effects, Theory,
* Implementation and Application.
*/
- sample = peak_gain * std::fabs(samplesIn[0][i]);
- a = (sample > env_delay) ? attack_rate : release_rate;
+ const float sample{peak_gain * std::fabs(samplesIn[0][i])};
+ const float a{(sample > env_delay) ? attack_rate : release_rate};
env_delay = lerpf(sample, env_delay, a);
/* Calculate the cos and alpha components for this sample's filter. */
- w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * (al::numbers::pi_v<float>*2.0f);
+ const float w0{minf((bandwidth*env_delay + freq_min), 0.46f) *
+ (al::numbers::pi_v<float>*2.0f)};
mEnv[i].cos_w0 = std::cos(w0);
mEnv[i].alpha = std::sin(w0)/(2.0f * QFactor);
}
@@ -194,18 +194,18 @@ void AutowahState::process(const size_t samplesToDo,
{
const float alpha{mEnv[i].alpha};
const float cos_w0{mEnv[i].cos_w0};
- float input, output;
- float a[3], b[3];
-
- b[0] = 1.0f + alpha*res_gain;
- b[1] = -2.0f * cos_w0;
- b[2] = 1.0f - alpha*res_gain;
- a[0] = 1.0f + alpha/res_gain;
- a[1] = -2.0f * cos_w0;
- a[2] = 1.0f - alpha/res_gain;
-
- input = insamples[i];
- output = input*(b[0]/a[0]) + z1;
+
+ const std::array b{
+ 1.0f + alpha*res_gain,
+ -2.0f * cos_w0,
+ 1.0f - alpha*res_gain};
+ const std::array a{
+ 1.0f + alpha/res_gain,
+ -2.0f * cos_w0,
+ 1.0f - alpha/res_gain};
+
+ const float input{insamples[i]};
+ const float 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]);
mBufferOut[i] = output;
@@ -214,8 +214,8 @@ void AutowahState::process(const size_t samplesToDo,
chandata->mFilter.z2 = z2;
/* Now, mix the processed sound data to the output. */
- MixSamples({mBufferOut, samplesToDo}, samplesOut[outidx].data(), chandata->mCurrentGain,
- chandata->mTargetGain, samplesToDo);
+ MixSamples({mBufferOut.data(), samplesToDo}, samplesOut[outidx].data(),
+ chandata->mCurrentGain, chandata->mTargetGain, samplesToDo);
++chandata;
}
}
diff --git a/alc/effects/base.h b/alc/effects/base.h
index 95695857..9bbbfc71 100644
--- a/alc/effects/base.h
+++ b/alc/effects/base.h
@@ -4,23 +4,30 @@
#include "core/effects/base.h"
-EffectStateFactory *NullStateFactory_getFactory(void);
-EffectStateFactory *ReverbStateFactory_getFactory(void);
-EffectStateFactory *StdReverbStateFactory_getFactory(void);
-EffectStateFactory *AutowahStateFactory_getFactory(void);
-EffectStateFactory *ChorusStateFactory_getFactory(void);
-EffectStateFactory *CompressorStateFactory_getFactory(void);
-EffectStateFactory *DistortionStateFactory_getFactory(void);
-EffectStateFactory *EchoStateFactory_getFactory(void);
-EffectStateFactory *EqualizerStateFactory_getFactory(void);
-EffectStateFactory *FlangerStateFactory_getFactory(void);
-EffectStateFactory *FshifterStateFactory_getFactory(void);
-EffectStateFactory *ModulatorStateFactory_getFactory(void);
-EffectStateFactory *PshifterStateFactory_getFactory(void);
-EffectStateFactory* VmorpherStateFactory_getFactory(void);
-
-EffectStateFactory *DedicatedStateFactory_getFactory(void);
-
-EffectStateFactory *ConvolutionStateFactory_getFactory(void);
+/* This is a user config option for modifying the overall output of the reverb
+ * effect.
+ */
+inline float ReverbBoost{1.0f};
+
+
+EffectStateFactory *NullStateFactory_getFactory();
+EffectStateFactory *ReverbStateFactory_getFactory();
+EffectStateFactory *StdReverbStateFactory_getFactory();
+EffectStateFactory *AutowahStateFactory_getFactory();
+EffectStateFactory *ChorusStateFactory_getFactory();
+EffectStateFactory *CompressorStateFactory_getFactory();
+EffectStateFactory *DistortionStateFactory_getFactory();
+EffectStateFactory *EchoStateFactory_getFactory();
+EffectStateFactory *EqualizerStateFactory_getFactory();
+EffectStateFactory *FlangerStateFactory_getFactory();
+EffectStateFactory *FshifterStateFactory_getFactory();
+EffectStateFactory *ModulatorStateFactory_getFactory();
+EffectStateFactory *PshifterStateFactory_getFactory();
+EffectStateFactory* VmorpherStateFactory_getFactory();
+
+EffectStateFactory *DedicatedDialogStateFactory_getFactory();
+EffectStateFactory *DedicatedLfeStateFactory_getFactory();
+
+EffectStateFactory *ConvolutionStateFactory_getFactory();
#endif /* EFFECTS_BASE_H */
diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp
index 9cbc922f..bc6ddaf0 100644
--- a/alc/effects/chorus.cpp
+++ b/alc/effects/chorus.cpp
@@ -48,7 +48,14 @@ namespace {
using uint = unsigned int;
-struct ChorusState final : public EffectState {
+constexpr auto inv_sqrt2 = static_cast<float>(1.0 / al::numbers::sqrt2);
+constexpr auto lcoeffs_pw = CalcDirectionCoeffs(std::array{-1.0f, 0.0f, 0.0f});
+constexpr auto rcoeffs_pw = CalcDirectionCoeffs(std::array{ 1.0f, 0.0f, 0.0f});
+constexpr auto lcoeffs_nrml = CalcDirectionCoeffs(std::array{-inv_sqrt2, 0.0f, inv_sqrt2});
+constexpr auto rcoeffs_nrml = CalcDirectionCoeffs(std::array{ inv_sqrt2, 0.0f, inv_sqrt2});
+
+
+struct ChorusState : public EffectState {
std::vector<float> mDelayBuffer;
uint mOffset{0};
@@ -58,16 +65,17 @@ struct ChorusState final : public EffectState {
uint mLfoDisp{0};
/* Calculated delays to apply to the left and right outputs. */
- uint mModDelays[2][BufferLineSize];
+ std::array<std::array<uint,BufferLineSize>,2> mModDelays{};
/* Temp storage for the modulated left and right outputs. */
- alignas(16) float mBuffer[2][BufferLineSize];
+ alignas(16) std::array<FloatBufferLine,2> mBuffer{};
/* Gains for left and right outputs. */
- struct {
- float Current[MaxAmbiChannels]{};
- float Target[MaxAmbiChannels]{};
- } mGains[2];
+ struct OutGains {
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
+ };
+ std::array<OutGains,2> mGains;
/* effect parameters */
ChorusWaveform mWaveform{};
@@ -78,65 +86,81 @@ struct ChorusState final : public EffectState {
void calcTriangleDelays(const size_t todo);
void calcSinusoidDelays(const size_t todo);
- void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
- void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
- const EffectTarget target) override;
+ void deviceUpdate(const DeviceBase *device, const float MaxDelay);
+ void update(const ContextBase *context, const EffectSlot *slot, const ChorusWaveform waveform,
+ const float delay, const float depth, const float feedback, const float rate,
+ int phase, const EffectTarget target);
+
+ void deviceUpdate(const DeviceBase *device, const BufferStorage*) override
+ { deviceUpdate(device, ChorusMaxDelay); }
+ void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props_,
+ const EffectTarget target) override
+ {
+ auto &props = std::get<ChorusProps>(*props_);
+ update(context, slot, props.Waveform, props.Delay, props.Depth, props.Feedback, props.Rate,
+ props.Phase, target);
+ }
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
- const al::span<FloatBufferLine> samplesOut) override;
+ const al::span<FloatBufferLine> samplesOut) final;
+};
- DEF_NEWDEL(ChorusState)
+struct FlangerState final : public ChorusState {
+ void deviceUpdate(const DeviceBase *device, const BufferStorage*) final
+ { ChorusState::deviceUpdate(device, FlangerMaxDelay); }
+ void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props_,
+ const EffectTarget target) final
+ {
+ auto &props = std::get<FlangerProps>(*props_);
+ ChorusState::update(context, slot, props.Waveform, props.Delay, props.Depth,
+ props.Feedback, props.Rate, props.Phase, target);
+ }
};
-void ChorusState::deviceUpdate(const DeviceBase *Device, const BufferStorage*)
-{
- constexpr float max_delay{maxf(ChorusMaxDelay, FlangerMaxDelay)};
+void ChorusState::deviceUpdate(const DeviceBase *Device, const float MaxDelay)
+{
const auto frequency = static_cast<float>(Device->Frequency);
- const size_t maxlen{NextPowerOf2(float2uint(max_delay*2.0f*frequency) + 1u)};
+ const size_t maxlen{NextPowerOf2(float2uint(MaxDelay*2.0f*frequency) + 1u)};
if(maxlen != mDelayBuffer.size())
decltype(mDelayBuffer)(maxlen).swap(mDelayBuffer);
std::fill(mDelayBuffer.begin(), mDelayBuffer.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);
+ e.Current.fill(0.0f);
+ e.Target.fill(0.0f);
}
}
-void ChorusState::update(const ContextBase *Context, const EffectSlot *Slot,
- const EffectProps *props, const EffectTarget target)
+void ChorusState::update(const ContextBase *context, const EffectSlot *slot,
+ const ChorusWaveform waveform, const float delay, const float depth, const float feedback,
+ const float rate, int phase, const EffectTarget target)
{
- constexpr int mindelay{(MaxResamplerPadding>>1) << MixerFracBits};
+ static constexpr int mindelay{(MaxResamplerPadding>>1) << MixerFracBits};
/* The LFO depth is scaled to be relative to the sample delay. Clamp the
* delay and depth to allow enough padding for resampling.
*/
- const DeviceBase *device{Context->mDevice};
+ const DeviceBase *device{context->mDevice};
const auto frequency = static_cast<float>(device->Frequency);
- mWaveform = props->Chorus.Waveform;
+ mWaveform = waveform;
- mDelay = maxi(float2int(props->Chorus.Delay*frequency*MixerFracOne + 0.5f), mindelay);
- mDepth = minf(props->Chorus.Depth * static_cast<float>(mDelay),
+ mDelay = maxi(float2int(delay*frequency*MixerFracOne + 0.5f), mindelay);
+ mDepth = minf(depth * static_cast<float>(mDelay),
static_cast<float>(mDelay - mindelay));
- mFeedback = props->Chorus.Feedback;
+ mFeedback = feedback;
/* Gains for left and right sides */
- static constexpr auto inv_sqrt2 = static_cast<float>(1.0 / al::numbers::sqrt2);
- static constexpr auto lcoeffs_pw = CalcDirectionCoeffs(std::array{-1.0f, 0.0f, 0.0f});
- static constexpr auto rcoeffs_pw = CalcDirectionCoeffs(std::array{ 1.0f, 0.0f, 0.0f});
- static constexpr auto lcoeffs_nrml = CalcDirectionCoeffs(std::array{-inv_sqrt2, 0.0f, inv_sqrt2});
- static constexpr auto rcoeffs_nrml = CalcDirectionCoeffs(std::array{ inv_sqrt2, 0.0f, inv_sqrt2});
- auto &lcoeffs = (device->mRenderMode != RenderMode::Pairwise) ? lcoeffs_nrml : lcoeffs_pw;
- auto &rcoeffs = (device->mRenderMode != RenderMode::Pairwise) ? rcoeffs_nrml : rcoeffs_pw;
+ const bool ispairwise{device->mRenderMode == RenderMode::Pairwise};
+ const auto lcoeffs = (!ispairwise) ? al::span{lcoeffs_nrml} : al::span{lcoeffs_pw};
+ const auto rcoeffs = (!ispairwise) ? al::span{rcoeffs_nrml} : al::span{rcoeffs_pw};
mOutTarget = target.Main->Buffer;
- ComputePanGains(target.Main, lcoeffs, Slot->Gain, mGains[0].Target);
- ComputePanGains(target.Main, rcoeffs, Slot->Gain, mGains[1].Target);
+ ComputePanGains(target.Main, lcoeffs, slot->Gain, mGains[0].Target);
+ ComputePanGains(target.Main, rcoeffs, slot->Gain, mGains[1].Target);
- float rate{props->Chorus.Rate};
if(!(rate > 0.0f))
{
mLfoOffset = 0;
@@ -149,7 +173,7 @@ void ChorusState::update(const ContextBase *Context, const EffectSlot *Slot,
/* Calculate LFO coefficient (number of samples per cycle). Limit the
* max range to avoid overflow when calculating the displacement.
*/
- uint lfo_range{float2uint(minf(frequency/rate + 0.5f, float{INT_MAX/360 - 180}))};
+ const uint lfo_range{float2uint(minf(frequency/rate + 0.5f, float{INT_MAX/360 - 180}))};
mLfoOffset = mLfoOffset * lfo_range / mLfoRange;
mLfoRange = lfo_range;
@@ -164,7 +188,6 @@ void ChorusState::update(const ContextBase *Context, const EffectSlot *Slot,
}
/* Calculate lfo phase displacement */
- int phase{props->Chorus.Phase};
if(phase < 0) phase = 360 + phase;
mLfoDisp = (mLfoRange*static_cast<uint>(phase) + 180) / 360;
}
@@ -266,10 +289,10 @@ void ChorusState::process(const size_t samplesToDo, const al::span<const FloatBu
else /*if(mWaveform == ChorusWaveform::Triangle)*/
calcTriangleDelays(samplesToDo);
- const uint *RESTRICT ldelays{mModDelays[0]};
- const uint *RESTRICT rdelays{mModDelays[1]};
- float *RESTRICT lbuffer{al::assume_aligned<16>(mBuffer[0])};
- float *RESTRICT rbuffer{al::assume_aligned<16>(mBuffer[1])};
+ const uint *RESTRICT ldelays{mModDelays[0].data()};
+ const uint *RESTRICT rdelays{mModDelays[1].data()};
+ float *RESTRICT lbuffer{al::assume_aligned<16>(mBuffer[0].data())};
+ float *RESTRICT rbuffer{al::assume_aligned<16>(mBuffer[1].data())};
for(size_t i{0u};i < samplesToDo;++i)
{
// Feed the buffer's input first (necessary for delays < 1).
@@ -292,10 +315,10 @@ void ChorusState::process(const size_t samplesToDo, const al::span<const FloatBu
++offset;
}
- MixSamples({lbuffer, samplesToDo}, samplesOut, mGains[0].Current, mGains[0].Target,
- samplesToDo, 0);
- MixSamples({rbuffer, samplesToDo}, samplesOut, mGains[1].Current, mGains[1].Target,
- samplesToDo, 0);
+ MixSamples({lbuffer, samplesToDo}, samplesOut, mGains[0].Current.data(),
+ mGains[0].Target.data(), samplesToDo, 0);
+ MixSamples({rbuffer, samplesToDo}, samplesOut, mGains[1].Current.data(),
+ mGains[1].Target.data(), samplesToDo, 0);
mOffset = offset;
}
@@ -312,7 +335,7 @@ struct ChorusStateFactory final : public EffectStateFactory {
*/
struct FlangerStateFactory final : public EffectStateFactory {
al::intrusive_ptr<EffectState> create() override
- { return al::intrusive_ptr<EffectState>{new ChorusState{}}; }
+ { return al::intrusive_ptr<EffectState>{new FlangerState{}}; }
};
} // namespace
diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp
index 0a7ed67a..717b6dd2 100644
--- a/alc/effects/compressor.cpp
+++ b/alc/effects/compressor.cpp
@@ -64,10 +64,11 @@ namespace {
struct CompressorState final : public EffectState {
/* Effect gains for each channel */
- struct {
+ struct TargetGain {
uint mTarget{InvalidChannelIndex};
float mGain{1.0f};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<TargetGain,MaxAmbiChannels> mChans;
/* Effect parameters */
bool mEnabled{true};
@@ -81,8 +82,6 @@ struct CompressorState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(CompressorState)
};
void CompressorState::deviceUpdate(const DeviceBase *device, const BufferStorage*)
@@ -103,7 +102,7 @@ void CompressorState::deviceUpdate(const DeviceBase *device, const BufferStorage
void CompressorState::update(const ContextBase*, const EffectSlot *slot,
const EffectProps *props, const EffectTarget target)
{
- mEnabled = props->Compressor.OnOff;
+ mEnabled = std::get<CompressorProps>(*props).OnOff;
mOutTarget = target.Main->Buffer;
auto set_channel = [this](size_t idx, uint outchan, float outgain)
@@ -119,8 +118,8 @@ void CompressorState::process(const size_t samplesToDo,
{
for(size_t base{0u};base < samplesToDo;)
{
- float gains[256];
- const size_t td{minz(256, samplesToDo-base)};
+ std::array<float,256> gains;
+ const size_t td{minz(gains.size(), samplesToDo-base)};
/* Generate the per-sample gains from the signal envelope. */
float env{mEnvFollower};
diff --git a/alc/effects/convolution.cpp b/alc/effects/convolution.cpp
index 517e6b08..3f3e157c 100644
--- a/alc/effects/convolution.cpp
+++ b/alc/effects/convolution.cpp
@@ -5,11 +5,12 @@
#include <array>
#include <complex>
#include <cstddef>
+#include <cstdint>
#include <functional>
#include <iterator>
#include <memory>
-#include <stdint.h>
#include <utility>
+#include <vector>
#ifdef HAVE_SSE_INTRINSICS
#include <xmmintrin.h>
@@ -190,12 +191,6 @@ void apply_fir(al::span<float> dst, const float *RESTRICT src, const float *REST
}
-struct PFFFTSetupDeleter {
- void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); }
-};
-using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>;
-
-
struct ConvolutionState final : public EffectState {
FmtChannels mChannels{};
AmbiLayout mAmbiLayout{};
@@ -207,7 +202,7 @@ struct ConvolutionState final : public EffectState {
al::vector<std::array<float,ConvolveUpdateSamples>,16> mFilter;
al::vector<std::array<float,ConvolveUpdateSamples*2>,16> mOutput;
- PFFFTSetupPtr mFft{};
+ PFFFTSetup mFft{};
alignas(16) std::array<float,ConvolveUpdateSize> mFftBuffer{};
alignas(16) std::array<float,ConvolveUpdateSize> mFftWorkBuffer{};
@@ -218,8 +213,8 @@ struct ConvolutionState final : public EffectState {
alignas(16) FloatBufferLine mBuffer{};
float mHfScale{}, mLfScale{};
BandSplitter mFilter{};
- float Current[MAX_OUTPUT_CHANNELS]{};
- float Target[MAX_OUTPUT_CHANNELS]{};
+ std::array<float,MaxOutputChannels> Current{};
+ std::array<float,MaxOutputChannels> Target{};
};
std::vector<ChannelData> mChans;
al::vector<float,16> mComplexData;
@@ -238,16 +233,14 @@ struct ConvolutionState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(ConvolutionState)
};
void ConvolutionState::NormalMix(const al::span<FloatBufferLine> samplesOut,
const size_t samplesToDo)
{
for(auto &chan : mChans)
- MixSamples({chan.mBuffer.data(), samplesToDo}, samplesOut, chan.Current, chan.Target,
- samplesToDo, 0);
+ MixSamples({chan.mBuffer.data(), samplesToDo}, samplesOut, chan.Current.data(),
+ chan.Target.data(), samplesToDo, 0);
}
void ConvolutionState::UpsampleMix(const al::span<FloatBufferLine> samplesOut,
@@ -257,7 +250,7 @@ void ConvolutionState::UpsampleMix(const al::span<FloatBufferLine> samplesOut,
{
const al::span<float> src{chan.mBuffer.data(), samplesToDo};
chan.mFilter.processScale(src, chan.mHfScale, chan.mLfScale);
- MixSamples(src, samplesOut, chan.Current, chan.Target, samplesToDo, 0);
+ MixSamples(src, samplesOut, chan.Current.data(), chan.Target.data(), samplesToDo, 0);
}
}
@@ -270,7 +263,7 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
static constexpr uint MaxConvolveAmbiOrder{1u};
if(!mFft)
- mFft = PFFFTSetupPtr{pffft_new_setup(ConvolveUpdateSize, PFFFT_REAL)};
+ mFft = PFFFTSetup{ConvolveUpdateSize, PFFFT_REAL};
mFifoPos = 0;
mInput.fill(0.0f);
@@ -331,10 +324,10 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
/* Load the samples from the buffer. */
const size_t srclinelength{RoundUp(buffer->mSampleLen+DecoderPadding, 16)};
- auto srcsamples = std::make_unique<float[]>(srclinelength * numChannels);
- std::fill_n(srcsamples.get(), srclinelength * numChannels, 0.0f);
+ auto srcsamples = std::vector<float>(srclinelength * numChannels);
+ std::fill(srcsamples.begin(), srcsamples.end(), 0.0f);
for(size_t c{0};c < numChannels && c < realChannels;++c)
- LoadSamples(srcsamples.get() + srclinelength*c, buffer->mData.data() + bytesPerSample*c,
+ LoadSamples(srcsamples.data() + srclinelength*c, buffer->mData.data() + bytesPerSample*c,
realChannels, buffer->mType, buffer->mSampleLen);
if(IsUHJ(mChannels))
@@ -342,12 +335,11 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
auto decoder = std::make_unique<UhjDecoderType>();
std::array<float*,4> samples{};
for(size_t c{0};c < numChannels;++c)
- samples[c] = srcsamples.get() + srclinelength*c;
+ samples[c] = srcsamples.data() + srclinelength*c;
decoder->decode({samples.data(), numChannels}, buffer->mSampleLen, buffer->mSampleLen);
}
- auto ressamples = std::make_unique<double[]>(buffer->mSampleLen +
- (resampler ? resampledCount : 0));
+ auto ressamples = std::vector<double>(buffer->mSampleLen + (resampler ? resampledCount : 0));
auto ffttmp = al::vector<float,16>(ConvolveUpdateSize);
auto fftbuffer = std::vector<std::complex<double>>(ConvolveUpdateSize);
@@ -357,19 +349,20 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
/* Resample to match the device. */
if(resampler)
{
- std::copy_n(srcsamples.get() + srclinelength*c, buffer->mSampleLen,
- ressamples.get() + resampledCount);
- resampler.process(buffer->mSampleLen, ressamples.get()+resampledCount,
- resampledCount, ressamples.get());
+ std::copy_n(srcsamples.data() + srclinelength*c, buffer->mSampleLen,
+ ressamples.data() + resampledCount);
+ resampler.process(buffer->mSampleLen, ressamples.data()+resampledCount,
+ resampledCount, ressamples.data());
}
else
- std::copy_n(srcsamples.get() + srclinelength*c, buffer->mSampleLen, ressamples.get());
+ std::copy_n(srcsamples.data() + srclinelength*c, buffer->mSampleLen,
+ ressamples.data());
/* Store the first segment's samples in reverse in the time-domain, to
* apply as a FIR filter.
*/
const size_t first_size{minz(resampledCount, ConvolveUpdateSamples)};
- std::transform(ressamples.get(), ressamples.get()+first_size, mFilter[c].rbegin(),
+ std::transform(ressamples.data(), ressamples.data()+first_size, mFilter[c].rbegin(),
[](const double d) noexcept -> float { return static_cast<float>(d); });
size_t done{first_size};
@@ -400,7 +393,7 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
/* Reorder backward to make it suitable for pffft_zconvolve and the
* subsequent pffft_transform(..., PFFFT_BACKWARD).
*/
- pffft_zreorder(mFft.get(), ffttmp.data(), al::to_address(filteriter), PFFFT_BACKWARD);
+ mFft.zreorder(ffttmp.data(), al::to_address(filteriter), PFFFT_BACKWARD);
filteriter += ConvolveUpdateSize;
}
}
@@ -408,54 +401,61 @@ void ConvolutionState::deviceUpdate(const DeviceBase *device, const BufferStorag
void ConvolutionState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
/* TODO: LFE is not mixed to output. This will require each buffer channel
* to have its own output target since the main mixing buffer won't have an
* LFE channel (due to being B-Format).
*/
- static constexpr ChanPosMap MonoMap[1]{
- { FrontCenter, std::array{0.0f, 0.0f, -1.0f} }
- }, StereoMap[2]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- }, RearMap[2]{
- { BackLeft, std::array{-sin30, 0.0f, cos30} },
- { BackRight, std::array{ sin30, 0.0f, cos30} },
- }, QuadMap[4]{
- { FrontLeft, std::array{-sin45, 0.0f, -cos45} },
- { FrontRight, std::array{ sin45, 0.0f, -cos45} },
- { BackLeft, std::array{-sin45, 0.0f, cos45} },
- { BackRight, std::array{ sin45, 0.0f, cos45} },
- }, X51Map[6]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { SideLeft, std::array{-sin110, 0.0f, -cos110} },
- { SideRight, std::array{ sin110, 0.0f, -cos110} },
- }, X61Map[7]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { BackCenter, std::array{ 0.0f, 0.0f, 1.0f} },
- { SideLeft, std::array{-1.0f, 0.0f, 0.0f} },
- { SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
- }, X71Map[8]{
- { FrontLeft, std::array{-sin30, 0.0f, -cos30} },
- { FrontRight, std::array{ sin30, 0.0f, -cos30} },
- { FrontCenter, std::array{ 0.0f, 0.0f, -1.0f} },
- { LFE, {} },
- { BackLeft, std::array{-sin30, 0.0f, cos30} },
- { BackRight, std::array{ sin30, 0.0f, cos30} },
- { SideLeft, std::array{ -1.0f, 0.0f, 0.0f} },
- { SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
+ static constexpr std::array MonoMap{
+ ChanPosMap{FrontCenter, std::array{0.0f, 0.0f, -1.0f}}
+ };
+ static constexpr std::array StereoMap{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ };
+ static constexpr std::array RearMap{
+ ChanPosMap{BackLeft, std::array{-sin30, 0.0f, cos30}},
+ ChanPosMap{BackRight, std::array{ sin30, 0.0f, cos30}},
+ };
+ static constexpr std::array QuadMap{
+ ChanPosMap{FrontLeft, std::array{-sin45, 0.0f, -cos45}},
+ ChanPosMap{FrontRight, std::array{ sin45, 0.0f, -cos45}},
+ ChanPosMap{BackLeft, std::array{-sin45, 0.0f, cos45}},
+ ChanPosMap{BackRight, std::array{ sin45, 0.0f, cos45}},
+ };
+ static constexpr std::array X51Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{SideLeft, std::array{-sin110, 0.0f, -cos110}},
+ ChanPosMap{SideRight, std::array{ sin110, 0.0f, -cos110}},
+ };
+ static constexpr std::array X61Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{BackCenter, std::array{ 0.0f, 0.0f, 1.0f} },
+ ChanPosMap{SideLeft, std::array{-1.0f, 0.0f, 0.0f} },
+ ChanPosMap{SideRight, std::array{ 1.0f, 0.0f, 0.0f} },
+ };
+ static constexpr std::array X71Map{
+ ChanPosMap{FrontLeft, std::array{-sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontRight, std::array{ sin30, 0.0f, -cos30}},
+ ChanPosMap{FrontCenter, std::array{ 0.0f, 0.0f, -1.0f}},
+ ChanPosMap{LFE, {}},
+ ChanPosMap{BackLeft, std::array{-sin30, 0.0f, cos30}},
+ ChanPosMap{BackRight, std::array{ sin30, 0.0f, cos30}},
+ ChanPosMap{SideLeft, std::array{ -1.0f, 0.0f, 0.0f}},
+ ChanPosMap{SideRight, std::array{ 1.0f, 0.0f, 0.0f}},
};
if(mNumConvolveSegs < 1) UNLIKELY
return;
+ auto &props = std::get<ConvolutionProps>(*props_);
mMix = &ConvolutionState::NormalMix;
for(auto &chan : mChans)
@@ -489,21 +489,19 @@ void ConvolutionState::update(const ContextBase *context, const EffectSlot *slot
}
mOutTarget = target.Main->Buffer;
- alu::Vector N{props->Convolution.OrientAt[0], props->Convolution.OrientAt[1],
- props->Convolution.OrientAt[2], 0.0f};
+ alu::Vector N{props.OrientAt[0], props.OrientAt[1], props.OrientAt[2], 0.0f};
N.normalize();
- alu::Vector V{props->Convolution.OrientUp[0], props->Convolution.OrientUp[1],
- props->Convolution.OrientUp[2], 0.0f};
+ alu::Vector V{props.OrientUp[0], props.OrientUp[1], props.OrientUp[2], 0.0f};
V.normalize();
/* Build and normalize right-vector */
alu::Vector U{N.cross_product(V)};
U.normalize();
- const float mixmatrix[4][4]{
- {1.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, U[0], -U[1], U[2]},
- {0.0f, -V[0], V[1], -V[2]},
- {0.0f, -N[0], N[1], -N[2]},
+ const std::array mixmatrix{
+ std::array{1.0f, 0.0f, 0.0f, 0.0f},
+ std::array{0.0f, U[0], -U[1], U[2]},
+ std::array{0.0f, -V[0], V[1], -V[2]},
+ std::array{0.0f, -N[0], N[1], -N[2]},
};
const auto scales = GetAmbiScales(mAmbiScaling);
@@ -642,7 +640,7 @@ void ConvolutionState::process(const size_t samplesToDo,
/* Calculate the frequency-domain response and add the relevant
* frequency bins to the FFT history.
*/
- pffft_transform(mFft.get(), mInput.data(), mComplexData.data() + curseg*ConvolveUpdateSize,
+ mFft.transform(mInput.data(), mComplexData.data() + curseg*ConvolveUpdateSize,
mFftWorkBuffer.data(), PFFFT_FORWARD);
const float *filter{mComplexData.data() + mNumConvolveSegs*ConvolveUpdateSize};
@@ -655,14 +653,14 @@ void ConvolutionState::process(const size_t samplesToDo,
const float *input{&mComplexData[curseg*ConvolveUpdateSize]};
for(size_t s{curseg};s < mNumConvolveSegs;++s)
{
- pffft_zconvolve_accumulate(mFft.get(), input, filter, mFftBuffer.data());
+ mFft.zconvolve_accumulate(input, filter, mFftBuffer.data());
input += ConvolveUpdateSize;
filter += ConvolveUpdateSize;
}
input = mComplexData.data();
for(size_t s{0};s < curseg;++s)
{
- pffft_zconvolve_accumulate(mFft.get(), input, filter, mFftBuffer.data());
+ mFft.zconvolve_accumulate(input, filter, mFftBuffer.data());
input += ConvolveUpdateSize;
filter += ConvolveUpdateSize;
}
@@ -672,8 +670,8 @@ void ConvolutionState::process(const size_t samplesToDo,
* second-half samples (and this output's second half is
* subsequently saved for next time).
*/
- pffft_transform(mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mFftWorkBuffer.data(), PFFFT_BACKWARD);
+ mFft.transform(mFftBuffer.data(), mFftBuffer.data(), mFftWorkBuffer.data(),
+ PFFFT_BACKWARD);
/* The filter was attenuated, so the response is already scaled. */
for(size_t i{0};i < ConvolveUpdateSamples;++i)
diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp
index a9131bfa..23ac4d1a 100644
--- a/alc/effects/dedicated.cpp
+++ b/alc/effects/dedicated.cpp
@@ -42,82 +42,100 @@ namespace {
using uint = unsigned int;
-struct DedicatedState final : public EffectState {
+struct DedicatedState : public EffectState {
/* The "dedicated" effect can output to the real output, so should have
* gains for all possible output channels and not just the main ambisonic
* buffer.
*/
- float mCurrentGains[MAX_OUTPUT_CHANNELS];
- float mTargetGains[MAX_OUTPUT_CHANNELS];
+ std::array<float,MaxOutputChannels> mCurrentGains{};
+ std::array<float,MaxOutputChannels> mTargetGains{};
- void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
+ void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) final;
void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
- const al::span<FloatBufferLine> samplesOut) override;
+ const al::span<FloatBufferLine> samplesOut) final;
+};
- DEF_NEWDEL(DedicatedState)
+struct DedicatedLfeState final : public DedicatedState {
+ void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
+ const EffectTarget target) final;
};
void DedicatedState::deviceUpdate(const DeviceBase*, const BufferStorage*)
{
- std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
+ std::fill(mCurrentGains.begin(), mCurrentGains.end(), 0.0f);
}
void DedicatedState::update(const ContextBase*, const EffectSlot *slot,
const EffectProps *props, const EffectTarget target)
{
- std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
+ std::fill(mTargetGains.begin(), mTargetGains.end(), 0.0f);
- const float Gain{slot->Gain * props->Dedicated.Gain};
+ const float Gain{slot->Gain * std::get<DedicatedDialogProps>(*props).Gain};
- if(slot->EffectType == EffectSlotType::DedicatedLFE)
+ /* Dialog goes to the front-center speaker if it exists, otherwise it plays
+ * from the front-center location.
+ */
+ const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[FrontCenter]
+ : InvalidChannelIndex};
+ if(idx != InvalidChannelIndex)
{
- const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[LFE] : InvalidChannelIndex};
- if(idx != InvalidChannelIndex)
- {
- mOutTarget = target.RealOut->Buffer;
- mTargetGains[idx] = Gain;
- }
+ mOutTarget = target.RealOut->Buffer;
+ mTargetGains[idx] = Gain;
}
- else if(slot->EffectType == EffectSlotType::DedicatedDialog)
+ else
{
- /* Dialog goes to the front-center speaker if it exists, otherwise it
- * plays from the front-center location. */
- const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[FrontCenter]
- : InvalidChannelIndex};
- if(idx != InvalidChannelIndex)
- {
- mOutTarget = target.RealOut->Buffer;
- mTargetGains[idx] = Gain;
- }
- else
- {
- static constexpr auto coeffs = CalcDirectionCoeffs(std::array{0.0f, 0.0f, -1.0f});
-
- mOutTarget = target.Main->Buffer;
- ComputePanGains(target.Main, coeffs, Gain, mTargetGains);
- }
+ static constexpr auto coeffs = CalcDirectionCoeffs(std::array{0.0f, 0.0f, -1.0f});
+
+ mOutTarget = target.Main->Buffer;
+ ComputePanGains(target.Main, coeffs, Gain, mTargetGains);
+ }
+}
+
+void DedicatedLfeState::update(const ContextBase*, const EffectSlot *slot,
+ const EffectProps *props, const EffectTarget target)
+{
+ std::fill(mTargetGains.begin(), mTargetGains.end(), 0.0f);
+
+ const float Gain{slot->Gain * std::get<DedicatedLfeProps>(*props).Gain};
+
+ const size_t idx{target.RealOut ? target.RealOut->ChannelIndex[LFE] : InvalidChannelIndex};
+ if(idx != InvalidChannelIndex)
+ {
+ mOutTarget = target.RealOut->Buffer;
+ mTargetGains[idx] = Gain;
}
}
void DedicatedState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
{
- MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains,
- samplesToDo, 0);
+ MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains.data(),
+ mTargetGains.data(), samplesToDo, 0);
}
-struct DedicatedStateFactory final : public EffectStateFactory {
+struct DedicatedDialogStateFactory final : public EffectStateFactory {
al::intrusive_ptr<EffectState> create() override
{ return al::intrusive_ptr<EffectState>{new DedicatedState{}}; }
};
+struct DedicatedLfeStateFactory final : public EffectStateFactory {
+ al::intrusive_ptr<EffectState> create() override
+ { return al::intrusive_ptr<EffectState>{new DedicatedLfeState{}}; }
+};
+
} // namespace
-EffectStateFactory *DedicatedStateFactory_getFactory()
+EffectStateFactory *DedicatedDialogStateFactory_getFactory()
+{
+ static DedicatedDialogStateFactory DedicatedFactory{};
+ return &DedicatedFactory;
+}
+
+EffectStateFactory *DedicatedLfeStateFactory_getFactory()
{
- static DedicatedStateFactory DedicatedFactory{};
+ static DedicatedLfeStateFactory DedicatedFactory{};
return &DedicatedFactory;
}
diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp
index 3d77ff35..d0946971 100644
--- a/alc/effects/distortion.cpp
+++ b/alc/effects/distortion.cpp
@@ -45,7 +45,7 @@ namespace {
struct DistortionState final : public EffectState {
/* Effect gains for each channel */
- float mGain[MaxAmbiChannels]{};
+ std::array<float,MaxAmbiChannels> mGain{};
/* Effect parameters */
BiquadFilter mLowpass;
@@ -53,7 +53,7 @@ struct DistortionState final : public EffectState {
float mAttenuation{};
float mEdgeCoeff{};
- alignas(16) float mBuffer[2][BufferLineSize]{};
+ alignas(16) std::array<FloatBufferLine,2> mBuffer{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -61,8 +61,6 @@ struct DistortionState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(DistortionState)
};
void DistortionState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -72,16 +70,17 @@ void DistortionState::deviceUpdate(const DeviceBase*, const BufferStorage*)
}
void DistortionState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<DistortionProps>(*props_);
const DeviceBase *device{context->mDevice};
/* Store waveshaper edge settings. */
- const float edge{minf(std::sin(al::numbers::pi_v<float>*0.5f * props->Distortion.Edge),
+ const float edge{minf(std::sin(al::numbers::pi_v<float>*0.5f * props.Edge),
0.99f)};
mEdgeCoeff = 2.0f * edge / (1.0f-edge);
- float cutoff{props->Distortion.LowpassCutoff};
+ float cutoff{props.LowpassCutoff};
/* Bandwidth value is constant in octaves. */
float bandwidth{(cutoff / 2.0f) / (cutoff * 0.67f)};
/* Divide normalized frequency by the amount of oversampling done during
@@ -90,15 +89,15 @@ void DistortionState::update(const ContextBase *context, const EffectSlot *slot,
auto frequency = static_cast<float>(device->Frequency);
mLowpass.setParamsFromBandwidth(BiquadType::LowPass, cutoff/frequency/4.0f, 1.0f, bandwidth);
- cutoff = props->Distortion.EQCenter;
+ cutoff = props.EQCenter;
/* Convert bandwidth in Hz to octaves. */
- bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
+ bandwidth = props.EQBandwidth / (cutoff * 0.67f);
mBandpass.setParamsFromBandwidth(BiquadType::BandPass, cutoff/frequency/4.0f, 1.0f, bandwidth);
static constexpr auto coeffs = CalcDirectionCoeffs(std::array{0.0f, 0.0f, -1.0f});
mOutTarget = target.Main->Buffer;
- ComputePanGains(target.Main, coeffs, slot->Gain*props->Distortion.Gain, mGain);
+ ComputePanGains(target.Main, coeffs, slot->Gain*props.Gain, mGain);
}
void DistortionState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
@@ -124,7 +123,7 @@ void DistortionState::process(const size_t samplesToDo, const al::span<const Flo
* (which is fortunately first step of distortion). So combine three
* operations into the one.
*/
- mLowpass.process({mBuffer[0], todo}, mBuffer[1]);
+ mLowpass.process({mBuffer[0].data(), todo}, mBuffer[1].data());
/* Second step, do distortion using waveshaper function to emulate
* signal processing during tube overdriving. Three steps of
@@ -138,15 +137,15 @@ void DistortionState::process(const size_t samplesToDo, const al::span<const Flo
smp = (1.0f + fc) * smp/(1.0f + fc*std::abs(smp));
return smp;
};
- std::transform(std::begin(mBuffer[1]), std::begin(mBuffer[1])+todo, std::begin(mBuffer[0]),
+ std::transform(mBuffer[1].begin(), mBuffer[1].begin()+todo, mBuffer[0].begin(),
proc_sample);
/* Third step, do bandpass filtering of distorted signal. */
- mBandpass.process({mBuffer[0], todo}, mBuffer[1]);
+ mBandpass.process({mBuffer[0].data(), todo}, mBuffer[1].data());
todo >>= 2;
- const float *outgains{mGain};
- for(FloatBufferLine &output : samplesOut)
+ const float *outgains{mGain.data()};
+ for(FloatBufferLine &RESTRICT output : samplesOut)
{
/* Fourth step, final, do attenuation and perform decimation,
* storing only one sample out of four.
diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp
index 714649c9..a5bfa6a5 100644
--- a/alc/effects/echo.cpp
+++ b/alc/effects/echo.cpp
@@ -53,29 +53,26 @@ struct EchoState final : public EffectState {
// The echo is two tap. The delay is the number of samples from before the
// current offset
- struct {
- size_t delay{0u};
- } mTap[2];
+ std::array<size_t,2> mDelayTap{};
size_t mOffset{0u};
/* The panning gains for the two taps */
- struct {
- float Current[MaxAmbiChannels]{};
- float Target[MaxAmbiChannels]{};
- } mGains[2];
+ struct OutGains {
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
+ };
+ std::array<OutGains,2> mGains;
BiquadFilter mFilter;
float mFeedGain{0.0f};
- alignas(16) float mTempBuffer[2][BufferLineSize];
+ alignas(16) std::array<FloatBufferLine,2> mTempBuffer{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(EchoState)
};
void EchoState::deviceUpdate(const DeviceBase *Device, const BufferStorage*)
@@ -92,27 +89,28 @@ void EchoState::deviceUpdate(const DeviceBase *Device, const BufferStorage*)
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);
+ std::fill(e.Current.begin(), e.Current.end(), 0.0f);
+ std::fill(e.Target.begin(), e.Target.end(), 0.0f);
}
}
void EchoState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<EchoProps>(*props_);
const DeviceBase *device{context->mDevice};
const auto frequency = static_cast<float>(device->Frequency);
- mTap[0].delay = maxu(float2uint(props->Echo.Delay*frequency + 0.5f), 1);
- mTap[1].delay = float2uint(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay;
+ mDelayTap[0] = maxu(float2uint(props.Delay*frequency + 0.5f), 1);
+ mDelayTap[1] = float2uint(props.LRDelay*frequency + 0.5f) + mDelayTap[0];
- const float gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */
+ const float gainhf{maxf(1.0f - props.Damping, 0.0625f)}; /* Limit -24dB */
mFilter.setParamsFromSlope(BiquadType::HighShelf, LowpassFreqRef/frequency, gainhf, 1.0f);
- mFeedGain = props->Echo.Feedback;
+ mFeedGain = props.Feedback;
/* Convert echo spread (where 0 = center, +/-1 = sides) to angle. */
- const float angle{std::asin(props->Echo.Spread)};
+ const float angle{std::asin(props.Spread)};
const auto coeffs0 = CalcAngleCoeffs(-angle, 0.0f, 0.0f);
const auto coeffs1 = CalcAngleCoeffs( angle, 0.0f, 0.0f);
@@ -127,14 +125,13 @@ void EchoState::process(const size_t samplesToDo, const al::span<const FloatBuff
const size_t mask{mSampleBuffer.size()-1};
float *RESTRICT delaybuf{mSampleBuffer.data()};
size_t offset{mOffset};
- size_t tap1{offset - mTap[0].delay};
- size_t tap2{offset - mTap[1].delay};
- float z1, z2;
+ size_t tap1{offset - mDelayTap[0]};
+ size_t tap2{offset - mDelayTap[1]};
ASSUME(samplesToDo > 0);
const BiquadFilter filter{mFilter};
- std::tie(z1, z2) = mFilter.getComponents();
+ auto [z1, z2] = mFilter.getComponents();
for(size_t i{0u};i < samplesToDo;)
{
offset &= mask;
@@ -161,8 +158,8 @@ void EchoState::process(const size_t samplesToDo, const al::span<const FloatBuff
mOffset = offset;
for(size_t c{0};c < 2;c++)
- MixSamples({mTempBuffer[c], samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target,
- samplesToDo, 0);
+ MixSamples({mTempBuffer[c].data(), samplesToDo}, samplesOut, mGains[c].Current.data(),
+ mGains[c].Target.data(), samplesToDo, 0);
}
diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp
index 50bec4ad..165d00f2 100644
--- a/alc/effects/equalizer.cpp
+++ b/alc/effects/equalizer.cpp
@@ -86,16 +86,17 @@ namespace {
struct EqualizerState final : public EffectState {
- struct {
+ struct OutParams {
uint mTargetChannel{InvalidChannelIndex};
/* Effect parameters */
- BiquadFilter mFilter[4];
+ std::array<BiquadFilter,4> mFilter;
/* Effect gains for each channel */
float mCurrentGain{};
float mTargetGain{};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<OutParams,MaxAmbiChannels> mChans;
alignas(16) FloatBufferLine mSampleBuffer{};
@@ -105,8 +106,6 @@ struct EqualizerState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(EqualizerState)
};
void EqualizerState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -114,18 +113,17 @@ void EqualizerState::deviceUpdate(const DeviceBase*, const BufferStorage*)
for(auto &e : mChans)
{
e.mTargetChannel = InvalidChannelIndex;
- std::for_each(std::begin(e.mFilter), std::end(e.mFilter),
- std::mem_fn(&BiquadFilter::clear));
+ std::for_each(e.mFilter.begin(), e.mFilter.end(), std::mem_fn(&BiquadFilter::clear));
e.mCurrentGain = 0.0f;
}
}
void EqualizerState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<EqualizerProps>(*props_);
const DeviceBase *device{context->mDevice};
auto frequency = static_cast<float>(device->Frequency);
- float gain, f0norm;
/* Calculate coefficients for the each type of filter. Note that the shelf
* and peaking filters' gain is for the centerpoint of the transition band,
@@ -133,22 +131,22 @@ void EqualizerState::update(const ContextBase *context, const EffectSlot *slot,
* property gains need their dB halved (sqrt of linear gain) for the
* shelf/peak to reach the provided gain.
*/
- gain = std::sqrt(props->Equalizer.LowGain);
- f0norm = props->Equalizer.LowCutoff / frequency;
+ float gain{std::sqrt(props.LowGain)};
+ float f0norm{props.LowCutoff / frequency};
mChans[0].mFilter[0].setParamsFromSlope(BiquadType::LowShelf, f0norm, gain, 0.75f);
- gain = std::sqrt(props->Equalizer.Mid1Gain);
- f0norm = props->Equalizer.Mid1Center / frequency;
+ gain = std::sqrt(props.Mid1Gain);
+ f0norm = props.Mid1Center / frequency;
mChans[0].mFilter[1].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
- props->Equalizer.Mid1Width);
+ props.Mid1Width);
- gain = std::sqrt(props->Equalizer.Mid2Gain);
- f0norm = props->Equalizer.Mid2Center / frequency;
+ gain = std::sqrt(props.Mid2Gain);
+ f0norm = props.Mid2Center / frequency;
mChans[0].mFilter[2].setParamsFromBandwidth(BiquadType::Peaking, f0norm, gain,
- props->Equalizer.Mid2Width);
+ props.Mid2Width);
- gain = std::sqrt(props->Equalizer.HighGain);
- f0norm = props->Equalizer.HighCutoff / frequency;
+ gain = std::sqrt(props.HighGain);
+ f0norm = props.HighCutoff / frequency;
mChans[0].mFilter[3].setParamsFromSlope(BiquadType::HighShelf, f0norm, gain, 0.75f);
/* Copy the filter coefficients for the other input channels. */
diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp
index d3989e84..076661cf 100644
--- a/alc/effects/fshifter.cpp
+++ b/alc/effects/fshifter.cpp
@@ -57,7 +57,7 @@ constexpr size_t HilStep{HilSize / OversampleFactor};
/* Define a Hann window, used to filter the HIL input and output. */
struct Windower {
- alignas(16) std::array<double,HilSize> mData;
+ alignas(16) std::array<double,HilSize> mData{};
Windower()
{
@@ -91,10 +91,11 @@ struct FshifterState final : public EffectState {
alignas(16) FloatBufferLine mBufferOut{};
/* Effect gains for each output channel */
- struct {
- float Current[MaxAmbiChannels]{};
- float Target[MaxAmbiChannels]{};
- } mGains[2];
+ struct OutGains {
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
+ };
+ std::array<OutGains,2> mGains;
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -102,8 +103,6 @@ struct FshifterState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(FshifterState)
};
void FshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -122,20 +121,21 @@ void FshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
for(auto &gain : mGains)
{
- std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f);
- std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f);
+ gain.Current.fill(0.0f);
+ gain.Target.fill(0.0f);
}
}
void FshifterState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<FshifterProps>(*props_);
const DeviceBase *device{context->mDevice};
- const float step{props->Fshifter.Frequency / static_cast<float>(device->Frequency)};
+ const float step{props.Frequency / static_cast<float>(device->Frequency)};
mPhaseStep[0] = mPhaseStep[1] = fastf2u(minf(step, 1.0f) * MixerFracOne);
- switch(props->Fshifter.LeftDirection)
+ switch(props.LeftDirection)
{
case FShifterDirection::Down:
mSign[0] = -1.0;
@@ -149,7 +149,7 @@ void FshifterState::update(const ContextBase *context, const EffectSlot *slot,
break;
}
- switch(props->Fshifter.RightDirection)
+ switch(props.RightDirection)
{
case FShifterDirection::Down:
mSign[1] = -1.0;
@@ -235,8 +235,8 @@ void FshifterState::process(const size_t samplesToDo, const al::span<const Float
mPhase[c] = phase_idx;
/* Now, mix the processed sound data to the output. */
- MixSamples({BufferOut, samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target,
- maxz(samplesToDo, 512), 0);
+ MixSamples({BufferOut, samplesToDo}, samplesOut, mGains[c].Current.data(),
+ mGains[c].Target.data(), maxz(samplesToDo, 512), 0);
}
}
diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp
index f99ba19c..7350ca5a 100644
--- a/alc/effects/modulator.cpp
+++ b/alc/effects/modulator.cpp
@@ -52,7 +52,7 @@ inline float Saw(uint index, float scale)
{ return static_cast<float>(index)*scale - 1.0f; }
inline float Square(uint index, float scale)
-{ return (static_cast<float>(index)*scale < 0.5f)*2.0f - 1.0f; }
+{ return float(static_cast<float>(index)*scale < 0.5f)*2.0f - 1.0f; }
inline float One(uint, float)
{ return 1.0f; }
@@ -89,14 +89,15 @@ struct ModulatorState final : public EffectState {
alignas(16) FloatBufferLine mModSamples{};
alignas(16) FloatBufferLine mBuffer{};
- struct {
+ struct OutParams {
uint mTargetChannel{InvalidChannelIndex};
BiquadFilter mFilter;
float mCurrentGain{};
float mTargetGain{};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<OutParams,MaxAmbiChannels> mChans;
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -104,8 +105,6 @@ struct ModulatorState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(ModulatorState)
};
template<>
@@ -126,8 +125,9 @@ void ModulatorState::deviceUpdate(const DeviceBase*, const BufferStorage*)
}
void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<ModulatorProps>(*props_);
const DeviceBase *device{context->mDevice};
/* The effective frequency will be adjusted to have a whole number of
@@ -137,8 +137,8 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
* but that may need a more efficient sin function since it needs to do
* many iterations per sample.
*/
- const float samplesPerCycle{props->Modulator.Frequency > 0.0f
- ? static_cast<float>(device->Frequency)/props->Modulator.Frequency + 0.5f
+ const float samplesPerCycle{props.Frequency > 0.0f
+ ? static_cast<float>(device->Frequency)/props.Frequency + 0.5f
: 1.0f};
const uint range{static_cast<uint>(clampf(samplesPerCycle, 1.0f,
static_cast<float>(device->Frequency)))};
@@ -150,17 +150,17 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
mIndexScale = 0.0f;
mGenModSamples = &ModulatorState::Modulate<One>;
}
- else if(props->Modulator.Waveform == ModulatorWaveform::Sinusoid)
+ else if(props.Waveform == ModulatorWaveform::Sinusoid)
{
mIndexScale = al::numbers::pi_v<float>*2.0f / static_cast<float>(mRange);
mGenModSamples = &ModulatorState::Modulate<Sin>;
}
- else if(props->Modulator.Waveform == ModulatorWaveform::Sawtooth)
+ else if(props.Waveform == ModulatorWaveform::Sawtooth)
{
mIndexScale = 2.0f / static_cast<float>(mRange-1);
mGenModSamples = &ModulatorState::Modulate<Saw>;
}
- else /*if(props->Modulator.Waveform == ModulatorWaveform::Square)*/
+ else /*if(props.Waveform == ModulatorWaveform::Square)*/
{
/* For square wave, the range should be even (there should be an equal
* number of high and low samples). An odd number of samples per cycle
@@ -171,7 +171,7 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
mGenModSamples = &ModulatorState::Modulate<Square>;
}
- float f0norm{props->Modulator.HighPassCutoff / static_cast<float>(device->Frequency)};
+ float f0norm{props.HighPassCutoff / static_cast<float>(device->Frequency)};
f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f);
/* Bandwidth value is constant in octaves. */
mChans[0].mFilter.setParamsFromBandwidth(BiquadType::HighPass, f0norm, 1.0f, 0.75f);
diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp
index 1f9ae67b..964afe47 100644
--- a/alc/effects/null.cpp
+++ b/alc/effects/null.cpp
@@ -1,7 +1,7 @@
#include "config.h"
-#include <stddef.h>
+#include <cstddef>
#include "almalloc.h"
#include "alspan.h"
@@ -25,8 +25,6 @@ struct NullState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(NullState)
};
/* This constructs the effect state. It's called when the object is first
diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp
index 0c27be30..1cc1a18c 100644
--- a/alc/effects/pshifter.cpp
+++ b/alc/effects/pshifter.cpp
@@ -58,7 +58,7 @@ constexpr size_t StftStep{StftSize / OversampleFactor};
/* Define a Hann window, used to filter the STFT input and output. */
struct Windower {
- alignas(16) std::array<float,StftSize> mData;
+ alignas(16) std::array<float,StftSize> mData{};
Windower()
{
@@ -74,12 +74,6 @@ struct Windower {
const Windower gWindow{};
-struct PFFFTSetupDeleter {
- void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); }
-};
-using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>;
-
-
struct FrequencyBin {
float Magnitude;
float FreqBin;
@@ -88,29 +82,29 @@ struct FrequencyBin {
struct PshifterState final : public EffectState {
/* Effect parameters */
- size_t mCount;
- size_t mPos;
- uint mPitchShiftI;
- float mPitchShift;
+ size_t mCount{};
+ size_t mPos{};
+ uint mPitchShiftI{};
+ float mPitchShift{};
/* Effects buffers */
- std::array<float,StftSize> mFIFO;
- std::array<float,StftHalfSize+1> mLastPhase;
- std::array<float,StftHalfSize+1> mSumPhase;
- std::array<float,StftSize> mOutputAccum;
+ std::array<float,StftSize> mFIFO{};
+ std::array<float,StftHalfSize+1> mLastPhase{};
+ std::array<float,StftHalfSize+1> mSumPhase{};
+ std::array<float,StftSize> mOutputAccum{};
- PFFFTSetupPtr mFft;
- alignas(16) std::array<float,StftSize> mFftBuffer;
- alignas(16) std::array<float,StftSize> mFftWorkBuffer;
+ PFFFTSetup mFft;
+ alignas(16) std::array<float,StftSize> mFftBuffer{};
+ alignas(16) std::array<float,StftSize> mFftWorkBuffer{};
- std::array<FrequencyBin,StftHalfSize+1> mAnalysisBuffer;
- std::array<FrequencyBin,StftHalfSize+1> mSynthesisBuffer;
+ std::array<FrequencyBin,StftHalfSize+1> mAnalysisBuffer{};
+ std::array<FrequencyBin,StftHalfSize+1> mSynthesisBuffer{};
- alignas(16) FloatBufferLine mBufferOut;
+ alignas(16) FloatBufferLine mBufferOut{};
/* Effect gains for each output channel */
- float mCurrentGains[MaxAmbiChannels];
- float mTargetGains[MaxAmbiChannels];
+ std::array<float,MaxAmbiChannels> mCurrentGains{};
+ std::array<float,MaxAmbiChannels> mTargetGains{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
@@ -118,8 +112,6 @@ struct PshifterState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(PshifterState)
};
void PshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
@@ -138,17 +130,18 @@ void PshifterState::deviceUpdate(const DeviceBase*, const BufferStorage*)
mAnalysisBuffer.fill(FrequencyBin{});
mSynthesisBuffer.fill(FrequencyBin{});
- std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
- std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
+ mCurrentGains.fill(0.0f);
+ mTargetGains.fill(0.0f);
if(!mFft)
- mFft = PFFFTSetupPtr{pffft_new_setup(StftSize, PFFFT_REAL)};
+ mFft = PFFFTSetup{StftSize, PFFFT_REAL};
}
void PshifterState::update(const ContextBase*, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
- const int tune{props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune};
+ auto &props = std::get<PshifterProps>(*props_);
+ const int tune{props.CoarseTune*100 + props.FineTune};
const float pitch{std::pow(2.0f, static_cast<float>(tune) / 1200.0f)};
mPitchShiftI = clampu(fastf2u(pitch*MixerFracOne), MixerFracHalf, MixerFracOne*2);
mPitchShift = static_cast<float>(mPitchShiftI) * float{1.0f/MixerFracOne};
@@ -197,8 +190,8 @@ void PshifterState::process(const size_t samplesToDo,
mFftBuffer[k] = mFIFO[src] * gWindow.mData[k];
for(size_t src{0u}, k{StftSize-mPos};src < mPos;++src,++k)
mFftBuffer[k] = mFIFO[src] * gWindow.mData[k];
- pffft_transform_ordered(mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mFftWorkBuffer.data(), PFFFT_FORWARD);
+ mFft.transform_ordered(mFftBuffer.data(), mFftBuffer.data(), mFftWorkBuffer.data(),
+ PFFFT_FORWARD);
/* Analyze the obtained data. Since the real FFT is symmetric, only
* StftHalfSize+1 samples are needed.
@@ -296,8 +289,8 @@ void PshifterState::process(const size_t samplesToDo,
/* Apply an inverse FFT to get the time-domain signal, and accumulate
* for the output with windowing.
*/
- pffft_transform_ordered(mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mFftWorkBuffer.data(), PFFFT_BACKWARD);
+ mFft.transform_ordered(mFftBuffer.data(), mFftBuffer.data(), mFftWorkBuffer.data(),
+ PFFFT_BACKWARD);
static constexpr float scale{3.0f / OversampleFactor / StftSize};
for(size_t dst{mPos}, k{0u};dst < StftSize;++dst,++k)
@@ -311,8 +304,8 @@ void PshifterState::process(const size_t samplesToDo,
}
/* Now, mix the processed sound data to the output. */
- MixSamples({mBufferOut.data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains,
- maxz(samplesToDo, 512), 0);
+ MixSamples({mBufferOut.data(), samplesToDo}, samplesOut, mCurrentGains.data(),
+ mTargetGains.data(), maxz(samplesToDo, 512), 0);
}
diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp
index 0f1fcca1..45bfaf0f 100644
--- a/alc/effects/reverb.cpp
+++ b/alc/effects/reverb.cpp
@@ -22,11 +22,12 @@
#include <algorithm>
#include <array>
+#include <cassert>
+#include <cstdint>
#include <cstdio>
#include <functional>
#include <iterator>
#include <numeric>
-#include <stdint.h>
#include "alc/effects/base.h"
#include "almalloc.h"
@@ -48,11 +49,6 @@
#include "vecmat.h"
#include "vector.h"
-/* This is a user config option for modifying the overall output of the reverb
- * effect.
- */
-float ReverbBoost = 1.0f;
-
namespace {
using uint = unsigned int;
@@ -70,7 +66,7 @@ struct CubicFilter {
static constexpr size_t sTableSteps{1 << sTableBits};
static constexpr size_t sTableMask{sTableSteps - 1};
- float mFilter[sTableSteps*2 + 1]{};
+ std::array<float,sTableSteps*2 + 1> mFilter{};
constexpr CubicFilter()
{
@@ -90,10 +86,14 @@ struct CubicFilter {
}
}
- constexpr float getCoeff0(size_t i) const noexcept { return mFilter[sTableSteps+i]; }
- constexpr float getCoeff1(size_t i) const noexcept { return mFilter[i]; }
- constexpr float getCoeff2(size_t i) const noexcept { return mFilter[sTableSteps-i]; }
- constexpr float getCoeff3(size_t i) const noexcept { return mFilter[sTableSteps*2-i]; }
+ [[nodiscard]] constexpr auto getCoeff0(size_t i) const noexcept -> float
+ { return mFilter[sTableSteps+i]; }
+ [[nodiscard]] constexpr auto getCoeff1(size_t i) const noexcept -> float
+ { return mFilter[i]; }
+ [[nodiscard]] constexpr auto getCoeff2(size_t i) const noexcept -> float
+ { return mFilter[sTableSteps-i]; }
+ [[nodiscard]] constexpr auto getCoeff3(size_t i) const noexcept -> float
+ { return mFilter[sTableSteps*2-i]; }
};
constexpr CubicFilter gCubicTable;
@@ -124,12 +124,12 @@ constexpr float MODULATION_DEPTH_COEFF{0.05f};
* tetrahedral array of discrete signals (boosted by a factor of sqrt(3), to
* reduce the error introduced in the conversion).
*/
-alignas(16) constexpr float B2A[NUM_LINES][NUM_LINES]{
- { 0.5f, 0.5f, 0.5f, 0.5f },
- { 0.5f, -0.5f, -0.5f, 0.5f },
- { 0.5f, 0.5f, -0.5f, -0.5f },
- { 0.5f, -0.5f, 0.5f, -0.5f }
-};
+alignas(16) constexpr std::array<std::array<float,NUM_LINES>,NUM_LINES> B2A{{
+ {{ 0.5f, 0.5f, 0.5f, 0.5f }},
+ {{ 0.5f, -0.5f, -0.5f, 0.5f }},
+ {{ 0.5f, 0.5f, -0.5f, -0.5f }},
+ {{ 0.5f, -0.5f, 0.5f, -0.5f }}
+}};
/* Converts (W-normalized) A-Format to B-Format for early reflections (scaled
* by 1/sqrt(3) to compensate for the boost in the B2A matrix).
@@ -252,7 +252,7 @@ constexpr std::array<float,NUM_LINES> EARLY_ALLPASS_LENGTHS{{
* Using an average dimension of 1m, we get:
*/
constexpr std::array<float,NUM_LINES> EARLY_LINE_LENGTHS{{
- 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f
+ 0.0000000e+0f, 4.9281100e-4f, 9.3916180e-4f, 1.3434322e-3f
}};
/* The late all-pass filter lengths are based on the late line lengths:
@@ -290,20 +290,16 @@ struct DelayLineI {
* of 2 to allow the use of bit-masking instead of a modulus for wrapping.
*/
size_t Mask{0u};
- union {
- uintptr_t LineOffset{0u};
- std::array<float,NUM_LINES> *Line;
- };
+ std::array<float,NUM_LINES> *Line;
/* Given the allocated sample buffer, this function updates each delay line
* offset.
*/
void realizeLineOffset(std::array<float,NUM_LINES> *sampleBuffer) noexcept
- { Line = sampleBuffer + LineOffset; }
+ { Line = sampleBuffer; }
/* Calculate the length of a delay line and store its mask and offset. */
- uint calcLineLength(const float length, const uintptr_t offset, const float frequency,
- const uint extra)
+ size_t calcLineLength(const float length, const float frequency, const uint extra)
{
/* All line lengths are powers of 2, calculated from their lengths in
* seconds, rounded up.
@@ -313,7 +309,6 @@ struct DelayLineI {
/* All lines share a single sample buffer. */
Mask = samples - 1;
- LineOffset = offset;
/* Return the sample count for accumulation. */
return samples;
@@ -369,7 +364,7 @@ struct DelayLineI {
struct VecAllpass {
DelayLineI Delay;
float Coeff{0.0f};
- size_t Offset[NUM_LINES]{};
+ std::array<size_t,NUM_LINES> Offset{};
void process(const al::span<ReverbUpdateLine,NUM_LINES> samples, size_t offset,
const float xCoeff, const float yCoeff, const size_t todo);
@@ -402,12 +397,12 @@ struct EarlyReflections {
* reflections.
*/
DelayLineI Delay;
- size_t Offset[NUM_LINES]{};
- float Coeff[NUM_LINES]{};
+ std::array<size_t,NUM_LINES> Offset{};
+ std::array<float,NUM_LINES> Coeff{};
/* The gain for each output channel based on 3D panning. */
- float CurrentGains[NUM_LINES][MaxAmbiChannels]{};
- float TargetGains[NUM_LINES][MaxAmbiChannels]{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> CurrentGains{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> TargetGains{};
void updateLines(const float density_mult, const float diffusion, const float decayTime,
const float frequency);
@@ -418,12 +413,12 @@ struct Modulation {
/* The vibrato time is tracked with an index over a (MOD_FRACONE)
* normalized range.
*/
- uint Index, Step;
+ uint Index{}, Step{};
/* The depth of frequency change, in samples. */
- float Depth;
+ float Depth{};
- float ModDelays[MAX_UPDATE_SAMPLES];
+ std::array<float,MAX_UPDATE_SAMPLES> ModDelays{};
void updateModulator(float modTime, float modDepth, float frequency);
@@ -433,7 +428,7 @@ struct Modulation {
struct LateReverb {
/* A recursive delay line is used fill in the reverb tail. */
DelayLineI Delay;
- size_t Offset[NUM_LINES]{};
+ std::array<size_t,NUM_LINES> Offset{};
/* Attenuation to compensate for the modal density and decay rate of the
* late lines.
@@ -441,7 +436,7 @@ struct LateReverb {
float DensityGain{0.0f};
/* T60 decay filters are used to simulate absorption. */
- T60Filter T60[NUM_LINES];
+ std::array<T60Filter,NUM_LINES> T60;
Modulation Mod;
@@ -449,8 +444,8 @@ struct LateReverb {
VecAllpass VecAp;
/* The gain for each output channel based on 3D panning. */
- float CurrentGains[NUM_LINES][MaxAmbiChannels]{};
- float TargetGains[NUM_LINES][MaxAmbiChannels]{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> CurrentGains{};
+ std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> TargetGains{};
void updateLines(const float density_mult, const float diffusion, const float lfDecayTime,
const float mfDecayTime, const float hfDecayTime, const float lf0norm,
@@ -465,21 +460,22 @@ struct LateReverb {
struct ReverbPipeline {
/* Master effect filters */
- struct {
+ struct FilterPair {
BiquadFilter Lp;
BiquadFilter Hp;
- } mFilter[NUM_LINES];
+ };
+ std::array<FilterPair,NUM_LINES> mFilter;
/* Core delay line (early reflections and late reverb tap from this). */
DelayLineI mEarlyDelayIn;
DelayLineI mLateDelayIn;
/* Tap points for early reflection delay. */
- size_t mEarlyDelayTap[NUM_LINES][2]{};
- float mEarlyDelayCoeff[NUM_LINES]{};
+ std::array<std::array<size_t,2>,NUM_LINES> mEarlyDelayTap{};
+ std::array<float,NUM_LINES> mEarlyDelayCoeff{};
/* Tap points for late reverb feed and delay. */
- size_t mLateDelayTap[NUM_LINES][2]{};
+ std::array<std::array<size_t,2>,NUM_LINES> mLateDelayTap{};
/* Coefficients for the all-pass and line scattering matrices. */
float mMixX{0.0f};
@@ -551,9 +547,9 @@ struct ReverbState final : public EffectState {
Normal,
};
PipelineState mPipelineState{DeviceClear};
- uint8_t mCurrentPipeline{0};
+ bool mCurrentPipeline{false};
- ReverbPipeline mPipelines[2];
+ std::array<ReverbPipeline,2> mPipelines;
/* The current write offset for all delay lines. */
size_t mOffset{};
@@ -582,14 +578,14 @@ struct ReverbState final : public EffectState {
for(size_t c{0u};c < NUM_LINES;c++)
{
const al::span<float> tmpspan{mEarlySamples[c].data(), todo};
- MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c],
- pipeline.mEarly.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c].data(),
+ pipeline.mEarly.TargetGains[c].data(), todo, 0);
}
for(size_t c{0u};c < NUM_LINES;c++)
{
const al::span<float> tmpspan{mLateSamples[c].data(), todo};
- MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c],
- pipeline.mLate.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c].data(),
+ pipeline.mLate.TargetGains[c].data(), todo, 0);
}
}
@@ -632,8 +628,8 @@ struct ReverbState final : public EffectState {
const float hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
pipeline.mAmbiSplitter[0][c].processHfScale(tmpspan, hfscale);
- MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c],
- pipeline.mEarly.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mEarly.CurrentGains[c].data(),
+ pipeline.mEarly.TargetGains[c].data(), todo, 0);
}
for(size_t c{0u};c < NUM_LINES;c++)
{
@@ -642,8 +638,8 @@ struct ReverbState final : public EffectState {
const float hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
pipeline.mAmbiSplitter[1][c].processHfScale(tmpspan, hfscale);
- MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c],
- pipeline.mLate.TargetGains[c], todo, 0);
+ MixSamples(tmpspan, samplesOut, pipeline.mLate.CurrentGains[c].data(),
+ pipeline.mLate.TargetGains[c].data(), todo, 0);
}
}
@@ -662,8 +658,6 @@ struct ReverbState final : public EffectState {
const EffectTarget target) override;
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
-
- DEF_NEWDEL(ReverbState)
};
/**************************************
@@ -678,11 +672,6 @@ inline float CalcDelayLengthMult(float density)
*/
void ReverbState::allocLines(const float frequency)
{
- /* All delay line lengths are calculated to accommodate the full range of
- * lengths given their respective parameters.
- */
- size_t totalSamples{0u};
-
/* Multiplier for the maximum density value, i.e. density=1, which is
* actually the least density...
*/
@@ -692,8 +681,12 @@ void ReverbState::allocLines(const float frequency)
* time and depth coefficient, and halfed for the low-to-high frequency
* swing.
*/
- constexpr float max_mod_delay{MaxModulationTime*MODULATION_DEPTH_COEFF / 2.0f};
+ static constexpr float max_mod_delay{MaxModulationTime*MODULATION_DEPTH_COEFF / 2.0f};
+
+ std::array<size_t,12> lineoffsets{};
+ size_t oidx{0};
+ size_t totalSamples{0u};
for(auto &pipeline : mPipelines)
{
/* The main delay length includes the maximum early reflection delay,
@@ -702,37 +695,45 @@ void ReverbState::allocLines(const float frequency)
* update size (BufferLineSize) for block processing.
*/
float length{ReverbMaxReflectionsDelay + EARLY_TAP_LENGTHS.back()*multiplier};
- totalSamples += pipeline.mEarlyDelayIn.calcLineLength(length, totalSamples, frequency,
- BufferLineSize);
+ size_t count{pipeline.mEarlyDelayIn.calcLineLength(length, frequency, BufferLineSize)};
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
- constexpr float LateLineDiffAvg{(LATE_LINE_LENGTHS.back()-LATE_LINE_LENGTHS.front()) /
+ static constexpr float LateDiffAvg{(LATE_LINE_LENGTHS.back()-LATE_LINE_LENGTHS.front()) /
float{NUM_LINES}};
- length = ReverbMaxLateReverbDelay + LateLineDiffAvg*multiplier;
- totalSamples += pipeline.mLateDelayIn.calcLineLength(length, totalSamples, frequency,
- BufferLineSize);
+ length = ReverbMaxLateReverbDelay + LateDiffAvg*multiplier;
+ count = pipeline.mLateDelayIn.calcLineLength(length, frequency, BufferLineSize);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The early vector all-pass line. */
length = EARLY_ALLPASS_LENGTHS.back() * multiplier;
- totalSamples += pipeline.mEarly.VecAp.Delay.calcLineLength(length, totalSamples, frequency,
- 0);
+ count = pipeline.mEarly.VecAp.Delay.calcLineLength(length, frequency, 0);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The early reflection line. */
length = EARLY_LINE_LENGTHS.back() * multiplier;
- totalSamples += pipeline.mEarly.Delay.calcLineLength(length, totalSamples, frequency,
- MAX_UPDATE_SAMPLES);
+ count = pipeline.mEarly.Delay.calcLineLength(length, frequency, MAX_UPDATE_SAMPLES);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The late vector all-pass line. */
length = LATE_ALLPASS_LENGTHS.back() * multiplier;
- totalSamples += pipeline.mLate.VecAp.Delay.calcLineLength(length, totalSamples, frequency,
- 0);
+ count = pipeline.mLate.VecAp.Delay.calcLineLength(length, frequency, 0);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
/* The late delay lines are calculated from the largest maximum density
* line length, and the maximum modulation delay. Four additional
* samples are needed for resampling the modulator delay.
*/
length = LATE_LINE_LENGTHS.back()*multiplier + max_mod_delay;
- totalSamples += pipeline.mLate.Delay.calcLineLength(length, totalSamples, frequency, 4);
+ count = pipeline.mLate.Delay.calcLineLength(length, frequency, 4);
+ lineoffsets[oidx++] = totalSamples;
+ totalSamples += count;
}
+ assert(oidx == lineoffsets.size());
if(totalSamples != mSampleBuffer.size())
decltype(mSampleBuffer)(totalSamples).swap(mSampleBuffer);
@@ -741,14 +742,15 @@ void ReverbState::allocLines(const float frequency)
std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), decltype(mSampleBuffer)::value_type{});
/* Update all delays to reflect the new sample buffer. */
+ oidx = 0;
for(auto &pipeline : mPipelines)
{
- pipeline.mEarlyDelayIn.realizeLineOffset(mSampleBuffer.data());
- pipeline.mLateDelayIn.realizeLineOffset(mSampleBuffer.data());
- pipeline.mEarly.VecAp.Delay.realizeLineOffset(mSampleBuffer.data());
- pipeline.mEarly.Delay.realizeLineOffset(mSampleBuffer.data());
- pipeline.mLate.VecAp.Delay.realizeLineOffset(mSampleBuffer.data());
- pipeline.mLate.Delay.realizeLineOffset(mSampleBuffer.data());
+ pipeline.mEarlyDelayIn.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mLateDelayIn.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mEarly.VecAp.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mEarly.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mLate.VecAp.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
+ pipeline.mLate.Delay.realizeLineOffset(mSampleBuffer.data() + lineoffsets[oidx++]);
}
}
@@ -761,17 +763,16 @@ void ReverbState::deviceUpdate(const DeviceBase *device, const BufferStorage*)
for(auto &pipeline : mPipelines)
{
- /* Clear filters and gain coefficients since the delay lines were all just
- * cleared (if not reallocated).
- */
+ /* Clear filters and gain coefficients since the delay lines were all
+ * just cleared (if not reallocated).
+ */
for(auto &filter : pipeline.mFilter)
{
filter.Lp.clear();
filter.Hp.clear();
}
- std::fill(std::begin(pipeline.mEarlyDelayCoeff),std::end(pipeline.mEarlyDelayCoeff), 0.0f);
- std::fill(std::begin(pipeline.mEarlyDelayCoeff),std::end(pipeline.mEarlyDelayCoeff), 0.0f);
+ pipeline.mEarlyDelayCoeff.fill(0.0f);
pipeline.mLate.DensityGain = 0.0f;
for(auto &t60 : pipeline.mLate.T60)
@@ -786,13 +787,13 @@ void ReverbState::deviceUpdate(const DeviceBase *device, const BufferStorage*)
pipeline.mLate.Mod.Depth = 0.0f;
for(auto &gains : pipeline.mEarly.CurrentGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
for(auto &gains : pipeline.mEarly.TargetGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
for(auto &gains : pipeline.mLate.CurrentGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
for(auto &gains : pipeline.mLate.TargetGains)
- std::fill(std::begin(gains), std::end(gains), 0.0f);
+ gains.fill(0.0f);
}
mPipelineState = DeviceClear;
@@ -1057,7 +1058,7 @@ void ReverbPipeline::updateDelayLine(const float earlyDelay, const float lateDel
* output.
*/
length = (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())/float{NUM_LINES}*density_mult +
- std::max(lateDelay - EARLY_LINE_LENGTHS[0]*density_mult, 0.0f);
+ lateDelay;
mLateDelayTap[i][1] = float2uint(length * frequency);
}
}
@@ -1076,7 +1077,7 @@ std::array<std::array<float,4>,4> GetTransformFromVector(const al::span<const fl
* rest of OpenAL which use right-handed. This is fixed by negating Z,
* which cancels out with the B-Format Z negation.
*/
- float norm[3];
+ std::array<float,3> norm;
float mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])};
if(mag > 1.0f)
{
@@ -1185,75 +1186,73 @@ void ReverbPipeline::update3DPanning(const al::span<const float,3> ReflectionsPa
}
void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<ReverbProps>(*props_);
const DeviceBase *Device{Context->mDevice};
const auto frequency = static_cast<float>(Device->Frequency);
/* If the HF limit parameter is flagged, calculate an appropriate limit
* based on the air absorption parameter.
*/
- float hfRatio{props->Reverb.DecayHFRatio};
- if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f)
- hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF,
- props->Reverb.DecayTime);
+ float hfRatio{props.DecayHFRatio};
+ if(props.DecayHFLimit && props.AirAbsorptionGainHF < 1.0f)
+ hfRatio = CalcLimitedHfRatio(hfRatio, props.AirAbsorptionGainHF, props.DecayTime);
/* Calculate the LF/HF decay times. */
constexpr float MinDecayTime{0.1f}, MaxDecayTime{20.0f};
- const float lfDecayTime{clampf(props->Reverb.DecayTime*props->Reverb.DecayLFRatio,
- MinDecayTime, MaxDecayTime)};
- const float hfDecayTime{clampf(props->Reverb.DecayTime*hfRatio, MinDecayTime, MaxDecayTime)};
+ const float lfDecayTime{clampf(props.DecayTime*props.DecayLFRatio, MinDecayTime,MaxDecayTime)};
+ const float hfDecayTime{clampf(props.DecayTime*hfRatio, MinDecayTime, MaxDecayTime)};
/* Determine if a full update is required. */
const bool fullUpdate{mPipelineState == DeviceClear ||
/* Density is essentially a master control for the feedback delays, so
* changes the offsets of many delay lines.
*/
- mParams.Density != props->Reverb.Density ||
+ mParams.Density != props.Density ||
/* Diffusion and decay times influences the decay rate (gain) of the
* late reverb T60 filter.
*/
- mParams.Diffusion != props->Reverb.Diffusion ||
- mParams.DecayTime != props->Reverb.DecayTime ||
+ mParams.Diffusion != props.Diffusion ||
+ mParams.DecayTime != props.DecayTime ||
mParams.HFDecayTime != hfDecayTime ||
mParams.LFDecayTime != lfDecayTime ||
/* Modulation time and depth both require fading the modulation delay. */
- mParams.ModulationTime != props->Reverb.ModulationTime ||
- mParams.ModulationDepth != props->Reverb.ModulationDepth ||
+ mParams.ModulationTime != props.ModulationTime ||
+ mParams.ModulationDepth != props.ModulationDepth ||
/* HF/LF References control the weighting used to calculate the density
* gain.
*/
- mParams.HFReference != props->Reverb.HFReference ||
- mParams.LFReference != props->Reverb.LFReference};
+ mParams.HFReference != props.HFReference ||
+ mParams.LFReference != props.LFReference};
if(fullUpdate)
{
- mParams.Density = props->Reverb.Density;
- mParams.Diffusion = props->Reverb.Diffusion;
- mParams.DecayTime = props->Reverb.DecayTime;
+ mParams.Density = props.Density;
+ mParams.Diffusion = props.Diffusion;
+ mParams.DecayTime = props.DecayTime;
mParams.HFDecayTime = hfDecayTime;
mParams.LFDecayTime = lfDecayTime;
- mParams.ModulationTime = props->Reverb.ModulationTime;
- mParams.ModulationDepth = props->Reverb.ModulationDepth;
- mParams.HFReference = props->Reverb.HFReference;
- mParams.LFReference = props->Reverb.LFReference;
+ mParams.ModulationTime = props.ModulationTime;
+ mParams.ModulationDepth = props.ModulationDepth;
+ mParams.HFReference = props.HFReference;
+ mParams.LFReference = props.LFReference;
mPipelineState = (mPipelineState != DeviceClear) ? StartFade : Normal;
- mCurrentPipeline ^= 1;
+ mCurrentPipeline = !mCurrentPipeline;
}
auto &pipeline = mPipelines[mCurrentPipeline];
/* Update early and late 3D panning. */
mOutTarget = target.Main->Buffer;
- const float gain{props->Reverb.Gain * Slot->Gain * ReverbBoost};
- pipeline.update3DPanning(props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan,
- props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, mUpmixOutput,
- target.Main);
+ const float gain{props.Gain * Slot->Gain * ReverbBoost};
+ pipeline.update3DPanning(props.ReflectionsPan, props.LateReverbPan, props.ReflectionsGain*gain,
+ props.LateReverbGain*gain, mUpmixOutput, target.Main);
/* Calculate the master filters */
- float hf0norm{minf(props->Reverb.HFReference/frequency, 0.49f)};
- pipeline.mFilter[0].Lp.setParamsFromSlope(BiquadType::HighShelf, hf0norm, props->Reverb.GainHF, 1.0f);
- float lf0norm{minf(props->Reverb.LFReference/frequency, 0.49f)};
- pipeline.mFilter[0].Hp.setParamsFromSlope(BiquadType::LowShelf, lf0norm, props->Reverb.GainLF, 1.0f);
+ float hf0norm{minf(props.HFReference/frequency, 0.49f)};
+ pipeline.mFilter[0].Lp.setParamsFromSlope(BiquadType::HighShelf, hf0norm, props.GainHF, 1.0f);
+ float lf0norm{minf(props.LFReference/frequency, 0.49f)};
+ pipeline.mFilter[0].Hp.setParamsFromSlope(BiquadType::LowShelf, lf0norm, props.GainLF, 1.0f);
for(size_t i{1u};i < NUM_LINES;i++)
{
pipeline.mFilter[i].Lp.copyParamsFrom(pipeline.mFilter[0].Lp);
@@ -1261,34 +1260,32 @@ void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
}
/* The density-based room size (delay length) multiplier. */
- const float density_mult{CalcDelayLengthMult(props->Reverb.Density)};
+ const float density_mult{CalcDelayLengthMult(props.Density)};
/* Update the main effect delay and associated taps. */
- pipeline.updateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
- density_mult, props->Reverb.DecayTime, frequency);
+ pipeline.updateDelayLine(props.ReflectionsDelay, props.LateReverbDelay, density_mult,
+ props.DecayTime, frequency);
if(fullUpdate)
{
/* Update the early lines. */
- pipeline.mEarly.updateLines(density_mult, props->Reverb.Diffusion, props->Reverb.DecayTime,
- frequency);
+ pipeline.mEarly.updateLines(density_mult, props.Diffusion, props.DecayTime, frequency);
/* Get the mixing matrix coefficients. */
- CalcMatrixCoeffs(props->Reverb.Diffusion, &pipeline.mMixX, &pipeline.mMixY);
+ CalcMatrixCoeffs(props.Diffusion, &pipeline.mMixX, &pipeline.mMixY);
/* Update the modulator rate and depth. */
- pipeline.mLate.Mod.updateModulator(props->Reverb.ModulationTime,
- props->Reverb.ModulationDepth, frequency);
+ pipeline.mLate.Mod.updateModulator(props.ModulationTime, props.ModulationDepth, frequency);
/* Update the late lines. */
- pipeline.mLate.updateLines(density_mult, props->Reverb.Diffusion, lfDecayTime,
- props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, frequency);
+ pipeline.mLate.updateLines(density_mult, props.Diffusion, lfDecayTime, props.DecayTime,
+ hfDecayTime, lf0norm, hf0norm, frequency);
}
/* Calculate the gain at the start of the late reverb stage, and the gain
* difference from the decay target (0.001, or -60dB).
*/
- const float decayBase{props->Reverb.ReflectionsGain * props->Reverb.LateReverbGain};
+ const float decayBase{props.ReflectionsGain * props.LateReverbGain};
const float decayDiff{ReverbDecayGain / decayBase};
if(decayDiff < 1.0f)
@@ -1297,10 +1294,10 @@ void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
* by -60dB), calculate the time to decay to -60dB from the start of
* the late reverb.
*/
- const float diffTime{std::log10(decayDiff)*(20.0f / -60.0f) * props->Reverb.DecayTime};
+ const float diffTime{std::log10(decayDiff)*(20.0f / -60.0f) * props.DecayTime};
- const float decaySamples{(props->Reverb.ReflectionsDelay + props->Reverb.LateReverbDelay
- + diffTime) * frequency};
+ const float decaySamples{(props.ReflectionsDelay+props.LateReverbDelay+diffTime)
+ * frequency};
/* Limit to 100,000 samples (a touch over 2 seconds at 48khz) to
* avoid excessive double-processing.
*/
@@ -1311,8 +1308,7 @@ void ReverbState::update(const ContextBase *Context, const EffectSlot *Slot,
/* Otherwise, if the late reverb already starts at -60dB or less, only
* include the time to get to the late reverb.
*/
- const float decaySamples{(props->Reverb.ReflectionsDelay + props->Reverb.LateReverbDelay)
- * frequency};
+ const float decaySamples{(props.ReflectionsDelay+props.LateReverbDelay) * frequency};
pipeline.mFadeSampleCount = static_cast<size_t>(minf(decaySamples, 100'000.0f));
}
}
@@ -1413,7 +1409,7 @@ void VecAllpass::process(const al::span<ReverbUpdateLine,NUM_LINES> samples, siz
ASSUME(todo > 0);
- size_t vap_offset[NUM_LINES];
+ std::array<size_t,NUM_LINES> vap_offset;
for(size_t j{0u};j < NUM_LINES;j++)
vap_offset[j] = offset - Offset[j];
for(size_t i{0u};i < todo;)
@@ -1504,10 +1500,11 @@ void ReverbPipeline::processEarly(size_t offset, const size_t samplesToDo,
mEarlyDelayTap[j][0] = mEarlyDelayTap[j][1];
}
- /* Apply a vector all-pass, to help color the initial reflections based
- * on the diffusion strength.
+ /* Apply a vector all-pass, to help color the initial reflections.
+ * Don't apply diffusion-based scattering since these are still the
+ * first reflections.
*/
- mEarly.VecAp.process(tempSamples, offset, mixX, mixY, todo);
+ mEarly.VecAp.process(tempSamples, offset, 1.0f, 0.0f, todo);
/* Apply a delay and bounce to generate secondary reflections, combine
* with the primary reflections and write out the result for mixing.
@@ -1594,17 +1591,52 @@ void ReverbPipeline::processLate(size_t offset, const size_t samplesToDo,
/* First, calculate the modulated delays for the late feedback. */
mLate.Mod.calcDelays(todo);
- /* Next, load decorrelated samples from the main and feedback delay
- * lines. Filter the signal to apply its frequency-dependent decay.
+ /* Now load samples from the feedback delay lines. Filter the signal to
+ * apply its frequency-dependent decay.
*/
+ for(size_t j{0u};j < NUM_LINES;++j)
+ {
+ size_t late_feedb_tap{offset - mLate.Offset[j]};
+ const float midGain{mLate.T60[j].MidGain};
+
+ for(size_t i{0u};i < todo;++i)
+ {
+ /* Calculate the read offset and offset between it and the next
+ * sample.
+ */
+ const float fdelay{mLate.Mod.ModDelays[i]};
+ const size_t idelay{float2uint(fdelay * float{gCubicTable.sTableSteps})};
+ const size_t delay{late_feedb_tap - (idelay>>gCubicTable.sTableBits)};
+ const size_t delayoffset{idelay & gCubicTable.sTableMask};
+ ++late_feedb_tap;
+
+ /* Get the samples around by the delayed offset. */
+ const float out0{late_delay.Line[(delay ) & late_delay.Mask][j]};
+ const float out1{late_delay.Line[(delay-1) & late_delay.Mask][j]};
+ const float out2{late_delay.Line[(delay-2) & late_delay.Mask][j]};
+ const float out3{late_delay.Line[(delay-3) & late_delay.Mask][j]};
+
+ /* The output is obtained by interpolating the four samples
+ * that were acquired above, and combined with the main delay
+ * tap.
+ */
+ const float out{out0*gCubicTable.getCoeff0(delayoffset)
+ + out1*gCubicTable.getCoeff1(delayoffset)
+ + out2*gCubicTable.getCoeff2(delayoffset)
+ + out3*gCubicTable.getCoeff3(delayoffset)};
+ tempSamples[j][i] = out * midGain;
+ }
+
+ mLate.T60[j].process({tempSamples[j].data(), todo});
+ }
+
+ /* Next load decorrelated samples from the main delay lines. */
const float fadeStep{1.0f / static_cast<float>(todo)};
- for(size_t j{0u};j < NUM_LINES;j++)
+ for(size_t j{0u};j < NUM_LINES;++j)
{
size_t late_delay_tap0{offset - mLateDelayTap[j][0]};
size_t late_delay_tap1{offset - mLateDelayTap[j][1]};
- size_t late_feedb_tap{offset - mLate.Offset[j]};
- const float midGain{mLate.T60[j].MidGain};
- const float densityGain{mLate.DensityGain * midGain};
+ const float densityGain{mLate.DensityGain};
const float densityStep{late_delay_tap0 != late_delay_tap1 ?
densityGain*fadeStep : 0.0f};
float fadeCount{0.0f};
@@ -1615,48 +1647,22 @@ void ReverbPipeline::processLate(size_t offset, const size_t samplesToDo,
late_delay_tap1 &= in_delay.Mask;
size_t td{minz(todo-i, in_delay.Mask+1 - maxz(late_delay_tap0, late_delay_tap1))};
do {
- /* Calculate the read offset and offset between it and the
- * next sample.
- */
- const float fdelay{mLate.Mod.ModDelays[i]};
- const size_t idelay{float2uint(fdelay * float{gCubicTable.sTableSteps})};
- const size_t delay{late_feedb_tap - (idelay>>gCubicTable.sTableBits)};
- const size_t delayoffset{idelay & gCubicTable.sTableMask};
- ++late_feedb_tap;
-
- /* Get the samples around by the delayed offset. */
- const float out0{late_delay.Line[(delay ) & late_delay.Mask][j]};
- const float out1{late_delay.Line[(delay-1) & late_delay.Mask][j]};
- const float out2{late_delay.Line[(delay-2) & late_delay.Mask][j]};
- const float out3{late_delay.Line[(delay-3) & late_delay.Mask][j]};
-
- /* The output is obtained by interpolating the four samples
- * that were acquired above, and combined with the main
- * delay tap.
- */
- const float out{out0*gCubicTable.getCoeff0(delayoffset)
- + out1*gCubicTable.getCoeff1(delayoffset)
- + out2*gCubicTable.getCoeff2(delayoffset)
- + out3*gCubicTable.getCoeff3(delayoffset)};
const float fade0{densityGain - densityStep*fadeCount};
const float fade1{densityStep*fadeCount};
fadeCount += 1.0f;
- tempSamples[j][i] = out*midGain +
- in_delay.Line[late_delay_tap0++][j]*fade0 +
+ tempSamples[j][i] += in_delay.Line[late_delay_tap0++][j]*fade0 +
in_delay.Line[late_delay_tap1++][j]*fade1;
++i;
} while(--td);
}
mLateDelayTap[j][0] = mLateDelayTap[j][1];
-
- mLate.T60[j].process({tempSamples[j].data(), todo});
}
/* Apply a vector all-pass to improve micro-surface diffusion, and
* write out the results for mixing.
*/
mLate.VecAp.process(tempSamples, offset, mixX, mixY, todo);
- for(size_t j{0u};j < NUM_LINES;j++)
+ for(size_t j{0u};j < NUM_LINES;++j)
std::copy_n(tempSamples[j].begin(), todo, outSamples[j].begin()+base);
/* Finally, scatter and bounce the results to refeed the feedback buffer. */
@@ -1673,7 +1679,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
ASSUME(samplesToDo > 0);
- auto &oldpipeline = mPipelines[mCurrentPipeline^1];
+ auto &oldpipeline = mPipelines[!mCurrentPipeline];
auto &pipeline = mPipelines[mCurrentPipeline];
if(mPipelineState >= Fading)
@@ -1681,7 +1687,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
/* Convert B-Format to A-Format for processing. */
const size_t numInput{minz(samplesIn.size(), NUM_LINES)};
const al::span<float> tmpspan{al::assume_aligned<16>(mTempLine.data()), samplesToDo};
- for(size_t c{0u};c < NUM_LINES;c++)
+ for(size_t c{0u};c < NUM_LINES;++c)
{
std::fill(tmpspan.begin(), tmpspan.end(), 0.0f);
for(size_t i{0};i < numInput;++i)
@@ -1722,7 +1728,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
const al::span<float> tmpspan{al::assume_aligned<16>(mTempLine.data()), samplesToDo};
const float fadeStep{1.0f / static_cast<float>(samplesToDo)};
- for(size_t c{0u};c < NUM_LINES;c++)
+ for(size_t c{0u};c < NUM_LINES;++c)
{
std::fill(tmpspan.begin(), tmpspan.end(), 0.0f);
for(size_t i{0};i < numInput;++i)
@@ -1746,7 +1752,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
filter.process(tmpspan, tmpspan.data());
pipeline.mEarlyDelayIn.write(offset, c, tmpspan.cbegin(), samplesToDo);
}
- for(size_t c{0u};c < NUM_LINES;c++)
+ for(size_t c{0u};c < NUM_LINES;++c)
{
std::fill(tmpspan.begin(), tmpspan.end(), 0.0f);
for(size_t i{0};i < numInput;++i)
@@ -1783,7 +1789,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span<const FloatBu
if(mPipelineState == Cleanup)
{
size_t numSamples{mSampleBuffer.size()/2};
- size_t pipelineOffset{numSamples * (mCurrentPipeline^1)};
+ size_t pipelineOffset{numSamples * (!mCurrentPipeline)};
std::fill_n(mSampleBuffer.data()+pipelineOffset, numSamples,
decltype(mSampleBuffer)::value_type{});
diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp
index 872c7add..eaf30d07 100644
--- a/alc/effects/vmorpher.cpp
+++ b/alc/effects/vmorpher.cpp
@@ -57,29 +57,30 @@ namespace {
using uint = unsigned int;
-#define MAX_UPDATE_SAMPLES 256
-#define NUM_FORMANTS 4
-#define NUM_FILTERS 2
-#define Q_FACTOR 5.0f
-
-#define VOWEL_A_INDEX 0
-#define VOWEL_B_INDEX 1
+constexpr size_t MaxUpdateSamples{256};
+constexpr size_t NumFormants{4};
+constexpr float QFactor{5.0f};
+enum : size_t {
+ VowelAIndex,
+ VowelBIndex,
+ NumFilters
+};
-#define WAVEFORM_FRACBITS 24
-#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
-#define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
+constexpr size_t WaveformFracBits{24};
+constexpr size_t WaveformFracOne{1<<WaveformFracBits};
+constexpr size_t WaveformFracMask{WaveformFracOne-1};
inline float Sin(uint index)
{
- constexpr float scale{al::numbers::pi_v<float>*2.0f / WAVEFORM_FRACONE};
+ constexpr float scale{al::numbers::pi_v<float>*2.0f / float{WaveformFracOne}};
return std::sin(static_cast<float>(index) * scale)*0.5f + 0.5f;
}
inline float Saw(uint index)
-{ return static_cast<float>(index) / float{WAVEFORM_FRACONE}; }
+{ return static_cast<float>(index) / float{WaveformFracOne}; }
inline float Triangle(uint index)
-{ return std::fabs(static_cast<float>(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); }
+{ return std::fabs(static_cast<float>(index)*(2.0f/WaveformFracOne) - 1.0f); }
inline float Half(uint) { return 0.5f; }
@@ -89,13 +90,12 @@ void Oscillate(float *RESTRICT dst, uint index, const uint step, size_t todo)
for(size_t i{0u};i < todo;i++)
{
index += step;
- index &= WAVEFORM_FRACMASK;
+ index &= WaveformFracMask;
dst[i] = func(index);
}
}
-struct FormantFilter
-{
+struct FormantFilter {
float mCoeff{0.0f};
float mGain{1.0f};
float mS1{0.0f};
@@ -106,20 +106,21 @@ struct FormantFilter
: mCoeff{std::tan(al::numbers::pi_v<float> * f0norm)}, mGain{gain}
{ }
- inline void process(const float *samplesIn, float *samplesOut, const size_t numInput)
+ void process(const float *samplesIn, float *samplesOut, const size_t numInput) noexcept
{
/* A state variable filter from a topology-preserving transform.
* Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg
*/
const float g{mCoeff};
const float gain{mGain};
- const float h{1.0f / (1.0f + (g/Q_FACTOR) + (g*g))};
+ const float h{1.0f / (1.0f + (g/QFactor) + (g*g))};
+ const float coeff{1.0f/QFactor + g};
float s1{mS1};
float s2{mS2};
for(size_t i{0u};i < numInput;i++)
{
- const float H{(samplesIn[i] - (1.0f/Q_FACTOR + g)*s1 - s2)*h};
+ const float H{(samplesIn[i] - coeff*s1 - s2)*h};
const float B{g*H + s1};
const float L{g*B + s2};
@@ -133,7 +134,7 @@ struct FormantFilter
mS2 = s2;
}
- inline void clear()
+ void clear() noexcept
{
mS1 = 0.0f;
mS2 = 0.0f;
@@ -142,16 +143,17 @@ struct FormantFilter
struct VmorpherState final : public EffectState {
- struct {
+ struct OutParams {
uint mTargetChannel{InvalidChannelIndex};
/* Effect parameters */
- FormantFilter mFormants[NUM_FILTERS][NUM_FORMANTS];
+ std::array<std::array<FormantFilter,NumFormants>,NumFilters> mFormants;
/* Effect gains for each channel */
float mCurrentGain{};
float mTargetGain{};
- } mChans[MaxAmbiChannels];
+ };
+ std::array<OutParams,MaxAmbiChannels> mChans;
void (*mGetSamples)(float*RESTRICT, uint, const uint, size_t){};
@@ -159,9 +161,9 @@ struct VmorpherState final : public EffectState {
uint mStep{1};
/* Effects buffers */
- alignas(16) float mSampleBufferA[MAX_UPDATE_SAMPLES]{};
- alignas(16) float mSampleBufferB[MAX_UPDATE_SAMPLES]{};
- alignas(16) float mLfo[MAX_UPDATE_SAMPLES]{};
+ alignas(16) std::array<float,MaxUpdateSamples> mSampleBufferA{};
+ alignas(16) std::array<float,MaxUpdateSamples> mSampleBufferB{};
+ alignas(16) std::array<float,MaxUpdateSamples> mLfo{};
void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
@@ -169,14 +171,12 @@ struct VmorpherState final : public EffectState {
void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
const al::span<FloatBufferLine> samplesOut) override;
- static std::array<FormantFilter,4> getFiltersByPhoneme(VMorpherPhenome phoneme,
- float frequency, float pitch);
-
- DEF_NEWDEL(VmorpherState)
+ static std::array<FormantFilter,NumFormants> getFiltersByPhoneme(VMorpherPhenome phoneme,
+ float frequency, float pitch) noexcept;
};
-std::array<FormantFilter,4> VmorpherState::getFiltersByPhoneme(VMorpherPhenome phoneme,
- float frequency, float pitch)
+std::array<FormantFilter,NumFormants> VmorpherState::getFiltersByPhoneme(VMorpherPhenome phoneme,
+ float frequency, float pitch) noexcept
{
/* Using soprano formant set of values to
* better match mid-range frequency space.
@@ -232,44 +232,43 @@ void VmorpherState::deviceUpdate(const DeviceBase*, const BufferStorage*)
for(auto &e : mChans)
{
e.mTargetChannel = InvalidChannelIndex;
- std::for_each(std::begin(e.mFormants[VOWEL_A_INDEX]), std::end(e.mFormants[VOWEL_A_INDEX]),
+ std::for_each(e.mFormants[VowelAIndex].begin(), e.mFormants[VowelAIndex].end(),
std::mem_fn(&FormantFilter::clear));
- std::for_each(std::begin(e.mFormants[VOWEL_B_INDEX]), std::end(e.mFormants[VOWEL_B_INDEX]),
+ std::for_each(e.mFormants[VowelBIndex].begin(), e.mFormants[VowelBIndex].end(),
std::mem_fn(&FormantFilter::clear));
e.mCurrentGain = 0.0f;
}
}
void VmorpherState::update(const ContextBase *context, const EffectSlot *slot,
- const EffectProps *props, const EffectTarget target)
+ const EffectProps *props_, const EffectTarget target)
{
+ auto &props = std::get<VmorpherProps>(*props_);
const DeviceBase *device{context->mDevice};
const float frequency{static_cast<float>(device->Frequency)};
- const float step{props->Vmorpher.Rate / frequency};
- mStep = fastf2u(clampf(step*WAVEFORM_FRACONE, 0.0f, float{WAVEFORM_FRACONE-1}));
+ const float step{props.Rate / frequency};
+ mStep = fastf2u(clampf(step*WaveformFracOne, 0.0f, float{WaveformFracOne}-1.0f));
if(mStep == 0)
mGetSamples = Oscillate<Half>;
- else if(props->Vmorpher.Waveform == VMorpherWaveform::Sinusoid)
+ else if(props.Waveform == VMorpherWaveform::Sinusoid)
mGetSamples = Oscillate<Sin>;
- else if(props->Vmorpher.Waveform == VMorpherWaveform::Triangle)
+ else if(props.Waveform == VMorpherWaveform::Triangle)
mGetSamples = Oscillate<Triangle>;
- else /*if(props->Vmorpher.Waveform == VMorpherWaveform::Sawtooth)*/
+ else /*if(props.Waveform == VMorpherWaveform::Sawtooth)*/
mGetSamples = Oscillate<Saw>;
- const float pitchA{std::pow(2.0f,
- static_cast<float>(props->Vmorpher.PhonemeACoarseTuning) / 12.0f)};
- const float pitchB{std::pow(2.0f,
- static_cast<float>(props->Vmorpher.PhonemeBCoarseTuning) / 12.0f)};
+ const float pitchA{std::pow(2.0f, static_cast<float>(props.PhonemeACoarseTuning) / 12.0f)};
+ const float pitchB{std::pow(2.0f, static_cast<float>(props.PhonemeBCoarseTuning) / 12.0f)};
- auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA);
- auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB);
+ auto vowelA = getFiltersByPhoneme(props.PhonemeA, frequency, pitchA);
+ auto vowelB = getFiltersByPhoneme(props.PhonemeB, frequency, pitchB);
/* 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].mFormants[VOWEL_A_INDEX]));
- std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].mFormants[VOWEL_B_INDEX]));
+ std::copy(vowelA.begin(), vowelA.end(), mChans[i].mFormants[VowelAIndex].begin());
+ std::copy(vowelB.begin(), vowelB.end(), mChans[i].mFormants[VowelBIndex].begin());
}
mOutTarget = target.Main->Buffer;
@@ -288,11 +287,11 @@ void VmorpherState::process(const size_t samplesToDo, const al::span<const Float
*/
for(size_t base{0u};base < samplesToDo;)
{
- const size_t td{minz(MAX_UPDATE_SAMPLES, samplesToDo-base)};
+ const size_t td{minz(MaxUpdateSamples, samplesToDo-base)};
- mGetSamples(mLfo, mIndex, mStep, td);
+ mGetSamples(mLfo.data(), mIndex, mStep, td);
mIndex += static_cast<uint>(mStep * td);
- mIndex &= WAVEFORM_FRACMASK;
+ mIndex &= WaveformFracMask;
auto chandata = std::begin(mChans);
for(const auto &input : samplesIn)
@@ -304,30 +303,30 @@ void VmorpherState::process(const size_t samplesToDo, const al::span<const Float
continue;
}
- auto& vowelA = chandata->mFormants[VOWEL_A_INDEX];
- auto& vowelB = chandata->mFormants[VOWEL_B_INDEX];
+ const auto vowelA = al::span{chandata->mFormants[VowelAIndex]};
+ const auto vowelB = al::span{chandata->mFormants[VowelBIndex]};
/* Process first vowel. */
std::fill_n(std::begin(mSampleBufferA), td, 0.0f);
- vowelA[0].process(&input[base], mSampleBufferA, td);
- vowelA[1].process(&input[base], mSampleBufferA, td);
- vowelA[2].process(&input[base], mSampleBufferA, td);
- vowelA[3].process(&input[base], mSampleBufferA, td);
+ vowelA[0].process(&input[base], mSampleBufferA.data(), td);
+ vowelA[1].process(&input[base], mSampleBufferA.data(), td);
+ vowelA[2].process(&input[base], mSampleBufferA.data(), td);
+ vowelA[3].process(&input[base], mSampleBufferA.data(), td);
/* Process second vowel. */
std::fill_n(std::begin(mSampleBufferB), td, 0.0f);
- vowelB[0].process(&input[base], mSampleBufferB, td);
- vowelB[1].process(&input[base], mSampleBufferB, td);
- vowelB[2].process(&input[base], mSampleBufferB, td);
- vowelB[3].process(&input[base], mSampleBufferB, td);
+ vowelB[0].process(&input[base], mSampleBufferB.data(), td);
+ vowelB[1].process(&input[base], mSampleBufferB.data(), td);
+ vowelB[2].process(&input[base], mSampleBufferB.data(), td);
+ vowelB[3].process(&input[base], mSampleBufferB.data(), td);
- alignas(16) float blended[MAX_UPDATE_SAMPLES];
+ alignas(16) std::array<float,MaxUpdateSamples> blended;
for(size_t i{0u};i < td;i++)
blended[i] = lerpf(mSampleBufferA[i], mSampleBufferB[i], mLfo[i]);
/* Now, mix the processed sound data to the output. */
- MixSamples({blended, td}, samplesOut[outidx].data()+base, chandata->mCurrentGain,
- chandata->mTargetGain, samplesToDo-base);
+ MixSamples({blended.data(), td}, samplesOut[outidx].data()+base,
+ chandata->mCurrentGain, chandata->mTargetGain, samplesToDo-base);
++chandata;
}