I'm trying to load background music into my game that is like three and a half minutes long. I'm getting an "OutOfMemoryError: Java heap space" when I try to load the game. Is there any way to actually stream it instead of having to load the whole music sample into memory? I can always increase the allocation limit, but I'd rather get more bang for my buck.
darkfrog
Okay, since there has been no response on this post and everything I've read suggests that LWJGL currently does not support any method of playing massive audio samples I decided to use the internal Java sound system. For your coding pleasure, here is what I've come up with as the solution to playing massive audio samples in my games, it does real audio streaming based on the buffer you set, allows for multiple audio files to be enqueued, handles repeats, executes in its own thread and in my test showed little to no reduction in my game speed or choppiness of the sound playing no matter what I did in the game, and the only big disadvantage is that it doesn't seem to support OGG or some other formats. I converted to a basic WAV file and it works great, so I'm happy.
/*
* Created on Jan 8, 2006
*/
package com.captiveimagination.jme;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.sound.sampled.*;
/**
* @author Matthew D. Hicks
*/
public class BackgroundMusicPlayer extends Thread {
private int buffer;
private boolean repeat;
private boolean keepAlive;
private ArrayList tracks;
public BackgroundMusicPlayer(int buffer, boolean repeat) {
this.buffer = buffer;
this.repeat = repeat;
keepAlive = true;
tracks = new ArrayList();
}
public void run() {
while (keepAlive) {
try {
AudioInputStream ais = getNextTrack();
if (ais != null) {
AudioFormat af = ais.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
line.open(af);
line.start();
int len;
byte[] buf = new byte[buffer];
while ((len = ais.read(buf, 0, buf.length)) != -1) {
line.write(buf, 0, len);
}
line.drain();
line.close();
}
Thread.sleep(50);
} catch(LineUnavailableException exc) {
exc.printStackTrace();
} catch(IOException exc) {
exc.printStackTrace();
} catch(InterruptedException exc) {
exc.printStackTrace();
} catch(UnsupportedAudioFileException exc) {
exc.printStackTrace();
}
}
}
public AudioInputStream getNextTrack() throws IOException, UnsupportedAudioFileException {
AudioInputStream ais = null;
if (tracks.size() > 0) {
Object o = tracks.get(0);
if (o instanceof URL) {
ais = AudioSystem.getAudioInputStream((URL)tracks.get(0));
} else if (o instanceof File) {
ais = AudioSystem.getAudioInputStream((File)tracks.get(0));
}
tracks.remove(0);
if (repeat) {
tracks.add(o);
}
}
return ais;
}
public void addTrack(File file) {
tracks.add(file);
}
public void addTrack(URL url) {
tracks.add(url);
}
}
Let me know if you have any questions.
darkfrog
Maybe I missed something here but isn't that what the stream stuff in jmex.sound is for?
I have been unable to figure out how to make it actually "stream" instead of loading the entire thing up into memory. Every time I try to stream it with jME it throws an OutOfMemoryError. That's why I posed my question here to see if anyone knows a way around that, but since I got no response I went for the custom solution. :o
darkfrog
seems like there is a boolean for "load into memory"? I'm not spenind any time looking deeper at the code so maybe it's broken…
Well, I'll look at that method, but it requires you pass in the filename as a String and I have to be able to reference it via URL. If I can get that method to work then I'll look at the source and see how difficult it would be to add another entry that takes a URL.
Thanks,
darkfrog
renanse said:
seems like there is a boolean for "load into memory"? I'm not spenind any time looking deeper at the code so maybe it's broken...
Yeah, I'm pretty sure Arman said that it didn't actually do anything -- it was just there because he planned on implementing streaming.
hehe, well I'll verify that tonight hopefully, but if that's the case…ARGH! :-p
It would be nice if I could use OGG files in my game.
darkfrog
FYI, here's the quote I was talking about:
http://www.jmonkeyengine.com/jmeforum/index.php?topic=1741.0
Doh, I may end up writing the support for this myself as I believe I know how now, but I may just stick with this little snippet I've already written for now. The bad thing is that I'm having to drop an uncompressed WAV file into my game to do it this way.
Thanks for the info Per.
darkfrog
streaming oggs from an url is really needed!
Agreed. I think for the sake of the download size of my game before I release I'm going to have to add support for OGGs and I'll make sure to share if something hasn't been done for it in jME by that time.
darkfrog
I noticed some checkins from Arman these days - so maybe he's back working on sound support . . .
That sneaky little guy. :o
Great, I look forward to seeing this implemented in jME.
darkfrog
he made stop and delete methods available from the soundsystem class, which i needed for cleanup on program exit, otherwise it crasched…
i hacked in stream loading using an url into jme, it took 2 minutes, and worked great…needed that for loading oggs from a jar-file…could send that to someone for addition to the cvs…
- cough *
- cough *
:-p
darkfrog
If it's too big to post, you can put a link to a file, or mail it. If it has a testcase that works on jME CVS I'll see if I can get it in tommorow. If it's not too much trouble, you can also create an issue: https://jme.dev.java.net/servlets/ProjectIssues
hehe sure i'll post it as soon as i get to work tomorrow, but i mean, it's just copy and paste the usual streamloading methods, and put an URL insteand of String file as input…and doing url.openstream instead of fileinputstream(filestring)…
I would be pleased to add your code in cvs
gimme tilll tomorrow