DSPark 1.6.1
Header-only audio DSP framework in pure C++20 — zero dependencies
Loading...
Searching...
No Matches
dspark::Biquad< T, MaxChannels > Class Template Reference

Biquad filter using Transposed Direct Form II (TDF-II) with thread-safe updates. More...

#include <Biquad.h>

Public Member Functions

 Biquad () noexcept=default
 
 Biquad (Biquad &&other) noexcept
 
Biquadoperator= (Biquad &&other) noexcept
 
 Biquad (const Biquad &)=delete
 
Biquadoperator= (const Biquad &)=delete
 
void setCoeffs (const BiquadCoeffs &c) noexcept
 Sets the filter coefficients asynchronously.
 
bool applyPendingCoeffs () noexcept
 Promotes any pending staged coefficients to active.
 
const BiquadCoeffsgetCoeffs () const noexcept
 Returns the active coefficient set currently in use by the DSP thread.
 
void reset () noexcept
 Resets all per-channel filter states to zero to avoid ringing/clicks.
 
processSample (T input, int channel) noexcept
 Processes a single sample for a specific channel.
 
double processSampleCore (double input, int channel) noexcept
 One recursion step in the core's own precision (double).
 
void processBlock (AudioBufferView< T > buffer) noexcept
 Processes a full audio buffer in-place.
 

Detailed Description

template<typename T, int MaxChannels = 8>
class dspark::Biquad< T, MaxChannels >

Biquad filter using Transposed Direct Form II (TDF-II) with thread-safe updates.

Implements a lock-free shadow buffering system (seqlock) to prevent torn reads when coefficients are updated by the UI thread concurrently with the audio thread. Per-channel states are stored compactly so adjacent channels share cache lines during block processing.

The filter core (coefficients, history and recursion) is always double precision, independent of the sample type: see the

Definition at line 555 of file Biquad.h.

Constructor & Destructor Documentation

◆ Biquad() [1/3]

template<typename T , int MaxChannels = 8>
dspark::Biquad< T, MaxChannels >::Biquad ( )
defaultnoexcept

◆ Biquad() [2/3]

template<typename T , int MaxChannels = 8>
dspark::Biquad< T, MaxChannels >::Biquad ( Biquad< T, MaxChannels > &&  other)
inlinenoexcept

Definition at line 567 of file Biquad.h.

◆ Biquad() [3/3]

template<typename T , int MaxChannels = 8>
dspark::Biquad< T, MaxChannels >::Biquad ( const Biquad< T, MaxChannels > &  )
delete

Member Function Documentation

◆ applyPendingCoeffs()

template<typename T , int MaxChannels = 8>
bool dspark::Biquad< T, MaxChannels >::applyPendingCoeffs ( )
inlinenoexcept

Promotes any pending staged coefficients to active.

Real-time safe. Both processBlock() and processSample() invoke this automatically (the per-sample call is gated by a relaxed-load fast path so it is essentially free when there is no pending update).

Exposed publicly for the rare case where you have just called setCoeffs() on this same thread and want the change reflected immediately, e.g. for an offline / introspection getCoeffs() right after pushing new ones.

Returns
true if the active coefficients changed in this call.

Definition at line 631 of file Biquad.h.

◆ getCoeffs()

template<typename T , int MaxChannels = 8>
const BiquadCoeffs & dspark::Biquad< T, MaxChannels >::getCoeffs ( ) const
inlinenoexcept

Returns the active coefficient set currently in use by the DSP thread.

Intended for the thread that owns processing (or single-threaded / offline use). A GUI thread reading this concurrently with a promotion may observe a mid-update set; for drawing response curves, keep your own copy of the coefficients you computed.

Definition at line 665 of file Biquad.h.

◆ operator=() [1/2]

template<typename T , int MaxChannels = 8>
Biquad & dspark::Biquad< T, MaxChannels >::operator= ( Biquad< T, MaxChannels > &&  other)
inlinenoexcept

Definition at line 575 of file Biquad.h.

◆ operator=() [2/2]

template<typename T , int MaxChannels = 8>
Biquad & dspark::Biquad< T, MaxChannels >::operator= ( const Biquad< T, MaxChannels > &  )
delete

◆ processBlock()

template<typename T , int MaxChannels = 8>
void dspark::Biquad< T, MaxChannels >::processBlock ( AudioBufferView< T >  buffer)
inlinenoexcept

Processes a full audio buffer in-place.

Thread-safe block processing. Absorbs asynchronous coefficient updates at the start of the block to ensure atomic parameter changes.

The inner loop runs on a local copy of the coefficients: with no per-sample dirty-flag check in sight, the compiler keeps b0..a2 and the filter state in registers for the whole block (roughly 1.5-2x faster than routing every sample through processSample()).

Channels beyond MaxChannels are left untouched (pass-through): only the first min(numChannels, MaxChannels) channels are filtered.

Parameters
bufferAudio buffer to process in-place.

Definition at line 750 of file Biquad.h.

◆ processSample()

template<typename T , int MaxChannels = 8>
T dspark::Biquad< T, MaxChannels >::processSample ( input,
int  channel 
)
inlinenoexcept

Processes a single sample for a specific channel.

Transposed Direct Form II implementation. Self-sufficient: any setCoeffs() update from another thread is picked up here on the very next sample with virtually zero overhead; the fast-path is a relaxed load (a plain MOV on x86) compiled into a single branchless check.

No external sequencing is required. The caller is free to mix processSample() and processBlock() calls in any order, and concurrent setCoeffs() from the GUI thread always becomes audible deterministically within at most a couple of samples (single sample on x86/ARM).

Precondition
channel must be in [0, MaxChannels). Enforced by assert in debug builds; out-of-range access in release builds is undefined behaviour.
Parameters
inputInput sample.
channelChannel index (0-based).
Returns
Filtered output sample.

Definition at line 694 of file Biquad.h.

◆ processSampleCore()

template<typename T , int MaxChannels = 8>
double dspark::Biquad< T, MaxChannels >::processSampleCore ( double  input,
int  channel 
)
inlinenoexcept

One recursion step in the core's own precision (double).

Same filter, same state, no conversion at the boundary: a cascade calls this to keep the intermediate signal in the core precision instead of re-quantising it to T between stages (FilterEngine does). Identical contract to processSample() otherwise, including the lock-free pickup of pending coefficients.

Precondition
channel must be in [0, MaxChannels).
Parameters
inputInput sample.
channelChannel index (0-based).
Returns
Filtered output sample.

Definition at line 714 of file Biquad.h.

◆ reset()

template<typename T , int MaxChannels = 8>
void dspark::Biquad< T, MaxChannels >::reset ( )
inlinenoexcept

Resets all per-channel filter states to zero to avoid ringing/clicks.

Definition at line 668 of file Biquad.h.

◆ setCoeffs()

template<typename T , int MaxChannels = 8>
void dspark::Biquad< T, MaxChannels >::setCoeffs ( const BiquadCoeffs c)
inlinenoexcept

Sets the filter coefficients asynchronously.

Safely updates coefficients without locking. The audio thread will pick up the new coefficients safely on the next process call to avoid torn reads and filter blow-ups.

Parameters
cNew coefficient set.

Definition at line 599 of file Biquad.h.


The documentation for this class was generated from the following file: