Expand description
A real-time mixer for games. Requires the mixer feature.
Mixer::new returns two halves. The Mixer goes to the audio callback, which
calls Mixer::render for every buffer. The MixerHandle stays with the game,
which starts voices, changes gains and pans, and stops them.
use audiobox::mixer::{Fade, Loop, Mixer, MixerConfig, Play};
use audiobox::Audio;
use std::sync::Arc;
let (mut mixer, mut handle) = Mixer::new(MixerConfig {
buses: vec!["music".into(), "effects".into()],
..MixerConfig::default()
})?;
let music = handle.bus("music").unwrap();
let effects = handle.bus("effects").unwrap();
let beep = Arc::new(Audio::new(vec![vec![0.25; 4800]], 48_000)?);
handle.play(beep.clone(), &Play { bus: effects, pan: -0.5, ..Play::default() })?;
handle.play(beep, &Play { bus: music, looping: Loop::Whole, fade_in: Fade::linear(0.5), ..Play::default() })?;
handle.set_bus_gain(music, 0.5, Fade::linear(1.0))?;
// In the audio callback: interleaved stereo at 48 kHz.
let mut buffer = [0.0f32; 2 * 512];
mixer.render(&mut buffer);§Sounds
A voice plays a Sound: decoded Audio shared through an Arc, so that
many voices play one sound without copying it, or a Stream that produces
frames as it plays, such as a Decoder of compressed
music or a Synth rendering a score. Sounds are mono or stereo.
Each voice has a gain, a pan, a bus, a priority, an optional fade-in, and a loop:
off, the whole sound, or a region between two frames. Gain, pan and bus gain
changes, and stops, can fade over a duration with a FadeCurve.
A voice also has a playback rate, which changes speed and pitch together, and a
pitch offset in semitones on top of it. Both can change while the voice plays, with
a ramp. Variation draws a random pitch and gain for each start of a repeated
sound, such as a footstep, from a generator seeded by MixerConfig::seed.
A voice can start partway through its sound (Play::start), and be paused and
resumed, optionally with a fade; it keeps its position, its fades and its loop.
Pausing a bus pauses every voice routed through it and no others, so a pause menu
can stop the game’s sounds and keep its own. MixerHandle::voice_status reads a
voice’s state and position as of the last render, without blocking the audio side. A loop of a
stream seeks it back, so a stream that loops must support seeking to the loop start.
§Voices and buses
By default at most MixerConfig::max_voices voices play at once. When a voice starts while
that many play, it takes the place of the playing voice with the lowest priority,
the oldest among equals, if that priority is not higher than its own. The voice it
replaces fades out over 5 ms and reports MixerEvent::Stolen. Otherwise the new
voice does not play and reports MixerEvent::Rejected. Give music a high
priority so that effects never take its place.
Opt into MixerConfig::virtual_voices to retain up to 4096 logical sources
while selecting only max_voices physical voices. Quiet, distant and lower-ranked
voices advance their clocks as VoiceState::Virtual. Memory sources skip PCM
and rebuild history on promotion; stateful streams still consume/discard PCM.
Selection uses priority, estimated source-peak level and start order at fixed
32-frame boundaries and command frames. Virtual/paused voices count against
logical and instance capacity. Physical stop fades have eight extra budget slots.
A sound can also limit its own voices with Instances: at most so many at once,
with a policy for one more, and a minimum gap between starts. A refused start
reports MixerEvent::Limited.
A voice can have a 2D position relative to the listener (Play::position,
MixerHandle::set_position), which sets its pan and a distance gain through the
mixer’s Space2d.
Every voice plays through a bus: the master bus, or one of the named buses of
MixerConfig::buses, which by default play through the master. BusRouting
and MixerHandle::set_routing opt into nested groups and shared pre/post-fader
BusSend routes, with stereo bus balance and explicit mute/solo path rules.
A voice’s samples are scaled
by its gain, its fades, its pan, its bus’s gain and the master gain.
effects adds ordered bus chains, ramped filters, compression/ducking, delay
and reverb. Sidechain dependencies order named buses before master processing.
Many voices together can go beyond full scale. MixerConfig::limiter enables a
MasterLimiter on the master bus, off by default, which keeps the output at or
below its ceiling and passes quieter signals unchanged. Its look-ahead, 0 by
default, delays the output by MixerHandle::latency frames.
§Rendering
Mixer::render fills an interleaved buffer of the output’s channels (1/2/4/6/8) at
the output’s sample rate. It writes out.len() / channels whole frames and sets any
remaining samples to 0; a buffer shorter than a frame renders nothing, but still
applies the changes that are due.
Sources at another sample rate, and voices whose rate or pitch differs from 1, are resampled with a 16-tap windowed-sinc filter (Blackman window, 256 interpolated phases, cutoff at 0.9 of the lower Nyquist frequency). It is designed for ratios up to 2:1, such as 44.1 kHz to 48 kHz; larger downsampling ratios alias more. A source at the output rate is copied sample for sample.
Play::resampling can explicitly select ResamplingQuality::Linear, cheaper
two-point interpolation without an anti-alias filter. Sinc remains the default.
Panning a mono source follows a constant-power law: cos θ on the left and
sin θ on the right, with θ = (pan + 1)·π/4, so the centre is -3 dB on each side.
A stereo source is balanced: the centre leaves it unchanged and the far side
follows √2·cos θ or √2·sin θ, limited to 1. A mono output sums mono sources and
averages the two channels of stereo ones.
§Real-time safety
Mixer::render allocates nothing, takes no lock that can wait and does not block.
Changes reach it through a bounded single-producer, single-consumer queue of the
crate’s own, allocated when the mixer is created. The handle and the mixer each own
one end and one counter, so a slot is only ever used by one side at a time; each slot
is taken with try_lock, which never blocks and, under this protocol, is never
contended. A full queue is reported to the handle; neither side ever waits. Voices
and their buffers are built by the handle, on the game’s thread. Finished voices go
back to the handle through a second such queue and are freed by
MixerHandle::poll_event, so the audio thread frees no memory either. Poll events
regularly, such as once per game frame.
§Timing and determinism
Every change applies at an output frame. MixerHandle::at schedules changes at an
exact frame, counted from the first rendered frame; they apply there whatever the
buffer sizes, splitting a buffer if needed. Changes sent without a frame apply at the
start of the next render. The same changes at the same frames give the same samples
on every platform: resampling, panning and fades use only basic IEEE arithmetic and
the crate’s own sine series.
Re-exports§
pub use spatial::Attenuation;pub use spatial::DistanceModel;pub use spatial::Emitter;pub use spatial::Listener;pub use spatial::OutputLayout;pub use spatial::Placement;pub use spatial::SpatialConfig;
Modules§
- effects
- Prepared bus effect chains. All times and parameter ramps are sample based.
- events
- Named sound events, parsed and prepared on the control thread (
eventsfeature). - music
- Music that follows a game: transitions, cues and intensity layers. Requires
music. - spatial
- Point-source 3D placement, horizontal speaker layouts and an explicit stereo fold. Coordinates are right-handed: +X right, +Y up, default forward -Z. Positions and distances use the same units; velocities and sound speed use units/second. Velocity controls Doppler only: the host supplies updated positions explicitly.
Structs§
- BusId
- A bus:
BusId::MASTERor a named bus fromMixerHandle::bus. - BusRouting
- One named bus’s complete routing/settings. Omitted buses retain one unity post-fader output to master. The master is a sink, configured through its existing gain/pause/effect APIs, and cannot appear as a source here.
- BusSend
- Commands
- Commands applied at one moment: see
MixerHandle::nowandMixerHandle::at. - Fade
- A change over a duration, with a curve. Zero seconds changes at once.
- Instances
- Limits for one sound: at most
maxvoices with the same key play at once, and a new one starts no sooner thanmin_gapseconds after the last, so that ten coins collected together do not sum into distortion. - Master
Limiter - Settings of the master bus’s limiter, enabled with
MixerConfig::limiter. - Mixer
- The audio thread’s half of the mixer. See the module documentation.
- Mixer
Config - Mixer
Handle - The game’s half of the mixer: starts, changes and stops voices.
- Play
- How a voice starts playing.
- Routing
Id - A successfully queued edit ID. Poll RoutingApplied/Rejected for its outcome.
- Space2d
- How a 2D position relative to the listener becomes a pan and a gain.
- Variation
- Random variation for sounds that repeat, such as footsteps, coins and impacts.
- Virtual
Voices - Opt-in logical voice pool.
MixerConfig::max_voicesremains the physical budget. - VoiceId
- Identifies a voice in commands and events. Unique for the life of a mixer.
- Voice
Status - A voice’s state and its position in its sound, in source frames. A looping voice’s position wraps back with the loop.
Enums§
- Distance
- How gain falls with distance in a
Space2d. - Loop
- Which part of a sound repeats.
- Mixer
Event - Something that happened to a voice, reported by
MixerHandle::poll_event. - Over
Limit - What happens when a sound already plays its
Instances::maxvoices. - Resampling
Quality - Per-voice interpolation quality. The default retains the original PCM/filter.
- Send
Position - Both taps are after inserts and the bus pause fade. Pre-fader excludes bus gain/pan; post-fader includes them. Mute/solo gate both taps and sidechain keys.
- Sound
- What a voice plays.
- Voice
State - What a voice is doing, as of the mixer’s last render.
Constants§
- MAX_
BUS_ ROUTES - Total main outputs plus sends in one graph, including omitted default outputs.
- MAX_
LOGICAL_ VOICES - Maximum retained logical voices, excluding the existing bounded fade-out slots.
- VIRTUAL_
VOICE_ QUANTUM - Fixed global output-frame cadence for physical selection, plus command frames.
Traits§
- Stream
- A source of interleaved frames that a voice plays as it goes.