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

#include <freeze_hold.hpp>

Classes

struct  Config
 Two sizing modes. More...

Public Types

using Snapshot = FreezeHoldSnapshotT<SampleType>

Public Member Functions

void prepare (const Config &requested)
 RT contract: prepare() allocates capture/hold storage and is not audio-thread safe.
const Config & config () const
 The resolved configuration this hold was prepared with.
void set_capture_frames (int frames)
 Hold length: the number of most recent frames the NEXT latch averages, clamped to [2, max_capture_frames].
void set_capture_seconds (double seconds)
 Seconds-based form of set_capture_frames(); ignored unless the hold was prepared with a sample rate.
int capture_frames () const
 The capture depth the next latch uses.
void reset ()
 Full reset: drops the hold and the capture history and re-seeds the PRNG (the prepared state).
void clear_history ()
 Forget captured input only.
void set_frozen (bool frozen)
 RT-safe engage/release request.
bool is_engaged () const
 The last engage/release request.
bool is_latched () const
 True once held content is actually playing (capture was full).
bool is_releasing () const
 True while a released hold is fading out.
bool has_hold () const
 True once a hold has been latched or restored since the last reset(); the held-state accessors and write_hold() describe it.
SampleType engage_progress () const
 Hold-weight position of the crossfade used for the most recent frame group: 0 = live only, 1 = hold only, stepping by 1/crossfade_frames per frame group.
std::span< const SampleType > held_magnitudes (int channel) const
 Averaged magnitudes of one channel's hold (num_bins values).
std::span< const double > held_phases (int channel) const
 Current hold phases of one channel, wrapped to [-pi, pi]: the phases the next hold frame is rendered with.
std::span< const double > instantaneous_frequency () const
 Per-bin instantaneous frequency of the hold, radians per sample.
bool write_hold (std::complex< SampleType > *const *frames, int channels, int num_bins) const
 Render the current hold frame (magnitude and phase only — no live mix, no crossfade, no phase advance) into frames.
bool engage_pending () const
 True while latch- or restore-side rotor construction is still being staged across frame groups (engage_bins_per_hop > 0).
void advance_hold (int frames=1)
 Advance the hold by frames analysis hops exactly as process_group() does after each held frame (instantaneous frequency plus the random walk, consuming the PRNG).
void rewind_hold_phases (int frames)
 Move the hold phases back by frames hops at the instantaneous frequency, without the random walk and without touching the PRNG — e.g.
bool snapshot (Snapshot &out) const
 Copy the current hold into out, which must have been prepared for this geometry.
bool stage_restore (const Snapshot &in, FreezeRestoreEngage engage=FreezeRestoreEngage::crossfade)
 Stage in to become the hold at the start of the next process_group().
bool restore_pending () const
 True while a staged restore is waiting for the next frame group.
void process_group (std::complex< SampleType > *const *frames, int channels, int num_bins)
 Run at the head of the vocoder chain for every analysis frame group.

Static Public Member Functions

static Config resolve (const Config &config) noexcept
 Resolve the time-based fields of config into frame counts: the exact configuration prepare() runs with.
static int frames_for_seconds (double seconds, const Config &config) noexcept
 round(seconds * sample_rate / analysis_hop) for a seconds-based config (0 when it is not seconds-based or seconds is not positive).
static bool checked_retained_bytes (const Config &requested, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept

Member Typedef Documentation

◆ Snapshot

template<typename SampleType = float>
using pulp::signal::FreezeHoldT< SampleType >::Snapshot = FreezeHoldSnapshotT<SampleType>

Member Function Documentation

◆ advance_hold()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::advance_hold ( int frames = 1)
inline

Advance the hold by frames analysis hops exactly as process_group() does after each held frame (instantaneous frequency plus the random walk, consuming the PRNG).

For consumers that render the hold with write_hold() instead of process_group(); never combine the two on the same frame.

◆ capture_frames()

template<typename SampleType = float>
int pulp::signal::FreezeHoldT< SampleType >::capture_frames ( ) const
inline

The capture depth the next latch uses.

◆ checked_retained_bytes()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::checked_retained_bytes ( const Config & requested,
std::uint64_t target_max_bytes,
std::uint64_t & bytes )
inlinestaticnoexcept

◆ clear_history()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::clear_history ( )
inline

Forget captured input only.

The hold, its request and fade position, and the PRNG are kept, so a playing hold continues seamlessly across a transport jump; an armed or later freeze re-fills its capture window from input analyzed after this call.

◆ config()

template<typename SampleType = float>
const Config & pulp::signal::FreezeHoldT< SampleType >::config ( ) const
inline

The resolved configuration this hold was prepared with.

◆ engage_pending()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::engage_pending ( ) const
inline

True while latch- or restore-side rotor construction is still being staged across frame groups (engage_bins_per_hop > 0).

◆ engage_progress()

template<typename SampleType = float>
SampleType pulp::signal::FreezeHoldT< SampleType >::engage_progress ( ) const
inline

Hold-weight position of the crossfade used for the most recent frame group: 0 = live only, 1 = hold only, stepping by 1/crossfade_frames per frame group.

Engage mixes hold/live linearly at this position; release mixes them with equal-power gains sin/cos(progress * pi/2). 0 while not latched. engage_progress() == 1 && !is_releasing() means the last frame group was pure hold.

◆ frames_for_seconds()

template<typename SampleType = float>
int pulp::signal::FreezeHoldT< SampleType >::frames_for_seconds ( double seconds,
const Config & config )
inlinestaticnoexcept

round(seconds * sample_rate / analysis_hop) for a seconds-based config (0 when it is not seconds-based or seconds is not positive).

◆ has_hold()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::has_hold ( ) const
inline

True once a hold has been latched or restored since the last reset(); the held-state accessors and write_hold() describe it.

◆ held_magnitudes()

template<typename SampleType = float>
std::span< const SampleType > pulp::signal::FreezeHoldT< SampleType >::held_magnitudes ( int channel) const
inline

Averaged magnitudes of one channel's hold (num_bins values).

◆ held_phases()

template<typename SampleType = float>
std::span< const double > pulp::signal::FreezeHoldT< SampleType >::held_phases ( int channel) const
inline

Current hold phases of one channel, wrapped to [-pi, pi]: the phases the next hold frame is rendered with.

With rotor synthesis the phases are derived from the phasors on each call (one atan2 per bin): an inspection accessor, not a per-hop call.

◆ instantaneous_frequency()

template<typename SampleType = float>
std::span< const double > pulp::signal::FreezeHoldT< SampleType >::instantaneous_frequency ( ) const
inline

Per-bin instantaneous frequency of the hold, radians per sample.

While engage_pending() the bins not yet staged are incomplete.

◆ is_engaged()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::is_engaged ( ) const
inline

The last engage/release request.

◆ is_latched()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::is_latched ( ) const
inline

True once held content is actually playing (capture was full).

Stays true through the release fade.

◆ is_releasing()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::is_releasing ( ) const
inline

True while a released hold is fading out.

◆ prepare()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::prepare ( const Config & requested)
inline

RT contract: prepare() allocates capture/hold storage and is not audio-thread safe.

After prepare(), every other member is allocation-free for the prepared channel/bin counts. prepare() drops a staged restore.

◆ process_group()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::process_group ( std::complex< SampleType > *const * frames,
int channels,
int num_bins )
inline

Run at the head of the vocoder chain for every analysis frame group.

Captures live frames; when engaged and latched, replaces frames with hold content (crossfaded at the edges).

◆ reset()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::reset ( )
inline

Full reset: drops the hold and the capture history and re-seeds the PRNG (the prepared state).

For a transport discontinuity that should keep an engaged hold, use clear_history() instead. A restore staged by stage_restore() stays pending and is adopted by the next process_group(), so a host that resets after recalling state still hears the recalled hold.

◆ resolve()

template<typename SampleType = float>
Config pulp::signal::FreezeHoldT< SampleType >::resolve ( const Config & config)
inlinestaticnoexcept

Resolve the time-based fields of config into frame counts: the exact configuration prepare() runs with.

Pure.

◆ restore_pending()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::restore_pending ( ) const
inline

True while a staged restore is waiting for the next frame group.

Safe from any thread.

◆ rewind_hold_phases()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::rewind_hold_phases ( int frames)
inline

Move the hold phases back by frames hops at the instantaneous frequency, without the random walk and without touching the PRNG — e.g.

to align a hold with a path that runs a fixed number of hops behind it. Not an exact inverse of advance_hold(), whose walk it does not undo.

With rotor synthesis a rewind while engage_pending() first finishes the staged rotor construction, since it needs every bin's rotor.

◆ set_capture_frames()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::set_capture_frames ( int frames)
inline

Hold length: the number of most recent frames the NEXT latch averages, clamped to [2, max_capture_frames].

RT-safe; it does not change a hold already playing. Survives reset() and clear_history(). A shorter window freezes closer to "now"; a longer one blends more of the recent past into a smoother hold.

◆ set_capture_seconds()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::set_capture_seconds ( double seconds)
inline

Seconds-based form of set_capture_frames(); ignored unless the hold was prepared with a sample rate.

◆ set_frozen()

template<typename SampleType = float>
void pulp::signal::FreezeHoldT< SampleType >::set_frozen ( bool frozen)
inline

RT-safe engage/release request.

Releasing a latched hold commits it to fade out and restarts the capture window, so the next freeze averages only frames analyzed from the release onward (re-arming, without muting, until the window is full again) — also when the freeze is requested again before the release fade has finished.

◆ snapshot()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::snapshot ( Snapshot & out) const
inline

Copy the current hold into out, which must have been prepared for this geometry.

Returns false (leaving out unchanged) when there is no hold, the storage does not match, or engage staging has not finished (engage_pending()). Allocation-free.

◆ stage_restore()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::stage_restore ( const Snapshot & in,
FreezeRestoreEngage engage = FreezeRestoreEngage::crossfade )
inline

Stage in to become the hold at the start of the next process_group().

Safe to call from ONE non-audio thread concurrently with process_group(); copies into storage allocated at prepare(). Returns false — the caller should drop the capture and re-arm — for a snapshot whose fft_size, channels or analysis_hop differ from this hold's, whose known sample rate differs from this hold's known rate, an invalid snapshot, or when an earlier restore has not been adopted yet. crossfade and immediate adoption engage the hold (set_frozen(true) is implied); as_captured resumes the recorded request and fade position.

◆ write_hold()

template<typename SampleType = float>
bool pulp::signal::FreezeHoldT< SampleType >::write_hold ( std::complex< SampleType > *const * frames,
int channels,
int num_bins ) const
inline

Render the current hold frame (magnitude and phase only — no live mix, no crossfade, no phase advance) into frames.

Returns false, writing nothing, when there is no hold or the shape does not match.


The documentation for this class was generated from the following file:
  • /home/runner/work/pulp/pulp/core/signal/include/pulp/signal/freeze_hold.hpp