Sound Byte Libs 0.5.1-121-g3358a44
C++ firmware library for audio applications on 32-bit ARM Cortex-M processors
Loading...
Searching...
No Matches
one_pole.hpp
Go to the documentation of this file.
1// sbl/dsp/one_pole.hpp — Single-pole IIR filters (LP and HP)
2//
3// OnePole (LP): y[n] = a * x[n] + (1-a) * y[n-1]
4// OnePoleHP: y[n] = x[n] - lp(x[n]) (complement of LP)
5//
6// Signal processors — cutoff is controlled by a signal (_su).
7// Configure frequency range and sample rate, then drive cutoff via
8// set_cutoff_su(). Engineering-unit setter is private (TestAccess).
9//
10// For parameter smoothing (settling time, not frequency), use ParameterSmoother.
11//
12// Usage:
13// sbl::dsp::OnePole lp;
14// lp.set_range(200.0f, 8000.0f); // [0,1] maps to this Hz range
15// lp.set_cutoff_su(0.5f); // → geometric midpoint ~1265 Hz
16// float y = lp.process(x);
17//
18// sbl::dsp::OnePoleHP hp;
19// hp.set_range(20.0f, 500.0f);
20// hp.set_cutoff_su(0.3f);
21// float y = hp.process(x);
22
23#ifndef SBL_DSP_PRIMITIVES_ONE_POLE_HPP_
24#define SBL_DSP_PRIMITIVES_ONE_POLE_HPP_
25
26#include <cmath>
27#include <cstdint>
28
33
34namespace sbl::dsp::primitives {
35
36struct OnePoleTestAccess;
37
38class OnePole {
39public:
40 /// @note All public methods are ISR-safe — bounded computation, no I/O.
41
42 /**
43 * @brief Set frequency range for _su mapping (configuration, not a signal)
44 *
45 * Defines the Hz range that [0, 1] maps to exponentially.
46 * Default range is 20–20000 Hz.
47 *
48 * @param min_hz Frequency at su = 0.0
49 * @param max_hz Frequency at su = 1.0
50 */
51 void set_range(float min_hz, float max_hz) {
52 min_hz_ = min_hz;
53 octaves_ = std::log2(max_hz / min_hz);
54 }
55
56 /**
57 * @brief Set cutoff frequency via signal unit
58 *
59 * Maps [0, 1] exponentially across the configured frequency range.
60 * su = 0.0 → min_hz, su = 1.0 → max_hz.
61 *
62 * @param su Unipolar signal [0, 1]
63 */
64 void set_cutoff_su(float su) {
65 set_frequency(math::su_to_hz(math::clamp01(su), min_hz_, octaves_));
66 }
67
68 /**
69 * @brief Set filter coefficient directly
70 *
71 * a = 0.0 → no filtering (hold previous output), 1.0 → full passthrough.
72 */
73 void set_coefficient(float a) { coeff_ = a; }
74
75 /**
76 * @brief Process a single sample
77 * @param x Input sample
78 * @return Filtered output
79 */
80 float process(float x) {
81 state_ += coeff_ * (x - state_);
82 return state_;
83 }
84
85 /**
86 * @brief Process a block of samples in-place
87 * @param buf Audio buffer (modified in-place)
88 * @param frames Number of samples
89 */
90 void process(float* buf, uint16_t frames) {
91 for (uint16_t i = 0; i < frames; ++i) {
92 buf[i] = process(buf[i]);
93 }
94 }
95
96 /** @brief Current filter state (last output) */
97 float value() const { return state_; }
98
99 /** @brief Current coefficient */
100 float coefficient() const { return coeff_; }
101
102 /** @brief Reset filter state to zero */
103 void reset() { state_ = 0.0f; }
104
105 /** @brief Reset filter state to a specific value */
106 void reset(float initial) { state_ = initial; }
107
108private:
109 friend struct OnePoleTestAccess;
110
111 /**
112 * @brief Compute coefficient from cutoff frequency (internal)
113 * @param freq_hz Cutoff frequency in Hz
114 */
115 void set_frequency(float freq_hz) {
117 }
118
119 float coeff_ = 0.0f;
120 float state_ = 0.0f;
121 float min_hz_ = 20.0f;
122 float octaves_ = 9.965784f; ///< log2(20000 / 20)
123};
124
125/**
126 * @brief Test access for OnePole engineering-unit API
127 */
129 static void set_frequency(OnePole& f, float hz) {
130 f.set_frequency(hz);
131 }
132};
133
134struct OnePoleHPTestAccess;
135
136/**
137 * @brief One-pole highpass filter (complement of OnePole LP)
138 *
139 * Computed as hp = x - lp(x). Same coefficient math as OnePole.
140 * Cutoff is controlled by a signal via set_cutoff_su().
141 */
143public:
144 /// @note All public methods are ISR-safe — bounded computation, no I/O.
145
146 void set_range(float min_hz, float max_hz) { lp_.set_range(min_hz, max_hz); }
147 void set_cutoff_su(float su) { lp_.set_cutoff_su(su); }
148 void set_coefficient(float a) { lp_.set_coefficient(a); }
149
150 float process(float x) {
151 return x - lp_.process(x);
152 }
153
154 void process(float* buf, uint16_t frames) {
155 for (uint16_t i = 0; i < frames; ++i) {
156 buf[i] = process(buf[i]);
157 }
158 }
159
160 float coefficient() const { return lp_.coefficient(); }
161 void reset() { lp_.reset(); }
162 void reset(float initial) { lp_.reset(initial); }
163
164private:
165 friend struct OnePoleHPTestAccess;
166 OnePole lp_;
167};
168
169/**
170 * @brief Test access for OnePoleHP engineering-unit API
171 */
173 static void set_frequency(OnePoleHP& f, float hz) {
175 }
176};
177
178} // namespace sbl::dsp::primitives
179
180#endif // SBL_DSP_PRIMITIVES_ONE_POLE_HPP_
Clamping (Cross-cutting — Math)
One-pole highpass filter (complement of OnePole LP)
Definition one_pole.hpp:142
void process(float *buf, uint16_t frames)
Definition one_pole.hpp:154
void set_range(float min_hz, float max_hz)
Definition one_pole.hpp:146
void reset(float initial)
Definition one_pole.hpp:162
void set_coefficient(float a)
Set filter coefficient directly.
Definition one_pole.hpp:73
void reset(float initial)
Reset filter state to a specific value.
Definition one_pole.hpp:106
void reset()
Reset filter state to zero.
Definition one_pole.hpp:103
void process(float *buf, uint16_t frames)
Process a block of samples in-place.
Definition one_pole.hpp:90
void set_range(float min_hz, float max_hz)
Set frequency range for _su mapping (configuration, not a signal)
Definition one_pole.hpp:51
float process(float x)
Process a single sample.
Definition one_pole.hpp:80
float value() const
Current filter state (last output)
Definition one_pole.hpp:97
float coefficient() const
Current coefficient.
Definition one_pole.hpp:100
void set_cutoff_su(float su)
Set cutoff frequency via signal unit.
Definition one_pole.hpp:64
The numbers every layer reaches for.
Fast analytical approximations (Audio Stack — Atoms)
Fixed-point constants and audio sample types.
constexpr float clamp01(float x)
x held to [0, 1]; NaN → 0.
Definition clamp.hpp:18
constexpr float one_minus_exp_neg(float x)
constexpr float TWO_PI
Definition constants.hpp:12
float su_to_hz(float su, float min_hz, float octaves)
Stateful, single-concern building blocks.
float SAMPLE_RATE_F
Definition fixed.hpp:17
Test access for OnePoleHP engineering-unit API.
Definition one_pole.hpp:172
static void set_frequency(OnePoleHP &f, float hz)
Definition one_pole.hpp:173
Test access for OnePole engineering-unit API.
Definition one_pole.hpp:128
static void set_frequency(OnePole &f, float hz)
Definition one_pole.hpp:129