0
mirror of https://github.com/torvalds/GuitarPedal.git synced 2026-06-20 05:31:55 +00:00
Files
torvalds-GuitarPedal/Software/audio/single-pole.h
Linus Torvalds eae1f76c00 Extend a bit on the single-pole helper functions
This adds a helper to just use RC values directly to compute alpha for
the single-pole functions, so that if you're converting an analog filter
to the DSP version, you can just use "single_pole_rc(R, C)" to get the
constant coefficient for the filter.

Also, while I did that really simple high-pass filter by just
subtracting the low-pass component from the signal, google tells me
that there's a proper way to do it, and what I did is called the
"complementary" high-pass filter.

They are pretty much the same in practice, and the complementary version
has the obvious advantage where the adding the high-pass and low-pass
filtered components back together results in the original signal.

But let's expose both as helpers, and use the 'proper' model by default.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-06-06 12:17:36 -07:00

74 lines
2.0 KiB
C

//
// Simple single-pole helpers
//
// This uses trivial wrapper structures for type safety (and
// incidentally to look a bit like the biquad code).
//
// Note that you can precompute 'alpha' when it makes sense, but for
// things like constant frequencies or times, it's much better to just
// do them as part of the step function, since that will allow the
// compiler to just fold all the computations.
struct single_pole_state { float y; };
struct single_pole_coeff { float alpha; };
// Use this if you want to precompute the coefficient
// and just have a single unified struct
struct single_pole {
struct single_pole_coeff coeff;
struct single_pole_state state;
};
static inline float _single_pole_step(float in,
struct single_pole_state *state,
const struct single_pole_coeff coeff)
{
return state->y = linear(coeff.alpha, state->y, in);
}
// Standard fast approximations when far away from Nyquist
static inline struct single_pole_coeff single_pole_freq(float freq)
{
float omega = freq * (TWOPI / SAMPLES_PER_SEC);
struct single_pole_coeff coeff = { omega / (1 + omega) };
return coeff;
}
static inline struct single_pole_coeff single_pole_time(float ms)
{
float tau = 1.0 / (SAMPLES_PER_MSEC * ms);
struct single_pole_coeff coeff = { tau / (1 + tau) };
return coeff;
}
static inline struct single_pole_coeff single_pole_rc(float R, float C)
{
return single_pole_time(R*C*1000);
}
static inline float single_pole_lpf(float in,
struct single_pole_state *state,
const struct single_pole_coeff coeff)
{
return _single_pole_step(in, state, coeff);
}
static inline float single_pole_hpf_complementary(float in,
struct single_pole_state *state,
const struct single_pole_coeff coeff)
{
return in - _single_pole_step(in, state, coeff);
}
// The proper way to do a single-pole high-pass filter,
// with 'R' being the filter pole location (1-alpha)
static inline float single_pole_hpf(float in,
struct single_pole_state *state,
const struct single_pole_coeff coeff)
{
float R = 1.0f - coeff.alpha;
float y = in + state->y;
state->y = R * y - in;
return y;
}