Mixing Busses
Learn how to use mixing buses for grouped audio control and routing
Overview
Mixing buses allow you to group and control multiple audio sources together. A mixing bus acts as a virtual audio mixer channel that enables:
- Group audio sources: Route multiple sounds through a single bus
- Collective volume control: Adjust the volume of all sounds on a bus with a single call
- Shared effects: Apply filters to all sounds routed through the bus
- Dynamic routing: Move live sounds between buses at runtime
Mixing buses are particularly useful for games and applications that need to manage different audio categories like music, SFX, voiceovers, and ambience independently.
1. Create a Mixing Bus
// Create a new mixing bus with an optional name
final sfxBus = SoLoud.instance.createMixingBus(name: 'SFX');
final musicBus = SoLoud.instance.createMixingBus(name: 'Music');
2. Play the Bus on the Engine
A bus must be "played" on the main engine before its output becomes audible:
// Play the bus on the engine (required!)
final busHandle = sfxBus.playOnEngine();
// You can also set initial volume and paused state
musicBus.playOnEngine(volume: 0.8, paused: false);
3. Play Sounds Through the Bus
// Load audio assets
final explosion = await SoLoud.instance.loadAsset('assets/explosion.mp3');
final backgroundMusic = await SoLoud.instance.loadAsset('assets/music.mp3');
// Play sounds through the bus...
await sfxBus.play(explosion);
await musicBus.play(backgroundMusic, looping: true);
// ...or play it with the usual `play()` method
await SoLoud.instance.play(explosion, busId: sfxBus.busId);
4. Control the Bus
// Adjust volume for all sounds on the bus
SoLoud.instance.setVolume(sfxBus.soundHandle!, 0.5);
// Apply effects to the entire bus
sfxBus.filters.echoFilter.activate();
sfxBus.filters.echoFilter.delay.value = 0.3;
// Get the number of active voices on the bus
final voiceCount = sfxBus.getActiveVoiceCount();
The Buses Singleton
Use the Buses singleton to manage all active buses:
// Get all active buses
final allBuses = Buses().buses;
// Find a bus by name
final sfxBus = Buses().byName('SFX');
// Find a bus by ID
final bus = Buses().byId(1);
Disposing Buses
When you're done with a bus, dispose it to free resources:
// Dispose a bus (stops all sounds playing through it)
sfxBus.dispose();
Annexing Sounds
Move a live sound from one bus to another (or from the engine to a bus):
// Play a sound on the main engine
final handle = await SoLoud.instance.play(someSound);
// Later, move it to a bus
sfxBus.annexSound(handle);
This is useful for:
- Dynamically grouping sounds at runtime
- Moving sounds between audio categories
- Applying effects to sounds that are already playing
3D Audio with Buses
You can play 3D positioned sounds through a bus:
// Play a 3D sound through the bus
await sfxBus.play3d(
explosion,
10.0, // posX
0.0, // posY
5.0, // posZ
);
Bus Filters
Apply filters to affect all sounds on a bus:
// Activate pitch shift filter on the bus
sfxBus.filters.pitchShiftFilter.activate();
sfxBus.filters.pitchShiftFilter
..shift(soundHandle: sfxBus.soundHandle).value = 1.5;
// Apply low-fi effect to all music
musicBus.filters.lofiFilter.activate();
musicBus.filters.lofiFilter
..sampleRate.value = 8000
..bitDepth.value = 4;
// Deactivate filters
sfxBus.filters.pitchShiftFilter.deactivate();
Channel Control
Configure the number of output channels and monitor levels:
// Set bus to mono or stereo (default is stereo)
sfxBus.setChannels(channels: Channels.mono);
// Get approximate output volume for VU meters
final leftVolume = sfxBus.getChannelVolume(0);
final rightVolume = sfxBus.getChannelVolume(1);
Complete Example
class AudioManager {
late Bus musicBus;
late Bus sfxBus;
late Bus voiceBus;
Future<void> init() async {
await SoLoud.instance.init();
// Create buses for different audio categories
musicBus = SoLoud.instance.createMixingBus(name: 'Music');
sfxBus = SoLoud.instance.createMixingBus(name: 'SFX');
voiceBus = SoLoud.instance.createMixingBus(name: 'Voice');
// Play all buses on the engine
musicBus.playOnEngine(volume: 0.7);
sfxBus.playOnEngine(volume: 1.0);
voiceBus.playOnEngine(volume: 0.9);
}
Future<void> playMusic(String path) async {
final music = await SoLoud.instance.loadAsset(path);
await musicBus.play(music, looping: true);
}
Future<void> playSfx(String path) async {
final sfx = await SoLoud.instance.loadAsset(path);
await sfxBus.play(sfx);
}
Future<void> playVoice(String path) async {
final voice = await SoLoud.instance.loadAsset(path);
await voiceBus.play(voice);
}
// Duck music when voice plays
void duckMusicForVoice() {
SoLoud.instance.setVolume(musicBus.soundHandle!, 0.3);
}
void restoreMusicVolume() {
SoLoud.instance.setVolume(musicBus.soundHandle!, 0.7);
}
void dispose() {
musicBus.dispose();
sfxBus.dispose();
voiceBus.dispose();
}
}
Best Practices
- Always call
playOnEngine()after creating a bus - sounds won't be audible until you do - Use meaningful names when creating buses to make them easier to identify
- Group logically - create buses for audio categories (music, SFX, UI, voice)
- Clean up - dispose buses when they're no longer needed
- Monitor voice count - use
getActiveVoiceCount()to debug audio issues - Use buses for effects - apply filters to buses rather than individual sounds when possible
- Volume categories - use buses to implement user-adjustable volume settings per category
Reference
- Bus class API - Full API documentation
- SoLoud Mixing Bus Documentation - Official SoLoud docs