Add updateCoefficients() that short-circuits when cutoff, resonance, and type are unchanged. Cache ladderG and formantCoefficients so processSample() avoids redundant exp()/tan() calls per sample. Extract static getCutoffHz() from Filter::process() so FilterBank can compute the keytracked cutoff once per parallel branch instead of per sample. Simplify formant() and screamer() signatures to use cached state.
63 lines
2.4 KiB
C++
63 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <JuceHeader.h>
|
|
#include "Params.h"
|
|
|
|
namespace serum
|
|
{
|
|
|
|
// ===========================================================================
|
|
// Mono filter with 7 models (Ladder LP/HP/BP, Diode, Comb, Formant, Screamer),
|
|
// 6/12/24 dB slopes (ladder family) and per-sample drive + keytrack. All state
|
|
// is clamped to prevent NaN/inf at extreme settings.
|
|
// ===========================================================================
|
|
class Filter
|
|
{
|
|
public:
|
|
void prepare (double sampleRate, int maxBlockSize);
|
|
void reset();
|
|
|
|
// Process a mono buffer in-place. cutoffNorm is 0..1 (mapped to 20Hz..20kHz).
|
|
void process (float* samples, int numSamples, float cutoffNorm, float res,
|
|
float drive, float keytrack, float noteHz, int type, int slope) noexcept;
|
|
|
|
// Single-sample version (used by the comb/naive paths where convenient).
|
|
float processSample (float in, float cutoffHz, float res, float drive, int type, int slope) noexcept;
|
|
static float getCutoffHz (float cutoffNorm, float keytrack, float noteHz) noexcept;
|
|
|
|
private:
|
|
double sr = 44100.0;
|
|
float lastCutoffHz = -1.0f, lastRes = -1.0f;
|
|
int lastType = -1;
|
|
double ladderG = 0.0;
|
|
|
|
// TPT SVF state (also reused by formant/screamer).
|
|
double ic1eq = 0.0, ic2eq = 0.0;
|
|
double lastG = 0.0, lastK = 0.0;
|
|
double a1 = 0.0, a2 = 0.0, a3 = 0.0;
|
|
|
|
// Ladder stage state.
|
|
std::array<double, 4> stage { { 0.0, 0.0, 0.0, 0.0 } };
|
|
|
|
// Comb delay line.
|
|
std::vector<float> combLine;
|
|
int combWrite = 0;
|
|
double combDamp = 0.0;
|
|
|
|
// Formant: three parallel bandpass SVFs (state pairs).
|
|
std::array<std::array<double, 2>, 3> formantState { { { { 0.0, 0.0 } }, { { 0.0, 0.0 } }, { { 0.0, 0.0 } } } };
|
|
std::array<std::array<double, 3>, 3> formantCoefficients {};
|
|
|
|
void updateCoefficients (float cutoffHz, float res, int type) noexcept;
|
|
void updateSvf (double g, double k) noexcept;
|
|
double svfLow (double in, double g, double k) noexcept;
|
|
double svfBand (double in, double g, double k) noexcept;
|
|
double svfHigh (double in, double g, double k) noexcept;
|
|
double ladder (double in, double g, double res, double drive, int stages, bool diode) noexcept;
|
|
double comb (double in, double freqHz, double res, double drive) noexcept;
|
|
double formant (double in) noexcept;
|
|
double screamer (double in, double drive) noexcept;
|
|
};
|
|
|
|
} // namespace serum
|