Getting started
Bonsai.Mixer provides low-latency, multi-channel audio playback over PortAudio. It plays audio as one-shot sounds or as long-lived sources that can loop, pause, stop, and move across the speakers while they play. This guide covers how the package fits together and walks through playing a sound.
Overview
The package is organized around three core concepts:
- The mixer context is an output stream on a device.
CreateMixerContextopens it andStartMixerstarts its real-time audio callback. The device, sample rate, channel count, and latency are chosen at creation, and the stream reports the actual values it opened with. - Audio buffers are the audio content, held as
Matarrays of 32-bit floating-point samples with one row per output channel, or a single row for a mono sound that the mixer broadcasts across the channels. They are generated or loaded with the usualBonsai.Dspoperators, off the audio thread. - Sources are the addressable voices that play buffers.
CreateSourceemits a handle for appending buffers withAppendBuffer, setting the gain withSetGain, and looping, pausing, or stopping playback.
PlayBuffer skips the handle entirely, playing a buffer directly on the mixer as a one-shot source managed internally.
The real-time audio callback only sums the active sources and applies gain, leaving all synthesis and processing to the upstream workflow. See how the mixer works for what this means for latency and logging.
Playing a sound
Below is a small workflow to open a mixer, start it, and play a single buffer.
CreateMixerContextopens the output stream. Left at its defaults it uses the default device and its maximum channel count.StartMixerbegins requesting audio from the device.- Publishing the started context in a
BehaviorSubjectnamedMixerlets every downstream branch reach the same stream. - A
Bonsai.Dspgenerator produces a buffer ofF32samples, whichPlayBufferplays once on the mixer.
Tip
Derive the sample rate from the mixer context rather than hardcoding it. Map SampleRate from the context onto the generator with a MemberSelector and a PropertyMapping so the generated buffer always matches the open stream.
Where to go next
- Audio sources: create controllable sources, loop them, and append buffers over time.
- Playback control: play, pause, and stop sources, and observe their state.
- Gain control: set volume and position a source across the output channels.
- How the mixer works: the audio callback model, buffer format, and what to keep off the audio thread.
Acknowledgments
Development of this package was supported by funding from the Coen Lab at University College London.