Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl/llms.txt

Use this file to discover all available pages before exploring further.

Prowl’s audio system is built on top of OpenAL, giving you hardware-accelerated spatial sound out of the box. The engine exposes a clean, component-driven API through AudioSource and AudioListener, while the static AudioSystem class lets you fire one-shot sounds and background music without attaching anything to a GameObject. Whether you need a looping ambient track, a 3D footstep effect that fades with distance, or a UI click that ignores the listener position entirely, Prowl handles it through a unified pool of ActiveAudio handles that you can adjust in real-time.

Audio System Initialization

AudioSystem.Initialize() is called automatically by the engine at startup. It attempts to create an OpenALEngine; if that fails (for example on a headless server), it silently falls back to NullAudioEngine so the rest of your code continues to run without modification.
// Engine calls this for you — shown here for reference only
AudioSystem.Initialize();

// Access the active backend at runtime
AudioEngine backend = AudioSystem.Engine;
Only one AudioListener may be active at a time. If a second listener is registered, Prowl logs a warning and ignores it. Destroy the first listener before creating a new one when switching cameras.

Components

AudioListener

AudioListener tells the engine where the “ears” are in your scene. Attach it to your main camera or player GameObject. Every frame it forwards the transform’s position, velocity, and orientation to the OpenAL backend so that 3D sounds are spatialized correctly.
// Add via code — usually done in the editor Inspector
AudioListener listener = cameraGameObject.AddComponent<AudioListener>();
There is nothing else to configure. The component registers itself with AudioSystem on OnEnable and unregisters on OnDisable, so enabling/disabling the camera naturally updates which listener is active.

AudioSource

AudioSource is the workhorse component for scene-attached sounds. It manages its own ActiveAudio source internally and updates the position every frame relative to the registered listener.
PropertyTypeDefaultDescription
ClipAssetRef<AudioClip>The audio clip to play
PlayOnAwakebooltruePlay automatically when the component starts
LoopingboolfalseLoop the clip continuously
Volumefloat1.0Gain multiplier (0–1)
MaxDistancefloat32.0Distance at which the sound is completely silent
public class FootstepPlayer : MonoBehaviour
{
    public AssetRef<AudioClip> StepClip;
    private AudioSource _source;

    public override void Awake()
    {
        _source = GameObject.AddComponent<AudioSource>();
        _source.Clip = StepClip;
        _source.PlayOnAwake = false;
        _source.Looping = false;
        _source.Volume = 0.8f;
        _source.MaxDistance = 20f;
    }

    public void Step()
    {
        _source.Play();
    }
}
Call _source.Stop() at any time to halt playback. When the component is disabled it stops automatically; when it is destroyed the underlying OpenAL source is disposed.

AudioClip Asset

AudioClip is a serialized runtime asset that stores raw PCM audio data together with metadata (sample rate, bit depth, channel count). Load it through the asset reference system:
// Declared as a serialized field so it appears in the Inspector
public AssetRef<AudioClip> MusicClip;

// Check availability before use
if (MusicClip.IsAvailable)
{
    AudioClip clip = MusicClip.Res!;
    Debug.Log($"Clip: {clip.Name}, Duration: {clip.Duration}s, Format: {clip.Format}");
}
The AudioClipImporter handles .wav, .wave, and .ogg files. Once imported, the clip is cached in AudioSystem as an AudioBuffer so repeated calls to PlaySound do not re-upload data to the audio hardware.

AudioSystem API

For sounds that do not need a persistent scene object — explosions, UI clicks, one-shot voice lines — call AudioSystem.PlaySound directly. All overloads return an ActiveAudio handle.
// Simplest: play a clip at full volume, listener-relative (UI/music)
ActiveAudio handle = AudioSystem.PlaySound(clip);

// Play with custom volume and pitch
ActiveAudio handle2 = AudioSystem.PlaySound(clip, volume: 0.5f, pitch: 1.2f);

// Play at an absolute world-space position (3D positional sound)
ActiveAudio handle3 = AudioSystem.PlaySound(
    clip,
    volume: 1f,
    pitch: 1f,
    position: explosionPos,
    positionKind: AudioPositionKind.AbsoluteWorld
);
Use AudioPositionKind.ListenerRelative (the default) for UI sounds and music so they are never attenuated by distance. Use AudioPositionKind.AbsoluteWorld for any sound that should come from a point in the scene.

PlaySound Overloads

SignatureDescription
PlaySound(AudioClip clip)Full volume, listener-relative.
PlaySound(AudioClip clip, float volume)Custom volume, listener-relative.
PlaySound(AudioClip clip, float volume, float pitch)Custom volume and pitch, listener-relative.
PlaySound(AudioClip clip, float volume, float pitch, Vector3 position, AudioPositionKind positionKind)Custom volume, pitch, and 3D position.

ActiveAudio Handle

PlaySound returns an ActiveAudio object that lets you modify or stop the sound while it is still playing.
public abstract class ActiveAudio : IDisposable
{
    public abstract float Gain { get; set; }          // Volume (0–1)
    public abstract float Pitch { get; set; }          // Pitch multiplier
    public abstract float MaxDistance { get; set; }    // Attenuation distance
    public abstract bool Looping { get; set; }
    public abstract Vector3 Position { get; set; }
    public abstract Vector3 Direction { get; set; }
    public abstract AudioPositionKind PositionKind { get; set; }
    public abstract float PlaybackPosition { get; set; } // 0–1 normalised
    public abstract bool IsPlaying { get; }
    public abstract void Play(AudioBuffer buffer);
    public abstract void Stop();
    public abstract void Dispose();
}
ActiveAudio music = AudioSystem.PlaySound(musicClip);
music.Looping = true;
music.Gain = 0.3f;   // background music at 30% volume

// Fade or stop later
music.Stop();
ActiveAudio handles are managed by the engine’s internal source pool. Stopped or finished sources are automatically returned to the pool by AudioSystem.UpdatePool(), which the engine calls each frame. Do not call Dispose() on handles returned from PlaySound — only call it on sources you created directly via AudioSystem.Engine.CreateAudioSource().

Code Examples

public class MusicManager : MonoBehaviour
{
    public AssetRef<AudioClip> ThemeClip;
    private ActiveAudio _music;

    public override void Awake()
    {
        if (!ThemeClip.IsAvailable) return;
        _music = AudioSystem.PlaySound(ThemeClip.Res!, volume: 0.4f, pitch: 1f);
        _music.Looping = true;
        _music.PositionKind = AudioPositionKind.ListenerRelative;
    }

    public override void OnDestroy()
    {
        _music?.Stop();
    }
}

AudioBuffer and AudioBufferPool

AudioBuffer is the low-level representation of decoded PCM data uploaded to the audio backend. AudioSystem.GetAudioBuffer(clip) lazily uploads the clip and caches the result in a dictionary keyed by AudioClip instance. You typically never need to create or destroy buffers manually — they live for the lifetime of the engine session and are disposed in AudioSystem.Dispose().
// Internally used by AudioSystem — shown for reference
AudioBuffer buffer = AudioSystem.GetAudioBuffer(myClip);
ActiveAudio src = AudioSystem.Engine.CreateAudioSource();
src.Play(buffer);
Calling AudioSystem.Dispose() is done automatically by the engine on shutdown. Do not call it from game code unless you are writing a custom engine host.

Build docs developers (and LLMs) love