Just Audio Engine
High-performance audio pipeline for just_game_engine.
just_audio_engine provides a single Dart façade over platform-native backends — AVAudioEngine on iOS/macOS, XAudio2 on Windows, OpenAL Soft on Linux, SoundPool and MediaPlayer on Android, and the Web Audio API on web — so your audio code is identical across every target.
Features
- BGM — background music with fade-in/fade-out, loop, and cross-fade when switching tracks
- SFX — one-shot and looping sound effects; returns a clip ID for per-voice volume, pan, pitch, and speed control
- Channel routing — five logical channels (
master,music,sfx,voice,ambient) each backed by anAudioBus - DSP effects — reverb, lowpass, highpass, EQ, delay, chorus, distortion applied per voice
- 3D audio — sounds placed in the world and heard from a listener: fading with distance (
AudioSpatial: inverse, linear or no rolloff between a min and max distance), panned by direction, doppler from motion, muffled far away; worked out the same way on every platform and sent in one batch per frame - Chunked streaming —
AudioStreamloads large files in chunks to keep memory usage flat - Voice pool — up to 64 concurrent voices; oldest unprotected voice is evicted on overflow
- Convenience managers —
MusicManagerandSoundEffectManagerfor common patterns with less boilerplate
Getting started
Add the dependency to your pubspec.yaml:
dependencies:
just_audio_engine: ^1.1.0
just_audio_engine is initialised automatically when it is first used (lazy init), but you can initialise it explicitly at startup:
final audio = AudioEngine();
await audio.initialize();
When used inside just_game_engine, the engine exposes pre-built managers:
final engine = Engine();
// engine.audio → AudioEngine
// engine.music → MusicManager
// engine.sfx → SoundEffectManager
Usage
Background music
// Play with a 2-second fade-in, loop forever
await engine.music.play(
'assets/audio/bgm.mp3',
loop: true,
fadeIn: true,
fadeDuration: const Duration(seconds: 2),
);
engine.music.pause();
engine.music.resume();
engine.music.stop(fadeOut: true);
engine.music.setChannelVolume(0.7);
Sound effects
// Fire a one-shot SFX — returns an opaque ID for per-voice control
final id = await engine.sfx.play(
'assets/audio/hit.wav',
volume: 0.8,
pan: -0.5,
pitch: 1.2,
speed: 0.9,
);
// Per-voice control while it's playing
engine.audio.setSfxVolume(id!, 0.5);
engine.audio.pauseSfx(id!);
engine.audio.resumeSfx(id!);
engine.audio.stopSfx(id!);
// Stop every active SFX at once
engine.audio.stopAllSfx();
Channel volume & mute
engine.audio.setMasterVolume(1.0);
engine.audio.setChannelVolume(AudioChannel.music, 0.7);
engine.audio.setChannelVolume(AudioChannel.sfx, 1.0);
engine.audio.setChannelVolume(AudioChannel.voice, 0.9);
engine.audio.setChannelVolume(AudioChannel.ambient, 0.5);
engine.audio.mute();
engine.audio.unmute();
engine.audio.toggleMute();
engine.audio.isMuted; // → bool
DSP effects
Effects are applied per voice at play time:
await engine.audio.playSfx(
'assets/audio/hit.wav',
effects: [
AudioEffect.reverb(roomSize: 0.8, damping: 0.5, wetLevel: 0.4),
AudioEffect.lowpass(frequency: 800, q: 1.0),
AudioEffect.highpass(frequency: 200, q: 1.0),
AudioEffect.delay(delayMs: 250, feedback: 0.3, mix: 0.3),
AudioEffect.eq(frequency: 1000, gain: 3.0, q: 1.0),
],
);
3D audio
A sound played with a position3d is heard from the listener: its volume
from how far away it is, its pan from which side it is on, its pitch from
how fast it and the listener move (doppler), and how muffled it is from how
far it is. AudioSpatial says how:
final hum = await engine.audio.playSfx(
'assets/audio/hum.wav',
loop: true,
position3d: const Audio3DPosition(4, 1, -2),
spatial: const AudioSpatial(
minDistance: 1, // full volume within 1 unit
maxDistance: 20, // silent beyond 20
rolloff: AudioRolloff.inverse, // or linear, or none
dopplerLevel: 1, // 0 = no doppler; 1 = real-world, for metres
farCutoff: 1500, // muffled down to 1.5 kHz at maxDistance; 0 = never
),
);
// Each frame: where the listener is and which way it faces…
engine.audio.setListener3D(Audio3DListener(
position: Audio3DPosition(player.x, player.y, player.z),
forward: const Audio3DPosition(0, 0, -1),
up: const Audio3DPosition(0, 1, 0),
));
// …where the sound has moved to…
engine.audio.updateSfxPosition(hum!, Audio3DPosition(x, y, z));
// …and the update that places every 3-D sound, in one call to the platform.
engine.audio.update();
The world is taken to be right-handed (the listener's right is
forward × up): OpenGL's axes and just_game_engine's (+Z forward, −Y up)
both are. Distances are in the world's units; AudioEngine.speedOfSound
(343, for metres) sets the doppler's scale. AudioSpatial.mix works out
what a sound sounds like from a listener, for tools and tests.
Every platform is given the same volume, pan, pitch and cutoff, so a game sounds the same everywhere: equal-power panning (−3 dB at the centre for a mono sound), a stereo file folded to mono before it is panned. Android has no per-voice filter, so far sounds are not muffled there, and it cannot fold a stereo file: use mono files for 3-D sounds.
Chunked streaming
Use AudioStream for music or long ambient loops to avoid loading the whole file into memory:
final stream = AudioStream(
path: 'assets/audio/bgm.mp3',
channel: AudioChannel.music,
);
await stream.open(engine.audio.backend);
await stream.play(volume: 0.8, loop: true);
await stream.setVolume(0.5);
await stream.fade(0.0, const Duration(seconds: 2));
await stream.pause();
await stream.resume();
await stream.stop();
await stream.dispose();
Platform support
| Platform | Backend |
|---|---|
| Android | SoundPool (effects), MediaPlayer (streams) |
| iOS | AVAudioEngine |
| macOS | AVAudioEngine |
| Windows | XAudio2 |
| Linux | OpenAL Soft |
| Web | Web Audio API |
Additional information
- Source — github.com/just-unknown-dev/just-audio-engine
- Issues — file bugs and feature requests on the GitHub issue tracker
- Contributing — see CONTRIBUTING.md
- Code of Conduct — see CODE_OF_CONDUCT.md
Libraries
- just_audio_engine
- just_audio_engine — High-performance audio processing pipeline for just_game_engine.