Background Music System: How do i do this? [SOLVED]

So i have a ton of tracks for my game already (all on my youtube channel)

but the sound system i have right now is hella buggy and doesnt passively play tracks like i need it to.

I need a system that plays a track, then when its done pick an amount of time based on a range to wait before playing the next track, then pick a track randomly from a list of tracks that can play depending on circumstances (time of day/area of map etc)

In short, a passive version (like minecraft) of terraria’s music system.

Can anyone give me any pointers?

EDIT: Tinysound turned out to be perfect and the sound system is now fully functional.

void tick() 
	{
		if (TritonForge.Screen != "Title" && Menu.playing() == true)
		{
			Menu.stop();
		}
		if (TritonForge.Screen == "Game")
		{
			if (music == false)
			{
				GoodMorning.stop();
				May.stop();
				timer--;
				if (timer  <= 0)
				{
					int i = new Random().nextInt(range) + 1800;
					timer = i;
					if (Sky.time == Sky.day)
					{
						int m = new Random().nextInt(5);
						if (m == 0){GoodMorning.play(true,musicvol); GoodMorning.setLoop(false);music = true;}
						if (m == 1){May.play(true,musicvol); May.setLoop(false);music = true;}
						if (m == 2){Sunset.play(true,musicvol); Sunset.setLoop(false);music = true;}
						if (m == 3){Winter.play(true,musicvol); Winter.setLoop(false);music = true;}
						if (m == 4){Calm.play(true,musicvol); Calm.setLoop(false);music = true;}
					}
					if (Sky.time == Sky.night)
					{
						int m = new Random().nextInt(2);
						if (m == 0){Sunset.play(true,musicvol); Sunset.setLoop(false);music = true;}
						if (m == 1){Dusk.play(true,musicvol); Dusk.setLoop(false);music = true;}
					}
				}
			}
		}
		System.out.println(timer);
		if (GoodMorning.playing() == false &&
			May.playing() == false &&
			Sunset.playing() == false &&
			Winter.playing() == false &&
			Calm.playing() == false)
		{
			music = false;
		}
	}

Just a quick question. Are you asking for how you would do this? Or asking for a sort of library? I just ask because you said it’s buggy so I get the impression that you’re referring to the the actual sound playing code?

Use a background thread that maintains an internal list of tracks to play, pick a track from that list and then play it, updating on the background thread.

For the randomness part, I’d say just use [icode]java.util.Random[/icode]'s nextInt(int bounds) method :point:

Or you could use this method if you don’t like 0 coming up:


public static int getInt(int bound) {
		Random r = new Random();
		int i = r.nextInt(bound);
		if (i == 0) {
			return 2;
		}
		return i;
	}

DarkCart: Please don’t suggest people do that. Just don’t. It gives whatever track is at 2 twice the expected frequency.

If anything, do this instead:

private static Random rng = new Random();

public static int getInt(int bound) {
		int i = rng.nextInt(bound - 1) + 1;
		return i;
	}

A library would be great, self engineered systems are too. The code i have right now is done in two seconds based on a mini tutorial series for a 2d game. music is overly loud and if you exit during a song, a millisecond of the song loops till the computer turns off (you can download tritonforge and see for yourself too)

Its really bad.

Something like this sounds like it would work. But sound code is one of the things i cant right from scratch at all…

are there any good music libraries anyone knows of before i scan the internet?

I find TinySound useful, example usage including project setup: http://www.java-gaming.org/topics/getting-tinysound-to-play-oggs-in-a-jar/36100/msg/342436/view.html#msg342436

You can at least use it until you need something more sophisticated.

Just a question after peaking through your audio code.

Why do you do this?

public void play()
  {
    try {
      new Thread()
      {
        public void run()
        {
          Sound.this.clip.play();
        }
      }
      .start();
      Thread.sleep(1L); // <-- THIS
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

Paulscode sound system may also be worth looking into, but BurntPizza’s suggestion of TinySound is probably the way to go.

EDIT: Also, I really don’t think using the audio backend from Applets is the best solution, there are probably newer approaches just in the java subset that work better. (since the applet AudioClip class was in the original JDK1.0)

Thank you everyone, i will look into tinysound.

I only really used that code because it was basically copy/paste and i knew nothing about sound application.

EDIT: Should i play sound effects in a completely separate thread?

Quick tip with TinySound, really any such media interface: if the sound to be played is long (such as a soundtrack) then strongly consider streaming it rather than loading the whole thing into memory up front. See http://finnkuusisto.github.io/TinySound/ and the streamFromFile options in the load* methods in http://finnkuusisto.github.io/TinySound/doc/
Really easy to not know about this and suddenly wonder why your app is using several gigs of RAM.

Thanks for pointing this out, saves me a few headaches in the long run.

Now this is really newbie but im not sure how im supposed to import tinysound since theres no direct guide on it…

Add the TS jar into your project classpath, in eclipse this is the ‘build path.’ There are various equivalent ways of adding a jar to it: http://stackoverflow.com/questions/2727669/how-can-i-add-a-jar-to-my-build-path-in-eclipse

Now i can’t seem to play music without getting a nullpointer exception, im loading music based on the way i did it before. is something wrong?

public class Audio extends Applet implements Runnable
{
	public static Sound blockBreak = TinySound.loadSound("/sound/Break.wav");
	public static Sound gen = TinySound.loadSound("/sound/Gen.wav");
	public static Sound hurt = TinySound.loadSound("/sound/Hit.wav");
	public static Sound Jump = TinySound.loadSound("/sound/Jump.wav");
	public static Music GoodMorning = TinySound.loadMusic("/sound/TritonForge_Theme.wav");
	public static Music Sunset = TinySound.loadMusic("/sound/sunset.wav");
	private boolean isRunning;
	public void run() 
	{ 
		while(isRunning)
		{
			tick();
		}
	}
	private void tick() 
	{
		TinySound.init();
		if (GoodMorning.playing() == false)
		{
			GoodMorning.play(true, 0.5);
		}
		TinySound.shutdown();
	}
	public void start()
	{
		isRunning = true;
		new Thread(this).start();
	}
}

Check to see if your Sounds are null, quite easy to get the resource string wrong.
TS.init() and shutdown() should only happen once each, at beginning and end of app.

alright so i made it initialize at the start of the whole program, but it says Tinysound isnt initialized

Change this

public static Sound blockBreak = TinySound.loadSound("/sound/Break.wav");
   public static Sound gen = TinySound.loadSound("/sound/Gen.wav");
   public static Sound hurt = TinySound.loadSound("/sound/Hit.wav");
   public static Sound Jump = TinySound.loadSound("/sound/Jump.wav");
   public static Music GoodMorning = TinySound.loadMusic("/sound/TritonForge_Theme.wav");
   public static Music Sunset = TinySound.loadMusic("/sound/sunset.wav");

to this


public static Sound blockBreak, gen, hurt, Jump;
public static Music GoodMorning, Sunset;

static {
	TinySound.init();
	blockBreak = TinySound.loadSound("/sound/Break.wav");
   	gen = TinySound.loadSound("/sound/Gen.wav");
   	hurt = TinySound.loadSound("/sound/Hit.wav");
   	Jump = TinySound.loadSound("/sound/Jump.wav");
   	GoodMorning = TinySound.loadMusic("/sound/TritonForge_Theme.wav");
  	Sunset = TinySound.loadMusic("/sound/sunset.wav");
}

I think that you are calling TinySound.init after you try to load your sounds (they load right away)

It says all of this right in the few sentences of the TinySound.java docs:

[quote] In order to use the TinySound system, it must be initialized. After that, Music and Sound objects can be loaded and used. When finished with the TinySound system, it must be shutdown.
[/quote]

ahhh that makes sense. but now i can only get music to play when the run configuration is the Audio itself… do i need to add the applet to a frame?

EDIT: I took off the applet extend, but trying to get this to work is hard. I tried starting the thread like any other thread in my game but its not working super well.

Nevermind, i got it to work. Thank you to everyone!!