Skip to content

Commit

Permalink
Use a variant to control the modulator effect generator
Browse files Browse the repository at this point in the history
  • Loading branch information
kcat committed Feb 16, 2024
1 parent 8e672fc commit d81b453
Showing 1 changed file with 44 additions and 44 deletions.
88 changes: 44 additions & 44 deletions alc/effects/modulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,42 +48,29 @@ namespace {

using uint = unsigned int;

inline float Sin(uint index, float scale)
{ return std::sin(static_cast<float>(index) * scale); }

inline float Saw(uint index, float scale)
{ return static_cast<float>(index)*scale - 1.0f; }

inline float Square(uint index, float scale)
{ return float(static_cast<float>(index)*scale < 0.5f)*2.0f - 1.0f; }
struct SinFunc {
static auto Get(uint index, float scale) noexcept(noexcept(std::sin(0.0f))) -> float
{ return std::sin(static_cast<float>(index) * scale); }
};

inline float One(uint, float)
{ return 1.0f; }
struct SawFunc {
static constexpr auto Get(uint index, float scale) noexcept -> float
{ return static_cast<float>(index)*scale - 1.0f; }
};

struct ModulatorState final : public EffectState {
template<float (&func)(uint,float)>
void Modulate(size_t todo)
{
const uint range{mRange};
const float scale{mIndexScale};
uint index{mIndex};
struct SquareFunc {
static constexpr auto Get(uint index, float scale) noexcept -> float
{ return float(static_cast<float>(index)*scale < 0.5f)*2.0f - 1.0f; }
};

ASSUME(range > 1);
ASSUME(todo > 0);
struct OneFunc {
static constexpr auto Get(uint, float) noexcept -> float
{ return 1.0f; }
};

for(size_t i{0};i < todo;)
{
size_t rem{std::min(todo-i, size_t{range-index})};
do {
mModSamples[i++] = func(index++, scale);
} while(--rem);
if(index == range)
index = 0;
}
mIndex = index;
}

void (ModulatorState::*mGenModSamples)(size_t){};
struct ModulatorState final : public EffectState {
std::variant<OneFunc,SinFunc,SawFunc,SquareFunc> mSampleGen;

uint mIndex{0};
uint mRange{1};
Expand All @@ -110,13 +97,6 @@ struct ModulatorState final : public EffectState {
const al::span<FloatBufferLine> samplesOut) override;
};

template<>
void ModulatorState::Modulate<One>(size_t todo)
{
std::fill_n(mModSamples.begin(), todo, 1.0f);
mIndex = 0;
}

void ModulatorState::deviceUpdate(const DeviceBase*, const BufferStorage*)
{
for(auto &e : mChans)
Expand Down Expand Up @@ -151,27 +131,27 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,
if(mRange == 1)
{
mIndexScale = 0.0f;
mGenModSamples = &ModulatorState::Modulate<One>;
mSampleGen.emplace<OneFunc>();
}
else if(props.Waveform == ModulatorWaveform::Sinusoid)
{
mIndexScale = al::numbers::pi_v<float>*2.0f / static_cast<float>(mRange);
mGenModSamples = &ModulatorState::Modulate<Sin>;
mSampleGen.emplace<SinFunc>();
}
else if(props.Waveform == ModulatorWaveform::Sawtooth)
{
mIndexScale = 2.0f / static_cast<float>(mRange-1);
mGenModSamples = &ModulatorState::Modulate<Saw>;
mSampleGen.emplace<SawFunc>();
}
else /*if(props.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
* would need a more complex value generator.
*/
mRange = (mRange+1) & ~1u;
mIndexScale = 1.0f / static_cast<float>(mRange-1);
mGenModSamples = &ModulatorState::Modulate<Square>;
mSampleGen.emplace<SquareFunc>();
}

float f0norm{props.HighPassCutoff / static_cast<float>(device->Frequency)};
Expand All @@ -192,7 +172,27 @@ void ModulatorState::update(const ContextBase *context, const EffectSlot *slot,

void ModulatorState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
{
(this->*mGenModSamples)(samplesToDo);
ASSUME(samplesToDo > 0);

std::visit([this,samplesToDo](auto&& type)
{
const uint range{mRange};
const float scale{mIndexScale};
uint index{mIndex};

ASSUME(range > 1);

for(size_t i{0};i < samplesToDo;)
{
size_t rem{std::min(samplesToDo-i, size_t{range-index})};
do {
mModSamples[i++] = type.Get(index++, scale);
} while(--rem);
if(index == range)
index = 0;
}
mIndex = index;
}, mSampleGen);

auto chandata = mChans.begin();
for(const auto &input : samplesIn)
Expand Down

0 comments on commit d81b453

Please sign in to comment.