|
Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
|
The engine's filter: a Chamberlin state-variable filter, with all four responses taken as different taps of the same two-integrator loop. More...
#include <tabulasonora/state_variable_filter.hpp>
Public Member Functions | |
| double | low () const noexcept |
| The lowpass integrator's current value. | |
| double | band () const noexcept |
| The bandpass integrator's current value. | |
| void | reset () noexcept |
| Clears the filter state. | |
| double | process (double input, double f, double q, FilterTap tap) noexcept |
| Advances the filter by one sample and returns the selected tap. | |
The engine's filter: a Chamberlin state-variable filter, with all four responses taken as different taps of the same two-integrator loop.
Read from the disassembly rather than inferred: there is no prescale, no oversampling and no reordering. Per sample,
low += f * band; high = input - (q * band + low); band += f * high;
Both coefficients come from tables, so no fitted constant appears anywhere in this path. Note that q is Chamberlin's reciprocal-Q: smaller means more resonant, and the neutral resonance byte gives exactly 1.0.
The order of those three lines is load-bearing and so is the grouping in the middle one. Reassociating input - (q*band + low) into input - q*band - low is a different sequence of IEEE operations, and the build disables FMA contraction so the compiler cannot fuse them either.
Verified against the reference, not just transcribed. Driving this recurrence with the engine's own filter-input buffer and its own f/q — both read live out of the DLL — reproduces its filter output to a mean relative error of about 1e-5, which is float32 round-off. A long investigation into drum tone 1946 passed through here twice on the way to the real cause, which turned out to be in the wave decode; see WaveRom. Nothing in this file needed changing, and a q clamp proposed along the way would have been a curve fit over an unrelated bug.
|
inlinenodiscardnoexcept |
The lowpass integrator's current value.
|
inlinenodiscardnoexcept |
The bandpass integrator's current value.
|
inlinenoexcept |
Clears the filter state.
|
inlinenodiscardnoexcept |
Advances the filter by one sample and returns the selected tap.
f is the frequency coefficient, 2*sin(pi*fc/fs); q is the reciprocal-Q damping.