4

I've written a code that read a WAV file (size is about 80 mb) and plays that. The problem is that sound plays badly (extreme lags). Can you please tell me what's the problem?

Here's my code: (I call the doPlay function inside a Jframe constructor)

private void doPlay(final String path) {
    try {
        stopPlay();
        InputStream is = new FileInputStream(path);
        InputStream bufferedIn = new BufferedInputStream(is);
        AudioInputStream ais = AudioSystem.getAudioInputStream(bufferedIn);
        AudioFormat format = ais.getFormat();
        // this is the value of format.
        // PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian
        DataLine.Info info = new DataLine.Info(Clip.class, format);
        clip = (Clip)AudioSystem.getLine(info);
        clip.open(ais);
        clip.start();
    } catch (Exception e) {
        stopPlay();
        e.printStackTrace();
    }
}
Radiodef
  • 37,180
  • 14
  • 90
  • 125
Alireza Farahani
  • 2,238
  • 3
  • 30
  • 54

2 Answers2

8

The problem is that you need to load the Clip prior to playing it. Clips are loaded into memory completely before they can be played.

In other words, everything up to clip.open() should occur well before it is time to play the clip. When you are ready to play the Clip, the only command you should use is clip.start(). To replay the clip, set its cursor position back to the start and call clip.start().

If a Clip is short enough, you can get away with the inefficient coding practice of opening them (loading them) at the same time as when you play them. If you really want to play from a file instead of from memory, use SourceDataLine, and it will start much faster than the Clip will for larger files.

Clip: has to be loaded into memory before it can play, once loaded, it plays with minimal cpu. Designed for small, and reused sound files.

SourceDataLine: plays from file location, starts immediately, consumes very little memory (much less than Clip) but uses slightly more cpu than Clip because of the file reading. Best for larger and single-play audio.

Another source of LAG: first time a sound file is called, it runs a little slower because of executing from compiled code. With reuse, the sound code is put into memory and executes with minimal lag. Thus, sometimes I play a "silent" sound at the start of a program to "prime the pump" so that when the first sound that needs to be heard plays, it plays with less lag.

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
3

Actually your code should work fine (tested it from inside a JFrame constructor with an +80mb audio file), so I can only give a few suggestions:

  1. Did you try your code with a different audio file and with a different audio format (e.g. aiff) to see if this makes any difference? Also try your code with an audio file of smaller size.
  2. When using the Clip class, the audio data gets loaded into memory. Do you certainly have enough available memory for the whole file? Did you try increasing the JVM heap size?
  3. Does your code involve any other background threads/computations, that could potentially result in too much cpu workload?
Community
  • 1
  • 1
Balder
  • 8,623
  • 4
  • 39
  • 61
  • yes, the code draws nearly 100 object every 0.1 second concurrently – Alireza Farahani Feb 19 '14 at 12:20
  • Then I would suggest to remove the drawing of the objects from your code to see if this solves the problem. If it does, then the lag will likely have nothing to do with your audio playback but instead with your Object drawing code. – Balder Feb 19 '14 at 12:43
  • The problem was size of the file. With smaller file the code works fine. But why your code worked with same size file? – Alireza Farahani Feb 20 '14 at 01:48
  • Hard to tell without having a look at the file and the rest of your code. What are your computer specifications? I tested it on a rather old computer with Windows XP, 2.7 GHz, 2 GB ram, and JRE 7 from within Eclipse. Do other audio files of the same size also cause the lag or is it just this file? – Balder Feb 20 '14 at 06:02
  • I also added the complete code I used for testing - have a look if the lag also occurs with this simplified code. – Balder Feb 20 '14 at 06:08
  • This answer misses the distinction between Clips and SourceDataLines, and appears to advocate a very inefficient way of playing Clips. Clips were designed to be loaded prior to use, not at the time of playback. – Phil Freihofner Feb 21 '14 at 10:15
  • @Phil +1 for your own answer - I didn't know, that a clip would start playback while it is still being loaded. I just wanted to give the OP some feedback because no one else did until yet. The code I posted in the edit was just the one I used for testing his own code - I removed it again. – Balder Feb 22 '14 at 06:05
  • @Balder - Thanks! I think it is good to be self-critical and to try and present the best solutions for those who follow. I should confess, too, that I had the very same misconception about Clips, not realizing the loading cost, and it took several months to figure it out. – Phil Freihofner Feb 23 '14 at 02:04