Files
serumalt/Source/EffectUnits/Phaser.cpp
T
biggy e4cea300db chore: land janitor round 1 and graft integration
Round 1 findings and fixes, all previously uncommitted:
- FXProcessor per-slot DSP history repair (HEAD does not compile without it)
- SynthVoice::getModulationValue, editor control-lock guard
- ExactCompare.h naming the deliberate exact float comparisons
- KnobLookAndFeel replacing the never-installed SerumLookAndFeel
- 55 first-party compiler warnings to 0
- AGENT.md renamed to AGENTS.md across Source/
- graft repository context graph and its hooks
- JANITOR_TASKS.md and UI_UX_AUDIT.md records
2026-10-06 08:50:45 +02:00

59 lines
1.7 KiB
C++

#include "Phaser.h"
namespace serum
{
void PhaserUnit::prepare (double sampleRate, int)
{
sr = sampleRate;
reset();
}
void PhaserUnit::reset()
{
lfoPhase = 0.0;
for (int i = 0; i < 6; ++i)
{
xL[i] = xR[i] = yL[i] = yR[i] = 0.0f;
}
}
void PhaserUnit::process (float* l, float* r, int numSamples, const float p[4])
{
const double rate = 0.05 + p[0] * 2.0;
const float depth = 0.3f + p[1] * 0.6f;
const float feedback = p[2] * 0.7f;
const int stages = juce::jlimit (2, 6, 2 + (int) (p[3] * 4.0f + 0.5f));
for (int i = 0; i < numSamples; ++i)
{
lfoPhase += juce::MathConstants<double>::twoPi * rate / sr;
if (lfoPhase > juce::MathConstants<double>::twoPi) lfoPhase -= juce::MathConstants<double>::twoPi;
const float sweep = (float) (0.5 + 0.5 * std::sin (lfoPhase));
// The allpass cascade is stable only while the coefficient stays inside
// (-1, 1). depth can push 0.3 + depth * sweep above 1, which makes every
// stage self-excite, so the filter state runs away to inf/NaN and keeps
// producing it. Clamp at the point where the coefficient is computed.
const float a = juce::jlimit (0.0f, 0.99f, 0.3f + depth * sweep);
float outL = l[i] + yL[5] * feedback;
float outR = r[i] + yR[5] * feedback;
for (int s = 0; s < stages; ++s)
{
// y = a*x + x_prev - a*y_prev
const float inL = outL, inR = outR;
outL = a * inL + xL[s] - a * yL[s];
outR = a * inR + xR[s] - a * yR[s];
xL[s] = inL; xR[s] = inR;
yL[s] = outL; yR[s] = outR;
}
l[i] = outL;
r[i] = outR;
}
}
} // namespace serum