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

Plays audio that a worker thread renders, at an exact, fixed latency, for a host whose blocks vary in size. More...

#include <async_block_worker.hpp>

Classes

class  Chunk
 One stretch of positions the job renders. More...

Public Types

using TimedEvent = AsyncBlockEvent<Event>
using Job = std::function<void(Chunk&)>
using LatencyListener = void (*)(void* context) noexcept

Public Member Functions

 AsyncBlockWorker ()=default
 ~AsyncBlockWorker ()
 AsyncBlockWorker (const AsyncBlockWorker &)=delete
AsyncBlockWorker & operator= (const AsyncBlockWorker &)=delete
bool prepare (const AsyncBlockWorkerConfig &config, Job job)
 Control thread.
void release () noexcept
 Control thread. Stops and joins the worker thread.
bool is_prepared () const noexcept
const AsyncBlockWorkerConfig & config () const noexcept
std::uint32_t latency_samples () const noexcept
 The latency to report to the host: the block latency plus the worker's own.
bool request_latency_blocks (std::uint32_t blocks) noexcept
 Any thread.
void set_worker_latency_samples (std::uint32_t samples) noexcept
 Any thread (typically the job, when its own latency moves).
void set_latency_listener (LatencyListener listener, void *context) noexcept
 Called on the audio thread, inside process(), when the reported latency changed.
template<typename Emit>
void process (const BufferView< const float > &input, BufferView< float > &output, std::uint32_t frames, std::span< const TimedEvent > events, Emit &&emit, AsyncBlockMode mode=AsyncBlockMode::Realtime) noexcept
 The audio callback.
std::uint32_t pump (std::uint32_t max_chunks=0) noexcept
 Worker step: renders every submitted position not yet produced, at most max_chunks chunks (0: all).
AsyncBlockWorkerStats stats () const noexcept

Detailed Description

template<typename Event = std::uint8_t>
class pulp::audio::AsyncBlockWorker< Event >

Plays audio that a worker thread renders, at an exact, fixed latency, for a host whose blocks vary in size.

Every frame has a stream position. process() writes the host block's input (and timed events) at positions [S, S + n), then plays the output of positions [D - L, D - L + n), where D counts the frames delivered so far and L = latency_blocks * max_block. The worker renders the positions in order, in chunks of its own size, into a ring addressed by position. Because latency is defined on positions, not on calls, it is exact for any block-size sequence (1 frame, 4096 frames, alternating) and cannot drift: a frame the worker has not finished in time plays as silence (counted as a miss) and its late output is never played, rather than shifting what follows. Positions before the first frame play as silence (pre-roll).

Events go to the worker with their absolute position and come back the same way, so an event the job emits at chunk offset k is delivered in the output callback that plays position start + k, at the matching offset. An output event whose frame has already been played is delivered at offset 0 of the next call (counted late) rather than dropped: a note-off must not be lost.

Threads:

  • prepare() / release(): control thread, no process() or pump() running.
  • process(): the audio thread. No allocation and no lock; it posts the worker through runtime::WakeSignal (a system call only while the worker sleeps). It blocks only in Offline mode, in Auto while the host pulls faster than real time, or at zero latency, and then never longer than wait_deadline.
  • The job: the worker thread (or the pump() caller), one chunk at a time.
  • request_latency_blocks() / set_worker_latency_samples(): any thread. A change takes effect at the start of the next process() call, which then calls the latency listener on the audio thread (a processor's flag_latency_changed() is the intended listener; it is realtime safe). A larger latency never replays audio: the frames the window moves back over were already played and play as silence once; a smaller one skips frames. Hosts expect a glitch when a plug-in's latency changes.

GpuAudioTransport keeps the same timeline for the special case of one fixed block size: its primed output ring is pre-roll, its latency_blocks is L / max_block, and its resync after a miss is the position rule above.

Member Typedef Documentation

◆ Job

template<typename Event = std::uint8_t>
using pulp::audio::AsyncBlockWorker< Event >::Job = std::function<void(Chunk&)>

◆ LatencyListener

template<typename Event = std::uint8_t>
using pulp::audio::AsyncBlockWorker< Event >::LatencyListener = void (*)(void* context) noexcept

◆ TimedEvent

template<typename Event = std::uint8_t>
using pulp::audio::AsyncBlockWorker< Event >::TimedEvent = AsyncBlockEvent<Event>

Constructor & Destructor Documentation

◆ AsyncBlockWorker() [1/2]

template<typename Event = std::uint8_t>
pulp::audio::AsyncBlockWorker< Event >::AsyncBlockWorker ( )
default

◆ ~AsyncBlockWorker()

template<typename Event = std::uint8_t>
pulp::audio::AsyncBlockWorker< Event >::~AsyncBlockWorker ( )
inline

◆ AsyncBlockWorker() [2/2]

template<typename Event = std::uint8_t>
pulp::audio::AsyncBlockWorker< Event >::AsyncBlockWorker ( const AsyncBlockWorker< Event > & )
delete

Member Function Documentation

◆ config()

template<typename Event = std::uint8_t>
const AsyncBlockWorkerConfig & pulp::audio::AsyncBlockWorker< Event >::config ( ) const
inlinenoexcept

◆ is_prepared()

template<typename Event = std::uint8_t>
bool pulp::audio::AsyncBlockWorker< Event >::is_prepared ( ) const
inlinenoexcept

◆ latency_samples()

template<typename Event = std::uint8_t>
std::uint32_t pulp::audio::AsyncBlockWorker< Event >::latency_samples ( ) const
inlinenoexcept

The latency to report to the host: the block latency plus the worker's own.

Any thread.

◆ operator=()

template<typename Event = std::uint8_t>
AsyncBlockWorker & pulp::audio::AsyncBlockWorker< Event >::operator= ( const AsyncBlockWorker< Event > & )
delete

◆ prepare()

template<typename Event = std::uint8_t>
bool pulp::audio::AsyncBlockWorker< Event >::prepare ( const AsyncBlockWorkerConfig & config,
Job job )
inline

Control thread.

Allocates the rings and starts the worker thread when configured. False for an invalid configuration.

◆ process()

template<typename Event = std::uint8_t>
template<typename Emit>
void pulp::audio::AsyncBlockWorker< Event >::process ( const BufferView< const float > & input,
BufferView< float > & output,
std::uint32_t frames,
std::span< const TimedEvent > events,
Emit && emit,
AsyncBlockMode mode = AsyncBlockMode::Realtime )
inlinenoexcept

The audio callback.

input may be empty for an instrument; frames at most max_block. Events carry offsets within this block, in offset order; emit is called as emit(offset, event) for each output event due in it. A job emits its chunk's events in offset order too.

◆ pump()

template<typename Event = std::uint8_t>
std::uint32_t pulp::audio::AsyncBlockWorker< Event >::pump ( std::uint32_t max_chunks = 0)
inlinenoexcept

Worker step: renders every submitted position not yet produced, at most max_chunks chunks (0: all).

Returns the chunks rendered. Call from one thread at a time: the internal worker, or the owner when run_worker_thread is false.

◆ release()

template<typename Event = std::uint8_t>
void pulp::audio::AsyncBlockWorker< Event >::release ( )
inlinenoexcept

Control thread. Stops and joins the worker thread.

◆ request_latency_blocks()

template<typename Event = std::uint8_t>
bool pulp::audio::AsyncBlockWorker< Event >::request_latency_blocks ( std::uint32_t blocks)
inlinenoexcept

Any thread.

Takes effect at the next process() call. False when out of the prepared range.

◆ set_latency_listener()

template<typename Event = std::uint8_t>
void pulp::audio::AsyncBlockWorker< Event >::set_latency_listener ( LatencyListener listener,
void * context )
inlinenoexcept

Called on the audio thread, inside process(), when the reported latency changed.

Set before the first process() call.

◆ set_worker_latency_samples()

template<typename Event = std::uint8_t>
void pulp::audio::AsyncBlockWorker< Event >::set_worker_latency_samples ( std::uint32_t samples)
inlinenoexcept

Any thread (typically the job, when its own latency moves).

◆ stats()

template<typename Event = std::uint8_t>
AsyncBlockWorkerStats pulp::audio::AsyncBlockWorker< Event >::stats ( ) const
inlinenoexcept

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