Package limn.sound

Interface AudioEngine


public interface AudioEngine
Service-provider interface for audio output, the sound counterpart of the Backend rendering SPI. The only shipped implementation is OpenAL (in limn-backend-lwjgl); the abstraction keeps the toolkit free of any audio library. Installed once at backend startup (see Sounds.installEngine(limn.sound.AudioEngine)).

Best-effort: on a machine with no audio device the engine reports unavailable and play(limn.sound.AudioClip, float, boolean) returns Playback.NONE rather than throwing, so UI feedback sounds never become a hard dependency.

  • Method Summary

    Modifier and Type
    Method
    Description
    boolean
    Whether an audio device is available and initialized.
    play(AudioClip clip, float gain, boolean loop)
    Plays clip once (or looping) at the given volume.
    default Playback
    play(AudioClip clip, PlayOptions options)
    Plays clip with the full PlayOptions: pitch, pan or 3D position, bus and steal priority.
    default Playback
    Streams source, decoding incrementally on the engine's streaming thread instead of uploading a whole clip.
    default void
    setBusGain(AudioBus bus, float gain)
    Sets bus's volume multiplier in [0..1], applied live to its playbacks.
    default void
    setListener(Vec3 position, Vec3 forward, Vec3 up)
    Positions the 3D listener for positional playbacks: where the "ears" are and which way they face.
    default void
    setMasterGain(float gain)
    Sets the global volume multiplier in [0..1], applied live to everything.
  • Method Details

    • play

      Playback play(AudioClip clip, float gain, boolean loop)
      Plays clip once (or looping) at the given volume. The clip's device buffer is created on first use and cached by object identity, so replaying a shared clip is cheap. Multiple clips may sound at once (mixed by the device). Safe to call from any thread.
      Parameters:
      clip - the audio to play
      gain - volume in [0..1]
      loop - whether to repeat until stopped
      Returns:
      a handle to the started sound, or Playback.NONE if no audio device is available
    • play

      default Playback play(AudioClip clip, PlayOptions options)
      Plays clip with the full PlayOptions: pitch, pan or 3D position, bus and steal priority. The default honors only gain/loop, so simple engines and test fakes keep working; the shipped backend honors everything. Safe to call from any thread.
    • playStream

      default Playback playStream(AudioStreamSource source, PlayOptions options)
      Streams source, decoding incrementally on the engine's streaming thread instead of uploading a whole clip. The engine takes ownership of the source (closing it when playback ends or is stopped). Looping rewinds via AudioStreamSource.reset(). Default: closes the source and reports Playback.NONE (no streaming support).

      Runs on the calling thread and is allowed to block there: an implementation that queues device buffers ahead of the play decodes the first of them here, before the sound starts. That is a decode of the first fraction of a second, so this is not a call to make on the UI thread with a source whose format is expensive.

    • setMasterGain

      default void setMasterGain(float gain)
      Sets the global volume multiplier in [0..1], applied live to everything.
    • setBusGain

      default void setBusGain(AudioBus bus, float gain)
      Sets bus's volume multiplier in [0..1], applied live to its playbacks.
    • setListener

      default void setListener(Vec3 position, Vec3 forward, Vec3 up)
      Positions the 3D listener for positional playbacks: where the "ears" are and which way they face.
      Parameters:
      position - the listener's world position
      forward - unit vector the listener faces
      up - unit up vector (perpendicular to forward)
    • isAvailable

      boolean isAvailable()
      Whether an audio device is available and initialized.

      An implementation may open the device here, on the first call. Loading the platform audio library and waking the default output is tens to hundreds of milliseconds (more when the output is asleep or on a Bluetooth link), and it blocks whichever thread asks. That is allowed, and it is why Sounds.warmUpAsync() exists: the facade needs one call it can make on a worker to get the cost over with. Calls after the first must be cheap: the facade asks this before it decides whether to open a track at all, so it sits on paths that run often.

      Failure is not an exception: a machine with no device answers false for the rest of the process rather than retrying the open on every call.

      Returns:
      whether something played now would be heard