使用 java.sound.sampled.Clip 播放声音文件的正确方法是什么

What is the correct way to play a sound file using java.sound.sampled.Clip

我已经阅读了很多关于此主题的 SoF 线程和其他网站,但其中 none 对我有用,所以我再次提问,希望得到量身定制的答案。

我的罐子里有一个 .WAV 文件,我想播放它,但我得到 NullPointerException. 我尝试了很多方法,甚至通过绝对路径在 jar 外播放文件,但我得到了相同的结果。 这是播放声音的函数

public void gimli(){
        try {
            Clip clip;
             AudioInputStream  stream = AudioSystem.getAudioInputStream(this.getClass().getResource(Utils.class.getResourceAsStream("gimlilaught.wav").toString()));
   AudioFormat format = stream.getFormat();
    DataLine.Info info = new DataLine.Info(Clip.class, format);
  clip = (Clip)AudioSystem.getLine(info);
    clip.open(stream);
    clip.start();
}catch(Exception ex){
ex.printStackTrace(System.out);
}

感谢您的尝试。

我昨晚正在尝试这个,似乎对我有用的是:

try {
            File filePath = new File(audioLocation);

            if (filePath.exists()) {
                AudioInputStream audioInput = AudioSystem.getAudioInputStream(filePath);
                Clip clip = AudioSystem.getClip();
                clip.open(audioInput);
                FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
                gainControl.setValue(getVolume());
                clip.loop(Clip.LOOP_CONTINUOUSLY);
                clip.start();
            } else {
                System.out.println("Incorrect audio file path!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

虽然我认为我应该在某处安装 clip.open() 并且我在停止和从另一个 class 启动音频时遇到问题,但它确实可以播放声音。

需要一个 AudioInputStream 作为打开 Clip 的参数。查看 API,您会看到 AudioSystem.getAudioInputStream(InputStream) or AudioSystem.getAudioInputStream(URL) 中的任一个都可用于获取 AudioInputStream

Class有两种服务方式:getResource(String)getResourceAsStream(String)getResource 方法将 return 一个 URLgetResourceAsStream 方法将 return 一个 InputStream.

我更喜欢使用 URL 形式,因为它更宽容。使用 AudioSystem.getAudioInputStream(InputStream) 时,如果文件不支持 标记 [=68],则 IOException 将被 returned =] 和 重置 。方法AudioSystem.getAudioInputStream(URL)规避了这个要求。

此外,您应该知道 URLFile 不同,可用于识别 jar 中的文件。

你也必须小心设置相对地址。我通常喜欢有一个 /res 文件或 /audio 文件来保存要加载的 .wav。例如,如果 /res 是并行文件夹或“res/myAudio.wav" 如果 /res 是子文件夹,相对于 中使用的 class 的位置getResource 方法。

这是一个简单的工作示例,其中音频文件位于子文件夹中,/res:

private static void loadAndPlayClip() throws UnsupportedAudioFileException, 
        IOException, LineUnavailableException, InterruptedException
{
    String filename = "a3.wav";
    URL url = BasicClipExample.class.getResource("res/" + filename);
    AudioInputStream ais = AudioSystem.getAudioInputStream(url);
    DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
    Clip clip = (Clip) AudioSystem.getLine(info);
    clip.open(ais);

    clip.start();
    Thread.sleep(7000); // Duration should match length of audio file.
    clip.close();
}

虽然这个例子应该有效,但它不应该按原样用于生产,原因有二。

  1. Thread.sleep() 命令会暂停主线程,这通常是不需要也不需要的。系统为 Clip 回放创建的线程是 daemon 线程。 守护进程 线程不会阻止程序完成和关闭。在这个简单的 "fire and forget" 示例中,主线程很快完成,因此如果我们不通过休眠间隔来延缓完成,程序将立即关闭。

  2. Clip 的初始加载和 Clip 的播放通常以两种不同的方法完成。 Clip 专为可以方便地保存在内存中的音频而设计,无需重新加载即可重播。如果您使用每个播放命令重新加载 Clip,您将同时重做不需要的工作并增加延迟,因为剪辑在完全加载之前不会开始播放。如果音频文件不方便保存在内存中(例如,由于持续时间长而导致的大文件),首选方法是使用 SourceDataLine.

  3. 播放它