0

I've looked around the internet on ways to play wav files, but I have found that they do not play on a separate thread and so cause the program to halt until the song is done, which does not work for a game. However, when I try to play everything on a separate thread, it lags. Does anyone have a fix for this?

Note: I also am painting on to the background continuously:

public class DrawThread extends Thread {

    JFrame j;

    public DrawThread(JFrame frame) {
        j = frame;
    }

    public void run() {
        while (!(isInterrupted())) {
            if (j.isDisplayable() && j.isActive() && j.isEnabled())
            j.update(j.getGraphics());
        }
    }

}

and update just calls paint which is:

public void paint(Graphics g) {
            Graphics2D bg = (Graphics2D) g;
    bg.setBackground(Color.black);
    int w = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
    int h = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
    if (time < 500) {
        x[time] = r.nextInt(w) + 150;
        y[time] = h;
        z[time] = r.nextInt(w) + 150;
        time++;
    }
    for (int i = 0; i < time; i++) {
        y[i] -= forward;
        x[i] -= right;
        if (y[i] < 1) {
            x[i] = r.nextInt(400) - 200;
            y[i] = 300;
            z[i] = r.nextInt(400) - 200;
        } else if (y[i] > 300) {
            x[i] = r.nextInt(400) - 200;
            y[i] = 1;
            z[i] = r.nextInt(400) - 200;
        }
        if (x[i] > 200)
            x[i] = -200;
        else if (x[i] < -200)
            x[i] = 200;
        bg.setColor(color);
        bg.drawLine(
                getWidth() / 2 + (int) Math.round(x[i] * 200 / y[i]),
                getHeight() / 2 + (int) Math.round(z[i] * 200 / y[i]),
                getWidth()
                        / 2
                        + (int) Math.round((x[i] + right) * 200
                                / Math.abs(y[i] + forward)),
                getHeight()
                        / 2
                        + (int) Math.round((z[i]) * 200
                                / Math.abs(y[i] + forward)));
    }
}

EDit: Adding the music player class I'm using (I've switched to BigClip):

import java.io.File;
import java.util.Collection;
import java.util.HashMap;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import org.crystalix.util.SoundListener;

public class MSHandler {
public static boolean pause = false;
public static boolean stop = false;
private static HashMap<String, BigClip> clips = new HashMap<String, BigClip>();

public static void stopAll() {
    Collection<BigClip> c = clips.values();
    for (BigClip b : c) {
        System.out.println("Stopping "+b.toString());
        b.stop();
        System.out.println("Stopped "+b.toString());
    }
}

public static void playMusic(File file) {
    try {
        AudioInputStream audioIn = AudioSystem.getAudioInputStream(file);
        BigClip clip = new BigClip();
        clip.open(audioIn);
        clip.addLineListener(new SoundListener());
        clip.loop(1);
        clip.start();
        clips.put(file.getName(), clip);
    } catch (Exception e) {
        System.err.println("Sound could not be started!");
        e.printStackTrace(System.err);
    }
}
}
Octavia Togami
  • 4,186
  • 4
  • 31
  • 49
  • 1) `j.update(j.getGraphics());` Don't do that. It is likely causing many other problems. 2) For better help sooner, post an [SSCCE](http://sscce.org/). 3) Use a `Clip` for the sound, as seen in the [Java Sound tag Wiki](http://stackoverflow.com/tags/javasound/info). – Andrew Thompson Nov 24 '12 at 15:02
  • How would you suggest I try to paint as often as possible? That's the only way I could find to make it paint repeatedly, as it doesn't do it by default. Also, the file is music, not sound so Clip doesn't work because it's too big. I actually used Clip and it failed. – Octavia Togami Nov 24 '12 at 16:52
  • *"How would you suggest I try to paint as often as possible?"* Use a language that interfaces directly with the video card. *"..it's too big. I actually used Clip and it failed"* In that case, use [`BigClip`](http://stackoverflow.com/a/5668510/418556). – Andrew Thompson Nov 24 '12 at 22:31
  • Ok, will try BigClip. Any suggestions on an API to use besides LWJGL for interfacing to the graphics card with Java? I need to use Java because I don't have another choice. – Octavia Togami Nov 24 '12 at 23:29
  • EDIT: Thread.join() waits indefinitely for some reason, any fix? – Octavia Togami Nov 25 '12 at 00:21

1 Answers1

0

You haven't shown the code you are using for the wav file playback. That makes it a bit hard to diagnose what might be going wrong!

1) The wav should simply be on its own thread. If you do so correctly, it will not block anything else. The Java sound tutorials don't do a particularly good job of pointing this out. So: put the code that calls the wav playback in its own runnable and you should be okay.

2) You can "open" the wav prior to the time when you wish to play it. Then, it should "start" right away when you finally tell it to go.

Another note: the code that plays back a wav file runs more quickly if it is already in memory. So, sometimes the first wav playback only starts after a slight hesitation. But it is possible to combat this by playing another sound at zero volume to get the sound playback code into memory. I often do this at the start of programs that have sound.

The continuous painting in the background is only an issue if you are using up so many cpus that the JVM doesn't have time to process the sound. I'd really be surprised if that was the issue. If it were, what you'd probably hear is the sound playback with lots of clicks in it.

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
  • I put the code that plays the wav files in the question. The problem I experience is that the sound cuts out and jumps around at some points, then smoothes out, and then starts jumping again. – Octavia Togami Nov 25 '12 at 15:17
  • Cutting in and out usually results from not feeding audio data to the output line quickly enough to keep up with playback. Try using SourceDataLine for your wav file, not BigClip which needs lots of RAM. Maybe BigClip, if used in the wrong circumstances triggers page swapping? Also put the playback in its own thread. I don't see where you are doing that yet. I would try running the sound on its own, to make sure you have it set up correctly, then start adding the graphics and see when it breaks down. Your graphics may simply be consuming too much cpu to allow concurrent sound. – Phil Freihofner Nov 26 '12 at 23:32
  • Is it Andrew's BigClip? If so, it uses SourceDataLine and it starts a new Thread. – Octavia Togami Nov 27 '12 at 01:58
  • OK, you are trying to troubleshoot a problem, right? When trouble-shooting, one tries to simplify things, not add complications. The most basic playback of a wav is to read it via an ais and output it via an sdl, and do so on its own thread to allow other elements to keep running. Do you know how to do this? If I understand the BigClip, it loads an entire wav into memory before playback. If it's 30 seconds long, you are consuming 30 * 44100 * 2 * 2 bytes = 53 MB. How long is your wav? How much RAM do you have? When does page-swapping kick in? Page swapping will make the sound intermittant. – Phil Freihofner Nov 27 '12 at 09:10
  • I don't know what page swapping is, but this problem also exists when using sdl and ais. I did start it on a new thread – Octavia Togami Nov 27 '12 at 14:34
  • Also, the file is about 1:36 sec. and I have 5 GB of RAM. – Octavia Togami Nov 27 '12 at 14:44
  • Page swapping is when cpu uses hard disk space as virtual memory because it runs out of RAM. With 5GB of RAM, perhaps 150MB of audio consuming that RAM is not an issue. Are you able to run the audio without problem when the background graphics are not running? Is there a way to run only a fraction of your graphics and test the audio? I am looking at your graphics--are you only doing a background clear and line draws? That shouldn't cause a problem. Maybe the problem is the while loop or the 'get graphics' as was suggested earlier. – Phil Freihofner Nov 27 '12 at 18:46
  • Most folks use either a "game loop" (a while loop with a thread.sleep() amount) or a util.Timer to trigger the graphics redraw at a rate of maybe 60 frames per second. Your graphics while loop could be hogging the cpu. You might try adding a small amount of sleep, like 5 or 10 msecs and see if that helps. The loop can be fine tuned later to make the sleep amount variable. – Phil Freihofner Nov 27 '12 at 18:50
  • I can run the program without the audio problems when the drawing is deactivated. – Octavia Togami Nov 27 '12 at 22:58
  • I edited the loop to grab the graphics var before the loop and added a delay of 20 milli., but it still jitters. I'm going to stop using BigClip, because it is still messed up with a delay of 2000 milli. – Octavia Togami Nov 28 '12 at 14:05