Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::ConvolverIrSwapperT< SampleType > Class Template Reference

Lock-free background-IR shuttle for PartitionedConvolver. More...

#include <convolver_messages.hpp>

Public Member Functions

 ConvolverIrSwapperT ()=default
 ConvolverIrSwapperT (const ConvolverIrSwapperT &)=delete
ConvolverIrSwapperT & operator= (const ConvolverIrSwapperT &)=delete
bool stage_ir (const SampleType *ir, std::size_t ir_length, std::size_t block_size)
 Build a fresh IR state off the audio thread and publish it for the audio thread to pick up.
bool stage_ir (std::unique_ptr< ConvolverIrStateT< SampleType > > next)
 Publish a pre-built state. Same semantics as the raw overload.
std::unique_ptr< ConvolverIrStateT< SampleType > > try_consume ()
 Audio-thread-callable: atomically claim the most recently staged IR, if any.
bool retire (std::unique_ptr< ConvolverIrStateT< SampleType > > &displaced)
 Audio-thread-callable: park the IR that the audio thread is displacing so a non-RT thread can free it.
bool has_retire_capacity () const
 True if there's room in the retire ring for one more displaced IR.
bool has_retire_capacity (std::size_t n) const
 Room to park at least n IRs — for a caller that must retire more than one in a single audio-thread step (e.g.
std::size_t drain_old ()
 UI / worker thread: reclaim ALL retired IRs the audio thread has parked.
std::unique_ptr< ConvolverIrStateT< SampleType > > drain_old_one ()
 UI / worker thread: pop ONE retired IR for test inspection.
bool has_pending () const
 True if a freshly-staged IR is awaiting consumption.
bool has_retired () const
 True if any retired IR is awaiting drain.

Static Public Member Functions

static constexpr std::size_t retire_capacity ()
 Compile-time capacity of the retired-IR ring.

Detailed Description

template<typename SampleType = float>
class pulp::signal::ConvolverIrSwapperT< SampleType >

Lock-free background-IR shuttle for PartitionedConvolver.

Workflow (single producer, single audio-thread consumer):

ConvolverIrSwapper swapper; // background / UI thread PartitionedConvolver conv; // audio thread conv.load_ir(initial_ir, len, 256); // first IR loaded inline

// ── UI / worker thread ── swapper.stage_ir(new_ir, new_len, 256); // allocates, FFTs

// ── audio thread (block boundary) ── conv.try_swap_ir(swapper); // atomically picks up new IR

// ── UI / worker thread ── swapper.drain_old(); // reclaim memory from the displaced IR

Guarantees:

  • Audio thread does ZERO allocation, ZERO FFT precompute work, and ZERO blocking on a mutex; just two atomic pointer ops.
  • Old IR ownership is transferred back to the swapper via a reverse atomic slot; the UI/worker thread reclaims it with drain_old(). Audio thread never frees memory.

Constructor & Destructor Documentation

◆ ConvolverIrSwapperT() [1/2]

template<typename SampleType = float>
pulp::signal::ConvolverIrSwapperT< SampleType >::ConvolverIrSwapperT ( )
default

◆ ConvolverIrSwapperT() [2/2]

template<typename SampleType = float>
pulp::signal::ConvolverIrSwapperT< SampleType >::ConvolverIrSwapperT ( const ConvolverIrSwapperT< SampleType > & )
delete

Member Function Documentation

◆ drain_old()

template<typename SampleType = float>
std::size_t pulp::signal::ConvolverIrSwapperT< SampleType >::drain_old ( )
inline

UI / worker thread: reclaim ALL retired IRs the audio thread has parked.

Returns the count freed; the actual deallocation runs off the audio thread.

◆ drain_old_one()

template<typename SampleType = float>
std::unique_ptr< ConvolverIrStateT< SampleType > > pulp::signal::ConvolverIrSwapperT< SampleType >::drain_old_one ( )
inline

UI / worker thread: pop ONE retired IR for test inspection.

Returns nullptr if none queued.

◆ has_pending()

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::has_pending ( ) const
inline

True if a freshly-staged IR is awaiting consumption.

◆ has_retire_capacity() [1/2]

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::has_retire_capacity ( ) const
inline

True if there's room in the retire ring for one more displaced IR.

Audio thread checks this before consuming pending so a swap never strands a displaced IR without an off-thread free path.

◆ has_retire_capacity() [2/2]

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::has_retire_capacity ( std::size_t n) const
inline

Room to park at least n IRs — for a caller that must retire more than one in a single audio-thread step (e.g.

a completed crossfade fade-out PLUS the just-displaced IR). Reserve before committing so no retire ever fails inline and strands an IR on the audio thread.

◆ has_retired()

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::has_retired ( ) const
inline

True if any retired IR is awaiting drain.

◆ operator=()

template<typename SampleType = float>
ConvolverIrSwapperT & pulp::signal::ConvolverIrSwapperT< SampleType >::operator= ( const ConvolverIrSwapperT< SampleType > & )
delete

◆ retire()

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::retire ( std::unique_ptr< ConvolverIrStateT< SampleType > > & displaced)
inlinenodiscard

Audio-thread-callable: park the IR that the audio thread is displacing so a non-RT thread can free it.

Returns true if the IR was queued for drain; false if the retire ring is already full. On false the displaced state is returned to the caller via the moved-in unique_ptr being LEFT INTACT (caller still owns it). The audio-thread caller (see PartitionedConvolver::try_swap_ir) should gate the swap on has_retire_capacity() first so this path is never hit in well-paced operation.

RT contract: never allocates, never blocks, never frees.

◆ retire_capacity()

template<typename SampleType = float>
constexpr std::size_t pulp::signal::ConvolverIrSwapperT< SampleType >::retire_capacity ( )
inlinestaticconstexpr

Compile-time capacity of the retired-IR ring.

Sized so a few back-to-back swaps survive a single missed drain tick — past this point, swaps refuse until a drain runs.

◆ stage_ir() [1/2]

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::stage_ir ( const SampleType * ir,
std::size_t ir_length,
std::size_t block_size )
inline

Build a fresh IR state off the audio thread and publish it for the audio thread to pick up.

Returns true on success.

If a previously-staged IR has not yet been consumed by the audio thread, this call replaces it and the old pre-built state is freed inline (still on the worker thread — never the audio thread).

◆ stage_ir() [2/2]

template<typename SampleType = float>
bool pulp::signal::ConvolverIrSwapperT< SampleType >::stage_ir ( std::unique_ptr< ConvolverIrStateT< SampleType > > next)
inline

Publish a pre-built state. Same semantics as the raw overload.

◆ try_consume()

template<typename SampleType = float>
std::unique_ptr< ConvolverIrStateT< SampleType > > pulp::signal::ConvolverIrSwapperT< SampleType >::try_consume ( )
inline

Audio-thread-callable: atomically claim the most recently staged IR, if any.

Returns nullptr if nothing is pending. NEVER blocks, NEVER allocates, NEVER frees.


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