17.8. Voice allocation, effect bus routing, and per-tick mixing
Module strudel_scheduler
17.8.1. Structures
- Voice
- Fields:
samples : array<float> - Interleaved stereo PCM buffer (raw, without gain/pan applied).
position : int = 0 - Current read position in floats (not frames); negative values delay playback start.
cut : int = 0 - Cut group — new voices in the same group kill older ones (0 = no cut).
gain : float = 0.8f - Linear gain applied during mixing.
pan : float = 0f - Stereo pan (-1 = left, 0 = center, 1 = right).
reverb_send : float = 0f - Reverb send amount (0.0–1.0) from Event.room.
chorus_send : float = 0f - Chorus send amount (0.0–1.0) from Event.chorus.
delay_send : float = 0f - Delay send amount (0.0–1.0) from Event.delay_amount.
orbit : int = 0 - Orbit index — selects which per-orbit effect bus receives this voice’s sends.
- StrudelSF2Meta
- Fields:
note : int = 0 - MIDI note number (used for re-trigger matching).
note_off_sample : int = -1 - Sample index at which to fire note-off (-1 = never auto note-off).
samples_elapsed : int = 0 - Total samples rendered for this voice so far.
reverb_send : float = 0f - Per-voice reverb send (from SF2 generators).
chorus_send : float = 0f - Per-voice chorus send (from SF2 generators).
delay_send : float = 0f - Per-voice delay send (from Event.delay_amount).
exclusive_class : int = 0 - SF2 exclusive class — voices in the same non-zero class choke each other (e.g. hi-hats).
cut : int = 0 - Strudel cut group (0 = no cut).
gain : float = 1f - Event gain × velocity, applied as an attenuation scale factor.
orbit : int = 0 - Orbit index — selects which per-orbit effect bus receives this voice’s sends.
fx : VoiceFX - Per-voice audio effects (crush/shape/filter/etc.), applied post-render.
pan : float = 0f - Stereo pan (-1..1), used when FX routing goes through a temp buffer.
- OrbitBus
- Fields:
reverb : ConvolutionReverb? - Convolution reverb instance (null until a voice requests reverb).
delay_proc : ma_delay? - Stereo delay instance (null until a voice requests delay).
reverb_send_buf : array<float> - Scratch buffer accumulating reverb sends from all voices routed to this orbit.
reverb_out_buf : array<float> - Scratch buffer receiving the reverb’s wet output for mixing into the master.
delay_send_buf : array<float> - Scratch buffer accumulating delay sends from all voices routed to this orbit.
delay_out_buf : array<float> - Scratch buffer receiving the delay’s wet output for mixing into the master.
current_roomsize : float = -1f - Most recently applied reverb roomsize (-1 = uninitialized).
current_delaytime : float = -1f - Most recently applied delay time in seconds (-1 = uninitialized).
current_delayfeedback : float = -1f - Most recently applied delay feedback amount (-1 = uninitialized).
- Scheduler
- Fields:
cps : double = 0.5lf - Cycles per second (0.5 = 120 BPM at 4 beats per cycle).
startTime : double = 0lf - Wall-clock time when playback started (seconds).
lastQueryEnd : double = 0lf - Cycle position of the last pattern-query end, used to avoid duplicate spawning.
voices : array< Voice?> - Pool of pre-rendered sample voices.
osc_voices : array< OscVoice> - Pool of streaming oscillator voices.
mixer : ma_volume_mixer - Miniaudio volume mixer, reused across ticks for gain/pan application.
mixer_ready : bool = false - True once the mixer has been initialized.
output : array<float> - Reusable stereo output buffer for the current tick.
sf2 : SF2File? - Loaded SoundFont (null = SF2 disabled for this scheduler).
sf2_voices : array< ma_sf2_voice> - Pool of real-time SF2 voices (C structs).
sf2_meta : array< StrudelSF2Meta> - Parallel metadata array for each SF2 voice.
orbit_buses : array< OrbitBus?> - Per-orbit effect buses, indexed by orbit number and allocated on demand.
chorus : ma_chorus? - Shared chorus unit (null until any voice requests chorus).
chorus_send_buf : array<float> - Chorus send accumulation buffer shared across orbits.
chorus_out_buf : array<float> - Chorus wet-output buffer mixed into the master.
voice_fx_buf : array<float> - Scratch buffer for per-voice FX processing, sized on demand each tick.
17.8.2. Orbit effects
- get_orbit_delay(sched: Scheduler; orbit: int = 0): ma_delay?
Fetch the delay instance for the given orbit (for inspection or tests). Returns null if no bus or no delay configured.
- Arguments:
sched : Scheduler
orbit : int
- get_orbit_reverb(sched: Scheduler; orbit: int = 0): ConvolutionReverb?
Fetch the reverb instance for the given orbit (for inspection or tests). Returns null if no bus or no reverb configured.
- Arguments:
sched : Scheduler
orbit : int
- init_chorus(sched: Scheduler)
Initialize the scheduler’s shared chorus unit with default parameters (no-op if already initialized).
- Arguments:
sched : Scheduler
- init_delay(sched: Scheduler; delaytime: float = 0.5f; delayfeedback: float = 0.5f)
Initialize delay on the scheduler’s default orbit (bus 0) with the given time/feedback.
- Arguments:
sched : Scheduler
delaytime : float
delayfeedback : float
- init_reverb(sched: Scheduler)
Initialize reverb on the scheduler’s default orbit (bus 0). Convenience wrapper used by older API.
- Arguments:
sched : Scheduler
17.8.3. Scheduler lifecycle
- shutdown_scheduler(sched: Scheduler)
Release native resources owned by the scheduler (reverb/delay/chorus instances on every orbit bus).
- Arguments:
sched : Scheduler
- tick(sched: Scheduler; pat: Pattern; bank: SampleBank; wall_time: double; chunk_seconds: float = 0.05f; lookAhead: float = 0.1f)
Advance one audio block: query the pattern for new events, spawn voices, mix all voices through the orbit/chorus buses into sched.output. chunk_seconds controls how much audio is produced this tick; lookAhead is how far ahead in time to query for new events.
- Arguments:
sched : Scheduler
pat : Pattern
bank : SampleBank
wall_time : double
chunk_seconds : float
lookAhead : float