Audio in FlatRedBall2
Access
Engine.Audio // AudioManager instance on FlatRedBallService
Loading Audio
Two paths. In the Common/Desktop template layout, prefer the direct path — it matches how every other raw asset (png, tmx, achx) is handled, with audio files living alongside them in Common/Content/. Reach for MGCB only when a format limit forces it (MP3).
Direct path — load the raw file (default for OGG/WAV)
Drop the file in Common/Content/ (e.g. Common/Content/Audio/song.ogg); it is linked into the Desktop output's Content/ automatically, no .mgcb entry needed. Load by full path with extension.
Song (music) — OGG only. Song.FromUri accepts only OGG Vorbis on DesktopGL; MP3 fails at runtime (NVorbis backend).
var song = Song.FromUri("song", new Uri(Path.GetFullPath("Content/Audio/song.ogg")));
SoundEffect — WAV only. SoundEffect.FromStream accepts only PCM WAV. OGG/MP3 effects need the MGCB path below.
using var stream = File.OpenRead("Content/Audio/hit.wav");
var sfx = SoundEffect.FromStream(stream);
Engine.Content.Track(sfx); // disposes on screen transition
Usings: System.IO, Microsoft.Xna.Framework.Audio, Microsoft.Xna.Framework.Media.
MGCB pipeline — for MP3 or compressed formats
Needed only when the direct path's format limits bite. The .mgcb lives in the .Desktop head, not Common: MonoGame.Content.Builder.Task runs only on the head, so a mgcb added to Common is silently never built. Put the #begin entry and the source file under Desktop/Content/. See multiplatform-conversion for the content-split rationale.
#begin Audio/song.mp3
/importer:Mp3Importer
/processor:SongProcessor
/build:Audio/song.mp3
Load with the asset name minus the source extension — /build:Audio/song.mp3 builds to Audio/song.xnb:
var song = Engine.Content.Load<Song>("Audio/song"); // not "Audio/song.mp3"
// ContentLoader disposes Load<>'d assets on screen transition — no Track() needed
Usings: Microsoft.Xna.Framework.Audio, Microsoft.Xna.Framework.Media.
Sound Effects
Engine.Audio.Play(sfx); // play with defaults
Engine.Audio.Play(sfx, volume: 0.5f, pitch: 0f, pan: 0f);
Engine.Audio.IsPlaying(sfx); // true if any instance is active
Per-frame dedup: calling Play(sfx) multiple times in a single frame (e.g., from CollisionOccurred firing on multiple pairs) plays the sound only once. Cross-frame overlap is allowed.
Background Music
Engine.Audio.PlaySong(song); // loops by default
Engine.Audio.PlaySong(song, loop: false);
Engine.Audio.PauseSong(); // holds position
Engine.Audio.ResumeSong(); // resumes from position
Engine.Audio.StopSong(); // clears position
Playlist
Engine.Audio.PlayPlaylist(song1, song2, song3); // plays sequentially, loops back to start
Pitchable music (runtime pitch/speed control)
PlaySong/PlayPlaylist are backed by MediaPlayer, which exposes no pitch/rate control on any
backend. For a slow-mo effect or similar, use PlayPitchableSong instead — it streams a raw OGG
file through a DynamicSoundEffectInstance, which does support real-time pitch:
Engine.Audio.PlayPitchableSong("Content/Audio/song.ogg"); // loops by default
Engine.Audio.MusicPitch = -0.3f; // tape-slowdown; [-1, 1], takes effect immediately
PauseSong/ResumeSong/StopSong/MusicVolume/MusicEnabled all work the same regardless of
whether PlaySong or PlayPitchableSong is active.
Volume and Enable/Disable
Engine.Audio.SoundVolume = 0.8f; // [0, 1], default 1
Engine.Audio.MusicVolume = 0.5f; // [0, 1], default 1; takes effect immediately
Engine.Audio.SoundEnabled = false; // silences new Play() calls; active instances finish naturally
Engine.Audio.MusicEnabled = false; // pauses current song immediately; true resumes it
Gotchas
- Music does not stop automatically on screen transition — call
Engine.Audio.StopSong()inCustomDestroy, or music keeps playing into the next screen. Song.FromUrionly works with OGG — on DesktopGL (NVorbis),Song.FromUrifails at runtime with MP3. Use the MGCB pipeline andEngine.Content.Load<Song>for MP3 files.Load<>name drops the source extension —Load<Song>("Audio/song"), not"Audio/song.ogg". Passing the extension makes MonoGame look forsong.ogg.xnb(the pipeline buildssong.xnb) and throwsFileNotFoundException. The.mgcbdefining it must be in the.Desktophead, notCommon.- Track SoundEffect only when loaded via
FromStream— callEngine.Content.Track(sfx)when usingSoundEffect.FromStreamso it is disposed on screen transition. MGCB-loaded assets (Engine.Content.Load<SoundEffect>) are disposed automatically by the ContentLoader — do not callTrackfor those. - Per-frame dedup in collision handlers —
Play(sfx)in aCollisionOccurredhandler is safe to call unconditionally; it fires at most once per frame regardless of how many pairs collide. PlayPitchableSongis OGG-only, same asSong.FromUri. It loads the raw file directly (not viaSong), soEngine.Content.Load<Song>/MGCB assets don't apply here.MusicPitchis a silent no-op while aPlaySong/PlayPlaylisttrack is active —Song/MediaPlayerexpose no pitch API on any backend. Switch toPlayPitchableSongto get real pitch control.