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

A tom, and the analogue electronic-drum voice it generalises. More...

#include <tom.hpp>

Classes

struct  PresetData

Public Types

enum class  LadderMathProfile : std::uint8_t { reference , realtime_efficient }
 The noise ladder's saturator, chosen per voice. More...
enum class  Wave { triangle , sine }
 Body waveform. More...
enum class  Preset {
  generic_tom , low_tom , mid_tom , hi_tom ,
  bass , snary , zap , cosmic
}

Public Member Functions

 TomVoice ()
void set_tune_hz (double hz)
 Pitch the body settles at, in Hz.
void set_bend_octaves (double octaves)
 Depth of the downward dive in octaves, and how quickly it lands.
void set_bend_ms (double ms)
void set_decay_ms (double ms)
 How long the note rings, as a T60. Unrelated to the bend.
void set_wave (Wave wave)
void set_noise_balance (double amount)
 Balance between the oscillator (0) and the filtered noise (1).
void set_noise_cutoff_hz (double hz)
 Corner and resonance of the four-pole lowpass the noise runs through.
void set_noise_resonance (double amount)
void set_noise_color (NoiseColor color)
bool set_ladder_math_profile (LadderMathProfile profile) noexcept
 Selects the noise ladder's saturation curve between hits.
LadderMathProfile ladder_math_profile () const noexcept
void set_click_level (double level)
 The beater.
void set_click_cutoff_hz (double hz)
void set_click_decay_ms (double ms)
void apply_preset (Preset preset)
LofiChain & body_lofi ()
 Independent degradation for the two halves of the drum.
const LofiChain & body_lofi () const
LofiChain & noise_lofi ()
const LofiChain & noise_lofi () const
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 std::array< PresetData, 8 > presets
 Original Pulp-authored voicings of this one SDS-V-family topology.

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.
virtual void render_add_stereo (float *left, float *right, int num_samples)
 Optional stereo realization.

Detailed Description

A tom, and the analogue electronic-drum voice it generalises.

The defining property is that the pitch envelope and the amplitude envelope are decoupled. In most percussion voices the body's pitch and its level fall together, because one envelope drives both; here they are separate controls, so the pitch can finish its dive in a few tens of milliseconds while the note rings on for a second afterwards. That is the sound of the early electronic drum kits: a fast downward swoop that arrives at a pitch and then simply sustains there. Tying the two envelopes together cannot produce it – the swoop would take the level with it.

The generic tom and the electronic voice are the same topology, retuned. A short bend and a mostly-noise balance is an acoustic-sounding tom; a deep bend and a pure oscillator is the laser-like electronic voice; a long decay with a high tuning is the "cosmic" end. Presets differ only in numbers, so there is one implementation rather than one per named sound.

Velocity deepens the bend rather than only raising the level, which is the physical claim: a harder strike deflects the head further, so the pitch starts higher and falls through a wider range. The voice's default VelocityResponse enables this, and it is the clearest single example of the velocity-to-timbre contract in the whole percussion set.

The noise path runs through a four-pole resonant lowpass rather than the two-pole used elsewhere, because at high resonance a steeper filter rings enough to give the noise a pitch of its own – which is what lets the same voice cover a snare-like sound without a second oscillator.

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

Member Enumeration Documentation

◆ LadderMathProfile

enum class pulp::signal::drum::TomVoice::LadderMathProfile : std::uint8_t
strong

The noise ladder's saturator, chosen per voice.

Each value runs the LadderSaturation of the same meaning explicitly, so the voice does not follow the build-time kDefaultLadderSaturation: reference is LadderSaturation::exact (std::tanh) and realtime_efficient is LadderSaturation::realtime_efficient (FastMath::tanh_minimax).

Enumerator
reference 
realtime_efficient 

◆ Preset

Enumerator
generic_tom 
low_tom 
mid_tom 
hi_tom 
bass 
snary 
zap 
cosmic 

◆ Wave

Body waveform.

Triangle is the authentic choice for the analogue electronic voices – their oscillators were triangle cores – and it carries odd harmonics that survive a small speaker where a sine does not.

Enumerator
triangle 
sine 

Constructor & Destructor Documentation

◆ TomVoice()

pulp::signal::drum::TomVoice::TomVoice ( )
inline

Member Function Documentation

◆ apply_preset()

void pulp::signal::drum::TomVoice::apply_preset ( Preset preset)
inline

◆ body_lofi() [1/2]

LofiChain & pulp::signal::drum::TomVoice::body_lofi ( )
inline

Independent degradation for the two halves of the drum.

A tom is an oscillator body under a filtered noise skin, and the machines this voice descends from crushed those paths separately – a bit-reduced body under clean hiss reads as a different instrument from a clean body under a decimated skin. One shared chain could only ever produce the average of the two.

◆ body_lofi() [2/2]

const LofiChain & pulp::signal::drum::TomVoice::body_lofi ( ) const
inline

◆ 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.

◆ ladder_math_profile()

LadderMathProfile pulp::signal::drum::TomVoice::ladder_math_profile ( ) const
inlinenoexcept

◆ latency_samples()

int pulp::signal::drum::TomVoice::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.

◆ noise_lofi() [1/2]

LofiChain & pulp::signal::drum::TomVoice::noise_lofi ( )
inline

◆ noise_lofi() [2/2]

const LofiChain & pulp::signal::drum::TomVoice::noise_lofi ( ) const
inline

◆ 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::TomVoice::on_is_active ( ) const
inlineoverrideprotectedvirtual

◆ on_note_on()

void pulp::signal::drum::TomVoice::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::TomVoice::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::TomVoice::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::TomVoice::output ( )
inline

◆ output() [2/2]

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

◆ output_oversampling()

OutputOversampling pulp::signal::drum::TomVoice::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::TomVoice::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::TomVoice::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()

virtual void pulp::signal::drum::Voice::render_add_stereo ( float * left,
float * right,
int num_samples )
inlineprotectedvirtualinherited

Optional stereo realization.

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

Reimplemented in pulp::signal::drum::ClapVoice.

◆ 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_bend_ms()

void pulp::signal::drum::TomVoice::set_bend_ms ( double ms)
inline

◆ set_bend_octaves()

void pulp::signal::drum::TomVoice::set_bend_octaves ( double octaves)
inline

Depth of the downward dive in octaves, and how quickly it lands.

This envelope is independent of the amplitude decay below – that separation is the whole point of the voice.

◆ set_click_cutoff_hz()

void pulp::signal::drum::TomVoice::set_click_cutoff_hz ( double hz)
inline

◆ set_click_decay_ms()

void pulp::signal::drum::TomVoice::set_click_decay_ms ( double ms)
inline

◆ set_click_level()

void pulp::signal::drum::TomVoice::set_click_level ( double level)
inline

The beater.

Short and highpassed: a tom's attack is the stick, not the head.

◆ set_decay_ms()

void pulp::signal::drum::TomVoice::set_decay_ms ( double ms)
inline

How long the note rings, as a T60. Unrelated to the bend.

◆ set_ladder_math_profile()

bool pulp::signal::drum::TomVoice::set_ladder_math_profile ( LadderMathProfile profile)
inlinenoexcept

Selects the noise ladder's saturation curve between hits.

Reference is the default; realtime_efficient uses the bounded FastMath::tanh_minimax.

◆ set_noise_balance()

void pulp::signal::drum::TomVoice::set_noise_balance ( double amount)
inline

Balance between the oscillator (0) and the filtered noise (1).

◆ set_noise_color()

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

◆ set_noise_cutoff_hz()

void pulp::signal::drum::TomVoice::set_noise_cutoff_hz ( double hz)
inline

Corner and resonance of the four-pole lowpass the noise runs through.

At high resonance it rings, which gives the noise a pitch.

◆ set_noise_resonance()

void pulp::signal::drum::TomVoice::set_noise_resonance ( double amount)
inline

◆ set_output_oversampling()

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

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

◆ set_tune_hz()

void pulp::signal::drum::TomVoice::set_tune_hz ( double hz)
inline

Pitch the body settles at, in Hz.

◆ set_velocity_response()

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

◆ set_wave()

void pulp::signal::drum::TomVoice::set_wave ( Wave wave)
inline

◆ 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

◆ presets

std::array<PresetData, 8> pulp::signal::drum::TomVoice::presets
staticconstexpr
Initial value:
{{
{Preset::generic_tom, "Generic Tom", 130.0, 0.35, 30.0, 450.0,
Wave::triangle, 0.25, 2200.0, 0.25, 0.35},
{Preset::low_tom, "LowTom", 75.0, 0.80, 45.0, 700.0,
Wave::triangle, 0.08, 1100.0, 0.25, 0.30},
{Preset::mid_tom, "MidTom", 110.0, 0.90, 35.0, 550.0,
Wave::triangle, 0.10, 1600.0, 0.28, 0.32},
{Preset::hi_tom, "HiTom", 170.0, 1.00, 28.0, 400.0,
Wave::triangle, 0.12, 2400.0, 0.30, 0.35},
{Preset::bass, "Bass", 55.0, 0.55, 55.0, 1100.0,
Wave::sine, 0.04, 900.0, 0.18, 0.22},
{Preset::snary, "Snary", 155.0, 0.25, 18.0, 320.0,
Wave::triangle, 0.70, 2500.0, 0.82, 0.50},
{Preset::zap, "Zap", 210.0, 3.20, 55.0, 500.0,
Wave::triangle, 0.02, 3200.0, 0.20, 0.15},
{Preset::cosmic, "Cosmic", 280.0, 2.40, 180.0, 1800.0,
Wave::sine, 0.20, 6000.0, 0.70, 0.25},
}}
@ sine
Definition tom.hpp:65
@ triangle
Definition tom.hpp:65
@ mid_tom
Definition tom.hpp:70
@ generic_tom
Definition tom.hpp:68
@ low_tom
Definition tom.hpp:69

Original Pulp-authored voicings of this one SDS-V-family topology.

They are clean starting points, not values copied from a sample library or a commercial preset bank.


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