尝试使用 clip 在 java 8 中播放声音会抛出 java.lang.NullPointerException

Trying to play a sound in java 8 using clip is throwing java.lang.NullPointerException

提问人:Kayla Clayton 提问时间:7/18/2023 更新时间:8/13/2023 访问量:43

问:

我目前正在编写一个小游戏,并尝试实现背景音乐。我对 Java 中的视觉/音频很陌生,在网上做了一些研究后,我发现 Clip 将是一个与我制作图形的方式兼容的选项。因此,我遵循了有关如何设置/使用它的教程,从而产生了这个“声音”类:

import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.*;

public class Sound implements LineListener {
    
    boolean isPlaybackCompleted;
    int playMode;
    
    public Sound(int mode) {
        playMode = mode; // 0 = background music
    }
    
    @Override
    public void update(LineEvent event) {
        if (LineEvent.Type.START == event.getType()) {
            isPlaybackCompleted = false;
            System.out.println("Playback started.");
        } else if (LineEvent.Type.STOP == event.getType()) {
            isPlaybackCompleted = true;
            System.out.println("Playback completed.");
        }
    }
    
    public void playSound(String soundName) throws LineUnavailableException, IOException, UnsupportedAudioFileException {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("./Sounds/facilityIndoors.wav");
        AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);
        AudioFormat audioFormat = audioStream.getFormat();
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        Clip audioClip = (Clip) AudioSystem.getLine(info);
        audioClip.addLineListener(this);
        audioClip.open(audioStream);
        audioClip.start();
        switch(playMode){
        case 0:
            if(isPlaybackCompleted == true) {
                
            }
        }
        audioClip.close();
        audioStream.close();
    }
}

(请注意,playSound 的“soundName”参数是我希望稍后实现的,这样我就可以根据与当前地图名称共享的变量在轨道之间切换,并且当前未使用,我刚刚将路径硬编码为现在已经存在的文件以供测试)

我在我的主

        Sound music = new Sound(0);
        music.playSound(map.currentMap);

但是,当我尝试调用playSound函数时,此错误会抛出:

Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:209)
    at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1006)
    at Sound.playSound(Sound.java:37)
    at Program.main(Program.java:22)

起初我以为我拼错了文件路径,但仔细检查后我的拼写似乎是正确的,如下所示: 文件路径和文件名的图像 “Global Research FacilityJava8”是我的项目文件夹,我的图像引用似乎是从该级别开始的,所以也许 Clip 不是从项目文件夹开始的,这可能是问题所在, 但如果是,我不知道如何解决。

我尝试检查文件路径中的拼写错误,并尝试从一开始就省略一些符号(例如,只是“Sounds/facilityIndoors.wav”或“/Sounds/facilityIndoors.wav”),但错误仍然存在。在发布此内容之前检查可能的重复列表时,我还发现了一篇帖子,讨论将我所有的资源文件夹放入一个“资源”文件夹中并将其添加到构建路径中,我现在已经尝试过,但无济于事,仍然抛出相同的错误。(文件路径现在为“resources/Sounds/facilityIndoors.wav”)

java eclipse 音频 javasound

评论


答:

1赞 Grinding For Reputation 7/18/2023 #1

我遇到了同样的问题,但我没有找到解决它的方法,而是决定通过将音频文件复制到我 PC 上的某个位置来解决它。

尝试以下代码来复制文件

File audio = new File("C://somewhere//audio.wav").mkdir();
Files.copy(getClass().getResourceAsStream("resources/Sounds/facilityIndoors.wav"), Paths.get("C://somewhere//audio.wav"), StandardCopyOption.REPLACE_EXISTING);

现在只需像这样使用该文件audio

AudioInputStream audioStream = AudioSystem.getAudioInputStream(audio));
Clip audioClip  = AudioSystem.getClip();
audioClip.open(audioStream);

评论

0赞 Kayla Clayton 7/18/2023
它现在继续抛出错误,尽管我还没有导入它所说的 com.sun 类(或任何,据我所知)这是相关的还是不同的?Exception in thread "main" java.lang.ClassCastException: class com.sun.media.sound.DirectAudioDevice$DirectSDL cannot be cast to class javax.sound.sampled.Clip (com.sun.media.sound.DirectAudioDevice$DirectSDL and javax.sound.sampled.Clip are in module java.desktop of loader 'bootstrap') at Sound.playSound(Sound.java:35) at Program.main(Program.java:21)
0赞 Grinding For Reputation 7/18/2023
您能否包含代码行 ->(Sound 类的第 32 行)Sound.java:32
0赞 Kayla Clayton 7/19/2023
回想起来,我意识到我没有更改我的 Clip 实例化以匹配您的实例化,它来自我遵循的原始教程,该教程使用了 AudioFormat 和 DataLine,我现在已经更改了它,它已停止抛出任何错误。感谢您的帮助!
0赞 Grinding For Reputation 7/19/2023
欢迎您的光临!很高兴它起作用!
0赞 Phil Freihofner 8/13/2023 #2

获得正确的声音文件的地址通常很棘手。如果未在地址中指定起始“/”,则搜索是相对于 .setResource.getResourceAsStream 方法引用的类进行的。在您发布的内容中,您在保存该类的文件夹中是否有子文件夹 /Sounds?否则,将收到 null 错误。Sound

“/”作为地址的前缀应该从项目文件夹开始搜索,但我承认我对它到底是如何工作的有些模糊。(我通常即时生成声音而不是参考资源,所以我不经常使用它)。我认为,例如,基于 Maven 的项目使用 /src/main/resources 文件夹,而其他 Java 项目使用 /src但我必须对此进行测试才能确认。

它可能不再有任何区别,但作为旁注,我认为最好使用返回 的 .getResource() 而不是返回 .后者更挑剔,例如,如果底层文件不支持标记重置操作,AudioSystem.getAudioInputStream() 将拒绝。如果向 .getAudioInputStream() 提供 ,则不需要支持标记重置。如果比较重载,可以在 AudioSystem.getAudioStream() 的 API 中了解此内容。用作参数(第三个重载)通常不是一个好的选择,因为 Java 无法在 Jar 中找到文件。URLInputStreamInputStreamURLFile