Clip plays WAV file with bad lag in Java

2020-07-18 09:47发布

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();
    }
}

2条回答
聊天终结者
2楼-- · 2020-07-18 10:09

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?
查看更多
虎瘦雄心在
3楼-- · 2020-07-18 10:17

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.

查看更多
登录 后发表回答