Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::drum::ClapVoice Class Reference

A hand clap. More...

#include <clap.hpp>

Public Member Functions

 ClapVoice ()
void set_burst_count (int count)
 How many bursts the train contains.
void set_burst_spacing_ms (double ms)
 Milliseconds between bursts.
void set_burst_decay_ms (double ms)
 How quickly each burst decays.
void set_burst_falloff (double ratio)
 How much quieter each burst is than the one before it, as a ratio.
void set_gap_jitter (double amount)
 How much each gap varies from the nominal spacing, 0 to 1.
void set_alternate_polarity (bool alternate)
 Invert every other burst.
void set_stereo_width (double width)
 Alternating burst width, 0 for mono through 1 for hard left/right.
void set_tail_level (double level)
 Level and decay of the tail that fuses the train.
void set_tail_decay_ms (double ms)
void set_cutoff_hz (double hz)
 Centre and resonance of the bandpass the noise is heard through.
void set_resonance (double q)
void set_noise_color (NoiseColor color)
void set_body_level (double level)
 Level of an optional sine under the train, at set_body_hz.
void set_body_hz (double hz)
OutputStage & output ()
const OutputStage & output () const
OutputStage * output_stage () noexcept override
 The terminal saturation and degradation stage, at the generic voice boundary.
int latency_samples () const noexcept override
 Fixed host-rate delay introduced by this voice's selected output quality.
OutputOversampling output_oversampling () const noexcept override
 Output quality at the generic voice boundary.
void set_output_oversampling (OutputOversampling factor) override
void prepare (double sample_rate)
 Fixes the sample rate and clears all state.
void reset ()
 Silences the voice immediately, without a fade.
void note_on (float velocity)
 Starts a hit. velocity is in [0, 1]; values outside are clamped.
void choke (float fade_ms=4.0f)
 Fades the voice out over fade_ms and then silences it.
bool is_active () const
 Whether the voice still has something to render.
VoiceState state () const
float velocity () const
double sample_rate () const
const OutputStage * output_stage () const noexcept
void set_velocity_response (const VelocityResponse &r)
const VelocityResponse & velocity_response () const
void process (float *out, int num_samples)
 Adds num_samples of this voice's output into out.
void process_stereo (float *left, float *right, int num_samples)
 Adds a stereo rendering to left and right.

Static Public Attributes

static constexpr int max_bursts = 8
 Upper bound on the burst train.

Protected Member Functions

void on_prepare (double sample_rate) override
 Sizes buffers and fixes coefficients.
void on_reset () override
 Clears every piece of state the voice carries, so is_active() becomes false and the next render starts from silence.
void on_note_on (float velocity) override
 Starts a hit at the given velocity, already clamped to [0, 1].
bool on_is_active () const override
void render_add (float *out, int num_samples) override
 Adds the voice's output into out. Must add, never assign.
void render_add_stereo (float *left, float *right, int num_samples) override
 Optional stereo realization.

Detailed Description

A hand clap.

A clap is not one sound. Several people clapping never land together, and even one person's clap is the hands meeting, separating slightly, and meeting again. What the ear identifies as "a clap" is that short burst train followed by the room – and the burst train is why a clap cannot be built as a single noise envelope no matter how it is shaped.

So the voice schedules a small number of noise bursts a few milliseconds apart and runs a longer, quieter tail underneath them from the first burst onward. The tail is what fuses the train into one event: without it the bursts are heard as separate ticks, and with it they are heard as one clap in a room. Widening the spacing past about 20 ms breaks that fusion, which is a usable effect and the reason the control is exposed rather than fixed.

The schedule is computed at note_on and is deterministic, so a clap renders identically for a given parameter set.

process() is the canonical mono realization. process_stereo() places successive bursts on alternating sides while keeping the tail and optional body in the centre. The two stereo channels sum to the canonical mono signal sample for sample, so a host can collapse the result without a level or timbre change.

What a mono sum does cost is decorrelation. Identically spaced, identically signed bursts are coherent with each other, so summing them combs: the train acquires a faint pitch at one over the gap that no single burst has. Two controls exist to break that up, and at least one of them wants to be on: set_gap_jitter varies the spacing per burst, and set_alternate_polarity flips every other burst. Both stay deterministic, so a render is still reproducible.

RT contract: prepare() allocates nothing; every other method allocates nothing and takes no locks.

Constructor & Destructor Documentation

◆ ClapVoice()

pulp::signal::drum::ClapVoice::ClapVoice ( )
inline

Member Function Documentation

◆ choke()

void pulp::signal::drum::Voice::choke ( float fade_ms = 4.0f)
inlineinherited

Fades the voice out over fade_ms and then silences it.

Used by choke groups; a shorter fade is more abrupt but never clicks the way an instant cut does.

◆ is_active()

bool pulp::signal::drum::Voice::is_active ( ) const
inlineinherited

Whether the voice still has something to render.

A kit uses this to skip voices entirely rather than summing silence.

◆ latency_samples()

int pulp::signal::drum::ClapVoice::latency_samples ( ) const
inlineoverridevirtualnoexcept

Fixed host-rate delay introduced by this voice's selected output quality.

Generic registry consumers can report it without recovering the concrete voice type.

Reimplemented from pulp::signal::drum::Voice.

◆ note_on()

void pulp::signal::drum::Voice::note_on ( float velocity)
inlineinherited

Starts a hit. velocity is in [0, 1]; values outside are clamped.

◆ on_is_active()

bool pulp::signal::drum::ClapVoice::on_is_active ( ) const
inlineoverrideprotectedvirtual

◆ on_note_on()

void pulp::signal::drum::ClapVoice::on_note_on ( float velocity)
inlineoverrideprotectedvirtual

Starts a hit at the given velocity, already clamped to [0, 1].

Implements pulp::signal::drum::Voice.

◆ on_prepare()

void pulp::signal::drum::ClapVoice::on_prepare ( double sample_rate)
inlineoverrideprotectedvirtual

Sizes buffers and fixes coefficients.

The only hook allowed to allocate.

Implements pulp::signal::drum::Voice.

◆ on_reset()

void pulp::signal::drum::ClapVoice::on_reset ( )
inlineoverrideprotectedvirtual

Clears every piece of state the voice carries, so is_active() becomes false and the next render starts from silence.

Implements pulp::signal::drum::Voice.

◆ output() [1/2]

OutputStage & pulp::signal::drum::ClapVoice::output ( )
inline

◆ output() [2/2]

const OutputStage & pulp::signal::drum::ClapVoice::output ( ) const
inline

◆ output_oversampling()

OutputOversampling pulp::signal::drum::ClapVoice::output_oversampling ( ) const
inlineoverridevirtualnoexcept

Output quality at the generic voice boundary.

Kits use this surface to keep every registered path on one latency contract.

Reimplemented from pulp::signal::drum::Voice.

◆ output_stage() [1/2]

OutputStage * pulp::signal::drum::ClapVoice::output_stage ( )
inlineoverridevirtualnoexcept

The terminal saturation and degradation stage, at the generic voice boundary.

A registry consumer reaches it without recovering the concrete voice type, so adding an engine cannot desynchronise a downcast from the engine it was selected for. A voice that ends without one returns nullptr.

Reimplemented from pulp::signal::drum::Voice.

◆ output_stage() [2/2]

const OutputStage * pulp::signal::drum::Voice::output_stage ( ) const
inlinenoexceptinherited

◆ prepare()

void pulp::signal::drum::Voice::prepare ( double sample_rate)
inlineinherited

Fixes the sample rate and clears all state.

The only method a derived voice may allocate in.

◆ process()

void pulp::signal::drum::Voice::process ( float * out,
int num_samples )
inlineinherited

Adds num_samples of this voice's output into out.

◆ process_stereo()

void pulp::signal::drum::Voice::process_stereo ( float * left,
float * right,
int num_samples )
inlineinherited

Adds a stereo rendering to left and right.

Voices that do not provide a stereo realization are placed in the centre with half their mono signal in each channel, so summing the two channels reproduces process() exactly. A stereo-capable voice may override render_add_stereo, but the shared choke fade remains here.

◆ render_add()

void pulp::signal::drum::ClapVoice::render_add ( float * out,
int num_samples )
inlineoverrideprotectedvirtual

Adds the voice's output into out. Must add, never assign.

Implements pulp::signal::drum::Voice.

◆ render_add_stereo()

void pulp::signal::drum::ClapVoice::render_add_stereo ( float * left,
float * right,
int num_samples )
inlineoverrideprotectedvirtual

Optional stereo realization.

The default is centre-panned and preserves exact mono-sum equivalence.

Reimplemented from pulp::signal::drum::Voice.

◆ reset()

void pulp::signal::drum::Voice::reset ( )
inlineinherited

Silences the voice immediately, without a fade.

For transport stops and buffer-size changes, where a click cannot be heard because nothing is playing either side of it.

◆ sample_rate()

double pulp::signal::drum::Voice::sample_rate ( ) const
inlineinherited

◆ set_alternate_polarity()

void pulp::signal::drum::ClapVoice::set_alternate_polarity ( bool alternate)
inline

Invert every other burst.

A cheaper decorrelation than jitter and free of any timing change: opposite-signed bursts cannot reinforce each other's comb even at exactly even spacing.

◆ set_body_hz()

void pulp::signal::drum::ClapVoice::set_body_hz ( double hz)
inline

◆ set_body_level()

void pulp::signal::drum::ClapVoice::set_body_level ( double level)
inline

Level of an optional sine under the train, at set_body_hz.

Some hardware claps carry one; it gives the voice a pitch centre and helps it sit in a mix that is otherwise busy in the clap's band.

◆ set_burst_count()

void pulp::signal::drum::ClapVoice::set_burst_count ( int count)
inline

How many bursts the train contains.

◆ set_burst_decay_ms()

void pulp::signal::drum::ClapVoice::set_burst_decay_ms ( double ms)
inline

How quickly each burst decays.

◆ set_burst_falloff()

void pulp::signal::drum::ClapVoice::set_burst_falloff ( double ratio)
inline

How much quieter each burst is than the one before it, as a ratio.

The hands lose energy each time they meet, and a train at constant level reads as a machine rather than a person.

◆ set_burst_spacing_ms()

void pulp::signal::drum::ClapVoice::set_burst_spacing_ms ( double ms)
inline

Milliseconds between bursts.

◆ set_cutoff_hz()

void pulp::signal::drum::ClapVoice::set_cutoff_hz ( double hz)
inline

Centre and resonance of the bandpass the noise is heard through.

A clap occupies a narrow, quite high band; without the filter the voice is simply noise bursts.

◆ set_gap_jitter()

void pulp::signal::drum::ClapVoice::set_gap_jitter ( double amount)
inline

How much each gap varies from the nominal spacing, 0 to 1.

Perfectly even bursts comb against each other and give the train a pitch; hands are never that regular anyway. Driven by a fixed sequence, so this adds irregularity without costing reproducibility.

◆ set_noise_color()

void pulp::signal::drum::ClapVoice::set_noise_color ( NoiseColor color)
inline

◆ set_output_oversampling()

void pulp::signal::drum::ClapVoice::set_output_oversampling ( OutputOversampling factor)
inlineoverridevirtual

Reimplemented from pulp::signal::drum::Voice.

◆ set_resonance()

void pulp::signal::drum::ClapVoice::set_resonance ( double q)
inline

◆ set_stereo_width()

void pulp::signal::drum::ClapVoice::set_stereo_width ( double width)
inline

Alternating burst width, 0 for mono through 1 for hard left/right.

The room tail and optional tonal body remain centred at every setting.

◆ set_tail_decay_ms()

void pulp::signal::drum::ClapVoice::set_tail_decay_ms ( double ms)
inline

◆ set_tail_level()

void pulp::signal::drum::ClapVoice::set_tail_level ( double level)
inline

Level and decay of the tail that fuses the train.

◆ set_velocity_response()

void pulp::signal::drum::Voice::set_velocity_response ( const VelocityResponse & r)
inlineinherited

◆ state()

VoiceState pulp::signal::drum::Voice::state ( ) const
inlineinherited

◆ velocity()

float pulp::signal::drum::Voice::velocity ( ) const
inlineinherited

◆ velocity_response()

const VelocityResponse & pulp::signal::drum::Voice::velocity_response ( ) const
inlineinherited

Member Data Documentation

◆ max_bursts

int pulp::signal::drum::ClapVoice::max_bursts = 8
staticconstexpr

Upper bound on the burst train.

Beyond about eight the train stops reading as a clap and starts reading as a roll.


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