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

Polyphonic synth that routes plain-MIDI events into a pool of Voice instances. More...

#include <synthesiser.hpp>

Public Member Functions

 Synthesiser (std::size_t polyphony=16)
 Construct with a fixed polyphony.
void set_steal_strategy (VoiceStealStrategy s)
VoiceStealStrategy steal_strategy () const
void set_pitch_bend_range_semitones (float r)
 Pitch-bend range applied to channel-level pitch-bend messages.
float pitch_bend_range_semitones () const
void note_on (uint8_t channel, uint8_t note, uint8_t velocity, int8_t priority=0, uint8_t voice_group=0, bool choke_group=false, float choke_fade_ms=0.0f)
 Direct event entry points — usable when the caller wants to build a Synthesiser pipeline without a full MidiBuffer.
void note_off (uint8_t channel, uint8_t note)
void pitch_bend (uint8_t channel, float bend_semitones)
void aftertouch (uint8_t channel, float pressure)
void cc (uint8_t channel, uint8_t cc_number, uint8_t value)
void process (const MidiBuffer &events, float *out, int num_samples)
 Drive the synth across one audio block.
void process (const MidiBuffer &events, float *out, int num_samples, const SynthesiserNoteOnPolicy &note_on_policy)
 Drive the synth with constant metadata applied to every note-on in the buffer.
template<typename PolicyFn>
requires std::is_invocable_r_v<SynthesiserNoteOnPolicy, PolicyFn&, uint8_t, uint8_t, uint8_t>
void process (const MidiBuffer &events, float *out, int num_samples, PolicyFn &&policy_for_note)
 Drive the synth resolving note-on metadata per note rather than once per buffer.
std::size_t polyphony () const
Voice & voice (std::size_t i)
const Voice & voice (std::size_t i) const
std::size_t active_count () const
std::size_t releasing_count () const
std::uint64_t steal_count () const
void reset_steal_count ()
SynthesiserTelemetry telemetry () const
 Cheap owner-thread snapshot for voice-count telemetry.
std::uint64_t estimate_optional_runtime_cost () const
SynthesiserRuntimeBudgetReport evaluate_optional_runtime_budget (runtime::RuntimeBudgetFrame &frame, runtime::RuntimeWorkLane lane=runtime::RuntimeWorkLane::Background, bool required=false) const
void panic (bool immediate)
 Silence every voice.
void reset ()

Detailed Description

template<typename Voice>
class pulp::midi::Synthesiser< Voice >

Polyphonic synth that routes plain-MIDI events into a pool of Voice instances.

Voice must derive from SynthesiserVoice.

Constructor & Destructor Documentation

◆ Synthesiser()

template<typename Voice>
pulp::midi::Synthesiser< Voice >::Synthesiser ( std::size_t polyphony = 16)
inlineexplicit

Construct with a fixed polyphony.

Voices are default-constructed.

Member Function Documentation

◆ active_count()

template<typename Voice>
std::size_t pulp::midi::Synthesiser< Voice >::active_count ( ) const
inline

◆ aftertouch()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::aftertouch ( uint8_t channel,
float pressure )
inline

◆ cc()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::cc ( uint8_t channel,
uint8_t cc_number,
uint8_t value )
inline

◆ estimate_optional_runtime_cost()

template<typename Voice>
std::uint64_t pulp::midi::Synthesiser< Voice >::estimate_optional_runtime_cost ( ) const
inline

◆ evaluate_optional_runtime_budget()

template<typename Voice>
SynthesiserRuntimeBudgetReport pulp::midi::Synthesiser< Voice >::evaluate_optional_runtime_budget ( runtime::RuntimeBudgetFrame & frame,
runtime::RuntimeWorkLane lane = runtime::RuntimeWorkLane::Background,
bool required = false ) const
inline

◆ note_off()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::note_off ( uint8_t channel,
uint8_t note )
inline

◆ note_on()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::note_on ( uint8_t channel,
uint8_t note,
uint8_t velocity,
int8_t priority = 0,
uint8_t voice_group = 0,
bool choke_group = false,
float choke_fade_ms = 0.0f )
inline

Direct event entry points — usable when the caller wants to build a Synthesiser pipeline without a full MidiBuffer.

◆ panic()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::panic ( bool immediate)
inline

Silence every voice.

immediate == true is the All Sound Off semantic: each voice is hard-reset, so release tails stop at once. false is the All Notes Off semantic: sustain and sostenuto holds are dropped and every sounding voice enters its normal release, so tails ring out.

◆ pitch_bend()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::pitch_bend ( uint8_t channel,
float bend_semitones )
inline

◆ pitch_bend_range_semitones()

template<typename Voice>
float pulp::midi::Synthesiser< Voice >::pitch_bend_range_semitones ( ) const
inline

◆ polyphony()

template<typename Voice>
std::size_t pulp::midi::Synthesiser< Voice >::polyphony ( ) const
inline

◆ process() [1/3]

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::process ( const MidiBuffer & events,
float * out,
int num_samples )
inline

Drive the synth across one audio block.

Events are dispatched at their sample offsets within the block; voices render the sub-segments between events. The output buffer is NOT zeroed — voices render additively, so the caller must clear it (or pass a buffer that already holds the desired pre-mix).

◆ process() [2/3]

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::process ( const MidiBuffer & events,
float * out,
int num_samples,
const SynthesiserNoteOnPolicy & note_on_policy )
inline

Drive the synth with constant metadata applied to every note-on in the buffer.

Event offsets and all non-note messages retain normal behavior.

◆ process() [3/3]

template<typename Voice>
template<typename PolicyFn>
requires std::is_invocable_r_v<SynthesiserNoteOnPolicy, PolicyFn&, uint8_t, uint8_t, uint8_t>
void pulp::midi::Synthesiser< Voice >::process ( const MidiBuffer & events,
float * out,
int num_samples,
PolicyFn && policy_for_note )
inline

Drive the synth resolving note-on metadata per note rather than once per buffer.

policy_for_note(channel, note, velocity) returns the policy for that note-on.

One instrument holding several sounds — a drum kit, where each note is a different drum — needs policies that differ within a single block: a closed hat chokes the open hat on trigger while the kick beside it in the same block must not, and each pad retriggering itself is a distinct group. A per-buffer policy cannot express that.

The callback runs on the audio thread inside the event loop, so it must not allocate, lock, or block. It is a template parameter rather than a std::function precisely so the call inlines and never heap-allocates.

◆ releasing_count()

template<typename Voice>
std::size_t pulp::midi::Synthesiser< Voice >::releasing_count ( ) const
inline

◆ reset()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::reset ( )
inline

◆ reset_steal_count()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::reset_steal_count ( )
inline

◆ set_pitch_bend_range_semitones()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::set_pitch_bend_range_semitones ( float r)
inline

Pitch-bend range applied to channel-level pitch-bend messages.

Default is ±2 semitones (MIDI 1.0 RPN 0 default). Override with set_pitch_bend_range_semitones to match the host's expected range (typically ±2, ±12, or ±24).

◆ set_steal_strategy()

template<typename Voice>
void pulp::midi::Synthesiser< Voice >::set_steal_strategy ( VoiceStealStrategy s)
inline

◆ steal_count()

template<typename Voice>
std::uint64_t pulp::midi::Synthesiser< Voice >::steal_count ( ) const
inline

◆ steal_strategy()

template<typename Voice>
VoiceStealStrategy pulp::midi::Synthesiser< Voice >::steal_strategy ( ) const
inline

◆ telemetry()

template<typename Voice>
SynthesiserTelemetry pulp::midi::Synthesiser< Voice >::telemetry ( ) const
inline

Cheap owner-thread snapshot for voice-count telemetry.

Call from the synth owner (normally the audio thread) and publish the returned value through a lock-free latest-value channel if another thread needs to observe it.

◆ voice() [1/2]

template<typename Voice>
Voice & pulp::midi::Synthesiser< Voice >::voice ( std::size_t i)
inline

◆ voice() [2/2]

template<typename Voice>
const Voice & pulp::midi::Synthesiser< Voice >::voice ( std::size_t i) const
inline

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