Process context — passed every audio callback with transport state. More...
#include <process_context.hpp>
Public Member Functions | |
| constexpr bool | has_transport (TransportField field) const noexcept |
| bool | is_realtime () const noexcept |
| bool | is_offline () const noexcept |
| bool | allows_offline_quality_work () const noexcept |
| bool | should_reset_dsp_state () const noexcept |
| True when DSP state should treat this block as a discontinuity boundary. | |
| bool | should_reset_stream_history () const noexcept |
| True when continuous audio-stream history should be cleared. | |
| bool | is_maintenance_render () const noexcept |
| True when this block is not a normal input-driven render but the host is still calling process() so a processor can settle internal state, drain a tail, or maintain bypass-aware state. | |
| bool | should_render_tail_only () const noexcept |
| True when the host is asking the processor to render only existing tail state. | |
Public Attributes | |
| double | sample_rate = 0 |
| int | num_samples = 0 |
| ProcessMode | process_mode = ProcessMode::Realtime |
| Runtime mode for this block. | |
| bool | is_bypassed = false |
| True when the host is rendering the plugin's bypass path for this block. | |
| bool | is_tail_drain = false |
| True when the host is asking a processor to continue rendering after input/transport stop so delay, reverb, or lookahead state can settle. | |
| bool | reset_requested = false |
| True for the first block after a transport jump, seek, or explicit DSP reset boundary. | |
| bool | transport_jump = false |
| True when the host observed a discontinuous timeline move since the previous block. | |
| RenderSpeedHint | render_speed_hint = RenderSpeedHint::Unknown |
| Advisory render-speed category for hosts that know whether the current pass is live, faster-than-realtime export, or slower/constrained render. | |
| bool | is_playing = false |
| bool | is_recording = false |
| double | tempo_bpm = 120.0 |
| double | position_beats = 0.0 |
| Position in quarter notes. | |
| int64_t | position_samples = 0 |
| int | time_sig_numerator = 4 |
| int | time_sig_denominator = 4 |
| int64_t | bar = 0 |
| Bar index derived from position_beats + the active time signature. | |
| bool | is_looping = false |
| True when the host's transport is in cycle/loop mode. | |
| double | loop_start_beats = 0.0 |
| Loop start in quarter notes, only meaningful when is_looping is true. | |
| double | loop_end_beats = 0.0 |
| Loop end in quarter notes, only meaningful when is_looping is true. | |
| int64_t | host_time_ns = 0 |
| Host clock timestamp matching the start of this block, in nanoseconds since an epoch the host chooses. | |
| FrameRate | frame_rate = FrameRate::unknown |
| SMPTE frame rate when the host exposes one. | |
| bool | tempo_changed = false |
| True when the host's reported tempo_bpm differs from the previous block. | |
| bool | time_sig_changed = false |
| True when the host's reported time signature (time_sig_numerator or time_sig_denominator) differs from the previous block. | |
| bool | transport_changed = false |
| True when any transport state field (is_playing, is_recording, is_looping) flipped since the previous block. | |
| bool | transport_started = false |
| True on the first block of a run — the block where the host's transport begins rolling. | |
| TransportValidity | transport_validity {} |
| Identifies which transport values were supplied for this block. | |
| bool | ordinary_loop_wrap = false |
| True when the adapter classified this block's transport_jump as the expected backward move from a stable host loop end to its loop start. | |
Process context — passed every audio callback with transport state.
Fields are populated by the host. Not all hosts provide all fields; when an adapter publishes transport_validity, it distinguishes unavailable values from valid defaults.
Adapter sourcing:
Change-flags (tempo_changed, time_sig_changed, transport_changed) are computed by the adapter once per block by diffing against the previous block's snapshot, so processors can branch on transitions only without re-reading every field.
|
inlinenoexcept |
|
inlineconstexprnoexcept |
|
inlinenoexcept |
True when this block is not a normal input-driven render but the host is still calling process() so a processor can settle internal state, drain a tail, or maintain bypass-aware state.
Processors must still obey the realtime/offline contract for the block.
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
True when the host is asking the processor to render only existing tail state.
This is intentionally separate from bypass: some hosts bypass by short-circuiting process(), while others continue calling process() to let tails settle.
|
inlinenoexcept |
True when DSP state should treat this block as a discontinuity boundary.
Hosts can request this explicitly, and adapters can derive it from a transport seek/jump. Processors commonly use this to clear synced phase, delay history, or tempo-grid caches before rendering the block.
|
inlinenoexcept |
True when continuous audio-stream history should be cleared.
Unlike should_reset_dsp_state(), an ordinary host loop wrap is not destructive: audio is still arriving continuously, so clearing a delay line or WOLA overlap state would manufacture a gap at every cycle boundary. Explicit host resets always win, including when they coincide with a loop wrap.
| int64_t pulp::format::ProcessContext::bar = 0 |
Bar index derived from position_beats + the active time signature.
Hosts may already publish a precomputed bar (VST3 Vst::ProcessContext::barPositionMusic) — in that case the adapter uses the host value directly. Otherwise the adapter derives bar = floor(position_beats * (time_sig_denominator / 4) / time_sig_numerator) and writes it here so processors that just need "what bar am I in" do not recompute it per block. Default 0 matches a stopped-at-origin playhead.
| FrameRate pulp::format::ProcessContext::frame_rate = FrameRate::unknown |
SMPTE frame rate when the host exposes one.
Default FrameRate::unknown is the documented sentinel meaning "host did not provide" — plugins must check before using.
| int64_t pulp::format::ProcessContext::host_time_ns = 0 |
Host clock timestamp matching the start of this block, in nanoseconds since an epoch the host chooses.
Used for video sync against the OS clock. Sources: VST3 Vst::ProcessContext::systemTime (already nanoseconds on Apple; otherwise host-defined); AU mach_absolute_time() converted via mach_timebase_info (the AU adapter performs the conversion before writing here); CLAP has no host-time field today, so the adapter leaves the value at 0 (sentinel = "not provided"); AAX IACFTransport's sample-position only — host time is unavailable, so leave at 0.
| bool pulp::format::ProcessContext::is_bypassed = false |
True when the host is rendering the plugin's bypass path for this block.
Most current adapters short-circuit before calling process() while bypassed, so the default remains false and this flag is only meaningful on hosts that intentionally process while bypassed to drain tails.
| bool pulp::format::ProcessContext::is_looping = false |
True when the host's transport is in cycle/loop mode.
VST3 exposes this as the kCycleActive flag on ProcessContext; AU surfaces it via HostTransport's outIsCycling; CLAP via the CLAP_TRANSPORT_IS_LOOP_ACTIVE bit on clap_event_transport::flags; AAX via IACFTransport's loop state. Default false (no loop).
| bool pulp::format::ProcessContext::is_playing = false |
| bool pulp::format::ProcessContext::is_recording = false |
| bool pulp::format::ProcessContext::is_tail_drain = false |
True when the host is asking a processor to continue rendering after input/transport stop so delay, reverb, or lookahead state can settle.
| double pulp::format::ProcessContext::loop_end_beats = 0.0 |
Loop end in quarter notes, only meaningful when is_looping is true.
Same source list as loop_start_beats. Default 0 (loop_start == loop_end => no loop range yet).
| double pulp::format::ProcessContext::loop_start_beats = 0.0 |
Loop start in quarter notes, only meaningful when is_looping is true.
Mirrors position_beats's PPQ convention. Sources: VST3 Vst::ProcessContext::cycleStartMusic; AU HostTransport::outCycleStartBeat; CLAP clap_event_transport::loop_start_beats (converted from CLAP's fixed-point clap_beattime); AAX IACFTransport::GetCurrentLoopPosition. Default 0.
| int pulp::format::ProcessContext::num_samples = 0 |
| bool pulp::format::ProcessContext::ordinary_loop_wrap = false |
True when the adapter classified this block's transport_jump as the expected backward move from a stable host loop end to its loop start.
transport_jump deliberately remains true: timeline-driven processors still need to observe that discontinuity. Streaming effects can use this narrower signal to preserve delay, overlap-add, and reverb history across an ordinary cycle while continuing to clear it on a real seek.
Classification is conservative. It is only true when the host supplied a coherent loop range plus enough beat/tempo timing to predict the wrapped position. Missing or inconsistent metadata leaves it false.
| double pulp::format::ProcessContext::position_beats = 0.0 |
Position in quarter notes.
| int64_t pulp::format::ProcessContext::position_samples = 0 |
| ProcessMode pulp::format::ProcessContext::process_mode = ProcessMode::Realtime |
Runtime mode for this block.
Defaults to live realtime processing for source compatibility; offline/headless/render hosts should set ProcessMode::Offline explicitly.
| RenderSpeedHint pulp::format::ProcessContext::render_speed_hint = RenderSpeedHint::Unknown |
Advisory render-speed category for hosts that know whether the current pass is live, faster-than-realtime export, or slower/constrained render.
| bool pulp::format::ProcessContext::reset_requested = false |
True for the first block after a transport jump, seek, or explicit DSP reset boundary.
Processors can use this to clear tempo-synced phase or delay history without guessing from position discontinuities.
| double pulp::format::ProcessContext::sample_rate = 0 |
| double pulp::format::ProcessContext::tempo_bpm = 120.0 |
| bool pulp::format::ProcessContext::tempo_changed = false |
True when the host's reported tempo_bpm differs from the previous block.
Lets processors recompute tempo-dependent derived state (sample-domain envelope rates, delay-line beat lengths) only on transitions instead of every block. Computed by the adapter as current.tempo_bpm != previous.tempo_bpm. Default false (no change relative to a hypothetical previous block, which matches the initial-state contract).
| bool pulp::format::ProcessContext::time_sig_changed = false |
True when the host's reported time signature (time_sig_numerator or time_sig_denominator) differs from the previous block.
Lets processors rebuild bar-grid state on transitions only. Default false.
| int pulp::format::ProcessContext::time_sig_denominator = 4 |
| int pulp::format::ProcessContext::time_sig_numerator = 4 |
| bool pulp::format::ProcessContext::transport_changed = false |
True when any transport state field (is_playing, is_recording, is_looping) flipped since the previous block.
Lets processors reset playback-only DSP state (e.g. flush a reverb tail when transport stops) on transitions only. Default false.
| bool pulp::format::ProcessContext::transport_jump = false |
True when the host observed a discontinuous timeline move since the previous block.
This is narrower than transport_changed: play/stop transitions do not imply a jump unless position also changed discontinuously.
| bool pulp::format::ProcessContext::transport_started = false |
True on the first block of a run — the block where the host's transport begins rolling.
Set when is_playing goes false→true, and also on the very first block a processor ever sees if the transport is already playing (a plugin inserted mid-playback), because that block starts a run from the processor's point of view.
This is deliberately NOT folded into should_reset_dsp_state(). A transport start is not a timeline discontinuity: pressing play at a parked position leaves position_samples unchanged, so transport_jump stays false and delay/reverb tails must survive. What a transport start does invalidate is run-relative phase — a tempo-synced LFO's cycle origin, a clock generator's first-pulse delay, a step sequencer's step index.
Processors that free-run a phase accumulator across a stop and then "catch up" to the new position on the next play emit a burst of backlogged events on that block. Capture your run origin here instead. Prefer deriving event positions from position_beats outright; then a start, a seek, and a loop wrap are all the same case and none of them can produce a burst.
| TransportValidity pulp::format::ProcessContext::transport_validity {} |
Identifies which transport values were supplied for this block.
A clear bit means the corresponding value is only its compatibility default. Format adapters publish this mask from their host APIs; a host that does not supply transport leaves it empty. Kept after the original data members so existing field offsets do not move.