agentsclimarketplace

Libgdx audio lifecycle

Skill kyu-n/gdx-claude-skills/skills/libgdx-audio-lifecycle

Claude Code skills for working with the libGDX framework

Install
npx -y skills add kyu-n/gdx-claude-skills --skill libgdx-audio-lifecycle

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing libGDX Java/Kotlin code involving audio (Sound, Music, Gdx.audio). Use when debugging audio not playing, audio format issues, or platform-specific audio behavior in libGDX.

SKILL.md

5.6 KB, as published. Nobody here has run it

libGDX Audio

Quick reference for libGDX audio APIs. Covers Sound, Music, platform gotchas, and common audio patterns.

Audio: Sound vs Music

SoundMusic
LoadingFully into memoryStreamed from disk
Use forShort effects (<1MB on Android)Background tracks, long audio
ConcurrentMultiple instances via play()One stream per Music object
Auto pause/resumeNoYes (libGDX handles automatically)

Formats: WAV, MP3, OGG all supported. OGG not supported on iOS — use WAV or MP3.

Sound API

Sound snd = Gdx.audio.newSound(Gdx.files.internal("click.wav"));

// play() returns instance ID (long).
long id = snd.play();                          // default volume
long id = snd.play(volume);                    // volume: [0, 1]
long id = snd.play(volume, pitch, pan);        // pitch: [0.5, 2.0], pan: [-1, 1]

long id = snd.loop();                          // same overloads as play()
long id = snd.loop(volume, pitch, pan);

// Per-instance control (pass the id from play/loop)
snd.setVolume(id, volume);
snd.setPitch(id, pitch);
snd.setPan(id, pan, volume);                   // NOTE: pan+volume together
snd.setLooping(id, true);
snd.stop(id);
snd.pause(id);
snd.resume(id);

// All-instance control (no id)
snd.stop();
snd.pause();
snd.resume();

snd.dispose();                                 // MUST call when done

In non-trivial projects, prefer loading audio via AssetManager rather than raw Gdx.audio.newSound(). AssetManager handles disposal via unload() and supports async loading.

Gotchas:

  • Pan only works on mono sounds (stereo sounds ignore pan).
  • Android: uncompressed PCM must be <1MB for Sound. Use Music for larger files.
  • play() on an already-playing Sound plays it concurrently (new instance).
  • Behavior when exceeding platform limits is backend-dependent — sounds may silently fail to play. Do not rely on the return value to detect this.
  • play() called in create() can silently fail on Android before the audio system is fully initialized. Defer initial sound playback to the first render() frame or use a boolean flag.

Music API

Music bgm = Gdx.audio.newMusic(Gdx.files.internal("theme.ogg")); // OGG not supported on iOS — use MP3 for cross-platform

bgm.play();
bgm.pause();
bgm.stop();                                    // resets to beginning

bgm.setVolume(volume);                         // [0, 1]
float v = bgm.getVolume();
bgm.setPan(pan, volume);                       // [-1, 1], [0, 1]

bgm.setLooping(true);
boolean playing = bgm.isPlaying();
boolean looping = bgm.isLooping();

bgm.setPosition(seconds);                      // seek (float, in seconds)
float pos = bgm.getPosition();

bgm.setOnCompletionListener(music -> {
    // Called when music finishes playing
});

bgm.dispose();                                 // MUST call when done

In non-trivial projects, prefer loading audio via AssetManager rather than raw Gdx.audio.newMusic(). AssetManager handles disposal via unload() and supports async loading.

Gotchas:

  • OnCompletionListener does NOT fire when looping is true. If you need looping + completion callback, set looping=false and restart in the listener.
  • libGDX automatically pauses/resumes Music on Android pause/resume. You do NOT need to manually pause music in ApplicationListener.pause(). Doing so is redundant.
  • Only one OnCompletionListener per Music instance (last set wins).
  • setPosition() is unreliable on some Android devices for MP3 — seeking uses bitrate estimation and can be off by several seconds. OGG seeking is more accurate, but OGG is unsupported on iOS. For cross-platform seeking accuracy, consider WAV (large files) or accept MP3 imprecision.

Common Patterns

Shared Music Across Screens

Store Music in the Game class, not in individual Screens. Dispose only in Game.dispose().

public class MyGame extends Game {
    public Music bgm;

    @Override
    public void create() {
        bgm = Gdx.audio.newMusic(Gdx.files.internal("theme.mp3")); // use MP3 for iOS compatibility
        bgm.setLooping(true);
        bgm.play();
        setScreen(new MenuScreen(this));
    }

    @Override
    public void dispose() {
        bgm.dispose();
        getScreen().dispose();
    }
}

Platform Differences

BehaviorDesktop (LWJGL3)AndroidiOS (RoboVM)
OGG supportYesYesNo
Music auto-pauseOn minimize onlyYesYes
Sound size limitNone<1MB PCMNone
MP3 seeking accuracyGoodUnreliableGood

Common Mistakes

  1. Manually pausing Music in pause() — libGDX does this automatically. Redundant code confuses readers.
  2. Using Sound for long audio — Sound loads entirely into memory. Use Music for anything over a few seconds.
  3. Expecting OnCompletionListener with looping — It won't fire. Use looping=false + manual restart.
  4. Using OGG on iOS — Will fail silently or crash. Use WAV/MP3.
  5. Playing Sound in create() on Android — Audio system may not be ready. Defer to first render() frame.
  6. Relying on Music.setPosition() accuracy with MP3 on Android — Seeking can be off by seconds. Use OGG for accuracy (but not on iOS).
  7. Checking Sound.play() return value for failure detection — Behavior is backend-dependent. Don't rely on it.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.