【问题标题】:Java - playing the same sound multiple times at onceJava - 一次多次播放相同的声音
【发布时间】:2015-03-05 22:19:31
【问题描述】:

我正在开发一款游戏,但我在多次播放相同的声音时遇到了一些问题,就像您激活一个已经在播放的声音一样,它不应该取消第一个声音。我在 Stackoverflow 上找到的解决方案是将其读入字节数组,我采用以下方式:

public SoundObject(AudioInputStream audioIn) {

    try {
        af = audioIn.getFormat();
        size = (int) (af.getFrameSize() * audioIn.getFrameLength());
        audio = new byte[size];
        info = new DataLine.Info(Clip.class, af, size);
        audioIn.read(audio, 0, size);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void playSound() {
    try {
        Clip localSound = (Clip) AudioSystem.getLine(info);
        localSound.open(af, audio, 0, size);
        localSound.start();
    } catch (LineUnavailableException e) {
        e.printStackTrace();
    }

}

直到现在我试图将它导出到一个 jar 文件中,这一直运行良好,jar 文件由于某种原因在播放字节数组时出现问题,导致声音在几毫秒后被切断,我设法找到了一个发布同样的问题,有人提出了以下解决方案:

    public SoundObject(String filePath) {
    try {
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(Loader.class.getResource(filePath));
        clip = AudioSystem.getClip();
        clip.open(audioInputStream);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (LineUnavailableException e) {
        e.printStackTrace();
    } catch (UnsupportedAudioFileException e) {
        e.printStackTrace();
    }
}

// Play the sound in a separate thread.
public void playSound() {
    Runnable soundPlayer = new Runnable() {

        @Override
        public void run() {
            try {
                clip.setMicrosecondPosition(0);
                clip.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    new Thread(soundPlayer).start();
}

使用第二种方法适用于 jar 文件,但问题是声音播放不如以前好,我有一个拍摄功能,如果你拍摄得非常快,这种方法并不总是能接受当我按空格射击时,有时无法播放声音。因此,对于这 2 种解决方案,我必须从不可靠的声音中做出选择,或者我将无法将其导出到可运行的 JAR。

有人遇到过这类问题吗?

编辑:这是一个向您展示 2 个罐子如何工作的剪辑:https://www.youtube.com/watch?v=wZPOIhHZSJM&

【问题讨论】:

    标签: audio


    【解决方案1】:

    我建议尝试 TinySound 库。它是免费代码,可在 github 上找到。这段代码提供了一个最小的混音器,并且可以同时播放剪辑。

    我很难弄清楚您的代码可能出了什么问题。我还制作了一个在游戏中使用的混音器,它支持 Clips 的并发播放。我将声音存储为 -1 到 1 之间的浮点数。每个播放实例从一个预制池(限制并发播放的数量)中获取一个光标,该光标跟踪浮点数组中的位置,并在此期间进行查询和递增循环将各种声音加在一起(简单加法)并转换为通过 SourceDataLine 输出的字节。如果你决定走那条路,这就是基本计划。

    通过创建线程池并让声音尽可能接近在被调用时准备好播放,您可能会在第二次设置中获得更高的效率。使用混音器,您只需要一个线程来处理音频。

    第一个例子有什么错误吗?从给出的代码中,我看不出为什么声音会由于使用罐子而被切断。是什么东西切断了它们,例如另一种声音,还是调用线程的结束?

    【讨论】:

    • 感谢您的回复。我不太明白你的混音器是如何工作的,声音是我遇到最多的问题,这两个解决方案都是在网上找到的,我只是修改了它们以在我的程序中工作。您对如何为我的示例设置线程池有任何想法吗?最后,我认为我的第一个示例中没有任何问题,它运行良好,直到我决定现在创建一个 jar 文件并分享它。我真的不明白为什么在罐子里使用它时它会被切断,因为它仍然通过剪辑播放。
    • 我录制了一个剪辑来向您展示区别:youtube.com/watch?v=wZPOIhHZSJM& 第一个是字节数组,第二个是线程方法,正如我在拍摄时所听到的那样按钮它听起来不像它的声音。当我在 Eclipse 中使用字节数组时,它听起来完美无缺。
    • 整洁!我分不清谁是头。特别是有人吗?我从 Goetz 的“Java Concurrency in Practice”中了解了线程池。好书,但对于我们这些只有几年经验的人来说很难读。我敢打赌,有一个 Java 教程部分,或者一个教程站点,可以帮助您了解执行器服务或线程池的主题。要调试 Eclipse/Jar 问题,请尝试一些 println 并将它们包含在 jar 中:例如,在加载后验证声音文件的大小,以及使用 start() 命令在块中。发现问题后即可取出。
    • 我在 playsound 部分加载之后和开始之前添加了以下内容: System.out.println(localSound.getFrameLength());他们在通过 jar 和通过 Eclipse 播放时打印相同大小的帧长度,这让我更加困惑:/ 有没有其他尺寸我可以测试或者还有什么问题?头部实际上是瑞典国王哈哈,我和我的朋友已经养成了在我们得到合适的精灵之前使用那个精灵作为我们项目的占位符的习惯。
    • 我基本上会尝试验证所有假设,例如,所有变量(大小、音频、af)在两种情况下都是相同的。也许(长镜头)Eclipse 正在加载与 Jar 中使用的音频文件不同的音频文件? (数据转储是否相同?)通过制作显示此错误的最简单的程序来“排除故障”。这可能是一些代码,它只是单个爆炸的回放,一个在 Eclipse 中,然后是一个 jar。这很神秘,至少可以这么说!也许重新考虑使用 TinySound。在 java-gaming.org 上有一些关于它的好帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多