2

我有以下代码可以在游戏中播放我的声音:

protected void playSound(final String sound, final int playTime){
        try {
            sounds.get(sound).open();
        } 
        catch(Exception e) {
            System.out.println(e);
        }
        new Thread(new Runnable() {
            public void run() {
                Clip actualClip = sounds.get(sound);
                actualClip.setFramePosition(0);
                if(playTime < 0){
                    actualClip.loop(Clip.LOOP_CONTINUOUSLY);
                }
                else{
                    actualClip.loop(playTime - 1);
                }
            }
        }).start();
    }

声音保存在哈希图中:

private HashMap<String, Clip> sounds;

当我“同时”播放两种不同的声音(相差 1 毫秒;))时,它们彼此平行播放;所以我可以同时听到两种声音。看起来像这样:

playSound("sound1", 1);
playSound("sound2", 1);

但是当我尝试两次播放相同的声音时,它不起作用:

playSound("sound1", 1);
//here its waiting in my programm
playSound("sound1", 1);

问题是,我想添加一个“死亡”声音——但两个暴徒也可以同时死亡,或者只是在另一秒之前死亡。当这种情况发生时,要么什么都没有发生,要么声音只播放一次。

为什么?我认为我在自己的线程中创建了同一文件的新 AudioClip?那么为什么它不起作用?

4

3 回答 3

1

首先,您能否调试该方法以显示是否播放了“声音”以确保它没有重叠,这样您就无法听到是否实际上同时播放了相同的声音?

我认为这里可能发生的是,在播放 SAME 剪辑时,其中一个线程将尝试访问另一个线程当前正在访问的相同数据,从而导致您描述的错误。您可能想研究 Java 中的同步。

于 2013-08-10T17:19:29.650 回答
0

当您播放相同的声音两次时,音量会更大吗?在完全相同的时间播放确切的声音与将单个声音的幅度加倍相同。我认为当两个相同的声音靠在一起播放时,您在聆听时可能无法听到单独的声音。

于 2013-08-10T23:55:47.183 回答
0

原因很简单:阅读Clip.play(). 它明确指出,无论何时播放正在进行,该方法都不会做任何事情。Javadoc ofsetFramePosition说“当剪辑下一次开始播放时,它将从在此位置播放帧开始。” 因此,它不能保证帧指针在请求时立即移动;它只是说,每当下次播放剪辑时,指针就会位于您想要的位置。

Clip 在内部使用 InputStream,它将在播放时指向当前音频帧。如果有两个请求,该指针应该做什么Clip.play()?开发人员选择什么都不做,这是一个很好的设计选择,因为它比播放随机音频帧更可取,因为并行访问相同的输入流。

解决方案:对于每个播放音频的请求,构造一个新的Clip并提供一个新的InputStream(包装成一个AudioInputStream)。它还减少了额外的工作,例如重置帧指针,因为您Clip只使用 a 播放一次。

为了提高效率,请读取一次音频文件并将其存储到byte[]. ByteArrayInputStream然后,使用它构建一个byte[]并将其输入到一个新剪辑中。这样您就不需要磁盘访问,因为您直接从内存中读取音频数据。

byte[] arr = ...;                 // audio data (e.g. read from disk)
Clip clip = AudioSystem.getClip();
ByteArrayInputStream bis = new ByteArrayInputStream(arr);
AudioInputStream ais = AudioSystem.getAudioInputStream(bis);
clip.open(ais);
clip.start();

请注意,资源也需要清理,示例中未显示。

于 2021-07-09T13:28:41.713 回答