Burnsies HideoutDocsBurnsie.Common

Audio — WavPlayer and FrontendSounds

RagePluginHook 1.124 has no managed sound API (verified absence). Burnsie.Common.Audio is the supported path for custom audio: WAV files preloaded into memory off the game thread, played on background CLR threads. A GameFiber never touches disk and never blocks.

For police-scanner voice lines, use ScannerAudio from the LSPDFR layer instead — that plays through LSPDFR's scanner system.

WavPlayer — custom WAV playback

var wav = new WavPlayer(log);

// At duty start: preload every sound you may play (off-thread, returns immediately).
wav.Preload("plugins/LSPDFR/MyPlugin/audio/alert.wav");

// Anywhere: play asynchronously. Never blocks the caller.
wav.Play("plugins/LSPDFR/MyPlugin/audio/alert.wav");

// Repeats with a gap (e.g. a triple panic tone):
wav.Play("plugins/LSPDFR/MyPlugin/audio/tone.wav", repeats: 3, gapMs: 450);

// Check load state (e.g. before offering an option that needs the sound):
bool ready = wav.IsLoaded(path);

// Teardown / stand-down:
wav.StopAll();

Behavior

  • Formats: PCM WAV — what System.Media.SoundPlayer supports. (No MP3/OGG.)
  • Paths: absolute, or relative to the GTA V root.
  • Files are cached in memory (case-insensitive by path). Play on an unloaded file loads it on the playback thread — the first play may be slightly delayed but the game never stalls; preloading at duty start avoids even that.
  • Missing files degrade to silence with a single warning. The path is remembered as unavailable, so a missing file warns once, not per play.
  • One background thread runs each logical playback (including all its repeats) over an in-memory stream — bounded work, no unmanaged thread leaks.
  • StopAll() abandons all pending repeats of every active playback. A buffer that has already started finishes naturally (SoundPlayer has no safe cross-thread mid-buffer stop); keep your tones short and this is inaudible in practice.

FrontendSounds — named HUD cues

Static, fail-soft wrappers over the game's frontend sound system (via SafeNatives.PlayFrontendSound). An unknown sound name/set pair is silence, never an error.

FrontendSounds.RadioSquelchOpen();   // classic mic click before a broadcast
FrontendSounds.RadioSquelchClose();  // squelch off
FrontendSounds.ErrorBeep();          // neutral denied beep (e.g. pressed during cooldown)
FrontendSounds.TimerStop();          // timer-end cue (hold-to-confirm completion)

The sound name/set pairs come from decompiled-script research. Pair RadioSquelchOpen/Close around scanner or radio moments for cheap immersion:

FrontendSounds.RadioSquelchOpen();
notifier.Show(Palette.Dispatch("copy, units en route"));

Rules

  • Never call WavPlayer methods expecting them to block until playback ends — everything is fire-and-forget. If you need to sequence after a sound, GameFiber.Sleep for the sound's known duration.
  • FrontendSounds must be called from a GameFiber (it goes through a native call).
  • WavPlayer.Play/Preload are safe from any thread.