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:
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:
init_chorus(sched: Scheduler)

Initialize the scheduler’s shared chorus unit with default parameters (no-op if already initialized).

Arguments:
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:

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:
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: