LibGDX, Eclipse, and .wav files

First, sorry if it seems like I’m spamming the forum with my recent questions, but I promise you they’re all legit.

I am having a problem exporting my game to a runnable jar, where the music files don’t play (or at least can’t be heard), but the SFX work fine. So I googled and found this:
My exact question :https://stackoverflow.com/questions/22469319/eclipse-and-libgdx-problems-with-playing-music-on-exported-jar

Within that link, one of the answers is this:
“I guess Eclipse has problems with WAV files, if they’re too big, because my Music.wav which was around 7mb wouldn’t work, but my Soundeffect.wav which was less than 1mb worked fine.”

Is this still true or am I doing something wrong? I feel like, at least with a program as big and important as Eclipse, that shouldn’t happen? But I’m probably wrong.
And if it is true, how come the music files play fine in Eclipse but not the runnable jar (if it is indeed an Eclipse problem)? I would think it would be the other way around. That seems like it would be a JVM problem of some sort, unless Eclipse f**ks it up during the export.

Edit: I can post the code if it helps…and also I’m not getting any errors running the jar from the command line that have anything to do with loading or playing the music files.

Edit 2: @philfrei I’m tagging you.

I also ask because I don’t necessarily want to use mp3s or oggs. I know that will make the game bigger, but I’m not really concerned about that right now.

No problem about posting questions. This forum could do with a lot more of them!

I’ve only had a little experience with libgdx’s libraries for handling audio, when I was first looking at what would be involved in writing a wrapper for my audio library. I’m assuming that you are NOT using javax.sound.sampled.SourceDataLine, which would normally be the first choice for the playback of files that are too large to hold in memory.

If you were using javax.sound.sampled.Clip, I’d ask if you were reloading the audio data for each play back. Lots of programmers new to audio do this, not realizing that the entire file has to load before the sound will start playing, and for large files the lag can be considerable.

Can you show the code for playback? Is everything identical except the size of the files?

I doubt this is an Eclipse issue. But if you are storing the SFX and the longer cues in different places, then that would be worth exploring. There are times when one can play audio from within Eclipse but not within a jar, due to how the files are addressed and where they are located.

As far as using mp3 or ogg, I think it was @nsigma who set up a collection of useful utils here. But they’d probably require a bit of fussing to get them to run over libgdx. He’ll probably know more about that.

Dude, I’m working really hard on Saints R…nvm. Of course I can post the code.

So, I’m sure you know, LibGDX (I think) uses two forms of audio, Music and Sound. Music is for long clips, and sound is for short clips like SFX.

Here is how everything is loaded:
Music:


public class MusicHandler {

	private boolean startDayTimeAmbientAudio   = true;
	private boolean startNightTimeAmbientAudio = true;
	private boolean startStormAudio            = true;
	private boolean startFootstepsAudio        = true;
	private boolean startOceanAudio            = true;

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	public void handleMusic(MusicLoader musicLoader) {
		if (GameAttributeHelper.gameState == Screens.GAME_SCREEN) {
			if (NightAndDayCycle.isDayTime()) {
				handleDayTimeAudio(musicLoader);
			} else {
				handleNightTimeAudio(musicLoader);
			}
			handleFootstepsAudio(musicLoader);
			handleFireAudio(musicLoader);
			handleOceanAudio(musicLoader);
		} 
	}

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	private void handleDayTimeAudio(MusicLoader musicLoader) {
		if (musicLoader.nightTimeAmbientNoise.isPlaying()) {
			musicLoader.nightTimeAmbientNoise.stop();
			startNightTimeAmbientAudio = true;
		}
		if (startDayTimeAmbientAudio) {
			musicLoader.dayTimeAmbientNoise.setVolume(AudioHandler.DAY_TIME_AMBIENT_VOLUME);
			musicLoader.dayTimeAmbientNoise.setLooping(true);
			musicLoader.dayTimeAmbientNoise.play();
			startDayTimeAmbientAudio = false;
		}
		handleStormAudio(musicLoader);
	}

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	private void handleStormAudio(MusicLoader musicLoader) {
		if (WeatherHandler.isStorming() && startStormAudio) {
			musicLoader.rainAndThunder.setVolume(AudioHandler.MAX_VOLUME);
			musicLoader.rainAndThunder.setLooping(true);
			musicLoader.rainAndThunder.play();
			musicLoader.dayTimeAmbientNoise.stop();
			startStormAudio = false;
		} else if (!WeatherHandler.isStorming()) {
			if (musicLoader.rainAndThunder.isPlaying()) {
				musicLoader.rainAndThunder.stop();
				startStormAudio = true;
			}
		}
	}

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	private void handleNightTimeAudio(MusicLoader musicLoader) {
		if (startNightTimeAmbientAudio) {
			musicLoader.nightTimeAmbientNoise.setVolume(AudioHandler.NIGHT_TIME_AMBIENT_VOLUME);
			musicLoader.nightTimeAmbientNoise.setLooping(true);
			musicLoader.nightTimeAmbientNoise.play();
			startNightTimeAmbientAudio = false;

			if (musicLoader.dayTimeAmbientNoise.isPlaying()) {
				musicLoader.dayTimeAmbientNoise.stop();
				startDayTimeAmbientAudio = true;
			}
		}
	}

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	private void handleFireAudio(MusicLoader musicLoader) {
		if (Fire.playSound) {
			musicLoader.fire.setVolume(AudioHandler.MAX_VOLUME);
			musicLoader.fire.play();
			Fire.playSound = false;
		} else {
			musicLoader.fire.stop();
		}
	}

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	private void handleOceanAudio(MusicLoader musicLoader) {
		// Play this audio if player is in water.
		if (Player.isInWater || MissionRawBar.phasesAreInProgress) {
			startOceanAudio = true;
		} else {
			musicLoader.ocean.stop();
		}
		if (startOceanAudio) {
			musicLoader.ocean.setVolume(AudioHandler.MAX_VOLUME);
			musicLoader.ocean.setLooping(true);
			musicLoader.ocean.play();
			startOceanAudio = false;
		}
	}

	/**
	 * 
	 * @param MusicLoader musicLoader
	 */
	private void handleFootstepsAudio(MusicLoader musicLoader) {
		if (
				Player.playerIsMoving && 
				Player.jumpingAction == Player.ON_GROUND && 
				!Player.isInWater && 
				!MissionRawBar.phasesAreInProgress
				) {
			startFootstepsAudio = true;
		} else {
			musicLoader.footsteps.stop();
		}
		if (startFootstepsAudio) {
			musicLoader.footsteps.setVolume(AudioHandler.FOOTSTEPS_VOLUME);
			musicLoader.footsteps.setLooping(true);
			musicLoader.footsteps.play();
			startFootstepsAudio = false;
		}
	}
}

Pretty straight forward.

Here’s how the SFX work:


public class SoundHandler {

	private boolean startLandingAudio = false;

	private int attackTimer    = GameAttributeHelper.TIMER_START_VALUE;
	private int inventoryTimer = GameAttributeHelper.TIMER_START_VALUE;
	private int jumpTimer      = GameAttributeHelper.TIMER_START_VALUE;

	/**
	 * 
	 * @param SoundLoader soundLoader
	 * @param MyGame      myGame
	 */
	public void handleSound(SoundLoader soundLoader, MyGame myGame) {
		if (GameAttributeHelper.gameState == Screens.GAME_SCREEN) {
			if (LegendSword.playSound) {
				soundLoader.pickUpSwordSound.play(AudioHandler.PICK_UP_SWORD_VOLUME);
				LegendSword.playSound = false;
			}
			if (Gun.playCollectionSound) {
				soundLoader.pickUpGunSound.play(AudioHandler.MAX_VOLUME);
				Gun.playCollectionSound = false;
			}
			if (MagicPearl.playCollectionSound) {
				soundLoader.bubbleSound.play(AudioHandler.MAX_VOLUME);
				MagicPearl.playCollectionSound = false;
			}
			if (MissionRawBar.playCollectionSound) {
				soundLoader.bubbleSound.play(AudioHandler.MAX_VOLUME);
				MissionRawBar.playCollectionSound = false;
			}

			for (int i = 0; i < myGame.gameScreen.enemyHandler.enemySpawner.length; i++) {
				for (int k = 0; k < myGame.gameScreen.enemyHandler.enemySpawner[i].enemies.size(); k++) {
					// For now make the same sound for every enemy killing.  The explosion sounds cool.
					if (myGame.gameScreen.enemyHandler.enemySpawner[i].enemies.get(k).getPlaySound()) {
						soundLoader.bombSound.play(AudioHandler.MEDIAN_VOLUME);
						myGame.gameScreen.enemyHandler.enemySpawner[i].enemies.get(k).setPlaySound(false);
					}
				}
			}

			attackTimer++;
			if (attackTimer > 2) {
				attackTimer = GameAttributeHelper.TIMER_START_VALUE;
			}
			if (Player.playerIsPerformingAttack) {
				if (attackTimer > 1) {
					if (myGame.getGameObject(Player.PLAYER_ONE).getInventory().inventory.get(Inventory.currentlySelectedInventoryObject) instanceof LegendSword) {
						soundLoader.swordSound.play(AudioHandler.MAX_VOLUME);
					} else if (myGame.getGameObject(Player.PLAYER_ONE).getInventory().inventory.get(Inventory.currentlySelectedInventoryObject) instanceof Gun) {
						soundLoader.pistolSound.play(AudioHandler.MEDIAN_VOLUME);
					} else {
						soundLoader.bubbleSound.play(AudioHandler.MAX_VOLUME);
					}
				}
			}

			// Collectibles.
			if (Heart.playSound) {
				soundLoader.heartSound.play(AudioHandler.MAX_VOLUME);
				Heart.playSound = false;
			}
			for (int i = 0; i < ChestLoader.chests.length; i++) {
				if (ChestLoader.chests[i].getPlaySound()) {
					soundLoader.chestSound.play(AudioHandler.CHEST_VOLUME);
					ChestLoader.chests[i].setPlaySound(false);
				}
			}

			// Click sound when choosing different inventory objects.
			inventoryTimer++;
			if (inventoryTimer > 2) {
				inventoryTimer = GameAttributeHelper.TIMER_START_VALUE;
			}
			if (Inventory.playClickSound) {
				if (inventoryTimer < 1) {
					soundLoader.clickSound.play(AudioHandler.MAX_VOLUME);
					Inventory.playClickSound = false;
					inventoryTimer           = GameAttributeHelper.TIMER_START_VALUE;
				}
			}
			handleJumpingAudio(soundLoader);
			handleLandingAudio(soundLoader);
		}
	}

	/**
	 * 
	 * @param SoundLoader soundLoader
	 */
	private void handleJumpingAudio(SoundLoader soundLoader) {
		if (Player.isJumping) {
			if (jumpTimer < 1) {
				soundLoader.jumpSound.play(AudioHandler.JUMP_VOLUME);
			}
			jumpTimer++;
			if (jumpTimer > 50) {
				jumpTimer = GameAttributeHelper.TIMER_START_VALUE;
			}
		} else {
			jumpTimer = GameAttributeHelper.TIMER_START_VALUE;
		}
	}

	/**
	 * 
	 * @param SoundLoader soundLoader
	 */
	private void handleLandingAudio(SoundLoader soundLoader) {
		if (startLandingAudio && Player.jumpingAction == Player.ON_GROUND) {
			soundLoader.landSound.play(AudioHandler.LAND_VOLUME);
			startLandingAudio = false;
		}
		if (Player.isJumping) {
			startLandingAudio = true;
		}
	}
}

And here is how the game makes them work together (which is in the game loop):


import loaders.MusicLoader;
import loaders.SoundLoader;

/**
 * Handles all audio in game.
 * 
 * @author Fabulous Fellini
 *
 */
public class AudioHandler {

	public final static float MINIMUM_VOLUME = 0f;
	public final static float MEDIAN_VOLUME  = 0.5f;
	public final static float MAX_VOLUME     = 1.0f;

	public final static float FOOTSTEPS_VOLUME = 0.15f;
	public final static float JUMP_VOLUME      = 0.10f;
	public final static float LAND_VOLUME      = 0.10f;

	public final static float DAY_TIME_AMBIENT_VOLUME   = 0.25f;
	public final static float NIGHT_TIME_AMBIENT_VOLUME = 0.7f;

	public final static float CHEST_VOLUME = .25f;

	public final static float PICK_UP_SWORD_VOLUME = 0.1f;

	/**
	 * Loads sounds.
	 */
	private SoundLoader soundLoader = new SoundLoader();

	/**
	 * Handles sounds.
	 */
	private SoundHandler soundHandler = new SoundHandler();

	/**
	 * Loads music.
	 */
	private MusicLoader musicLoader = new MusicLoader();

	/**
	 * Handles music.
	 */
	private MusicHandler musicHandler = new MusicHandler();

	public void init() {
		soundLoader.init();
		musicLoader.init();
	}

	public void dispose() {
		soundLoader.dispose();
		musicLoader.dispose();
	}

	/**
	 * 
	 * @param MyGame myGame
	 */
	public void handleAudio(MyGame myGame) {
		soundHandler.handleSound(soundLoader, myGame);
		musicHandler.handleMusic(musicLoader);
	}
}

Also if you see anything with me doing this incorrectly, please let me know.

Where are the sound files stored? How are you addressing those files? Are they being addressed by their File addresses or by URL? File addresses don’t work in jars, but they will work in Eclipse. You should be using URLs.

Another thought, is it possible to inquire programmatically about the length of the various cues after they are loaded? I’m wanting to verify that the files actually get loaded.

Another thought, it might be an interesting test to take the largest SFX file and load it as a musical cue, and the shortest musical cue and load it as an SFX.