我有以下代码在游戏中播放我的声音:
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 ms;)),它们彼此平行播放;所以我可以在同一时间听到两个声音。看起来像这样:
playSound("sound1", 1);
playSound("sound2", 1);
但是当我尝试两次播放相同的声音时,它不起作用:
playSound("sound1", 1);
//here its waiting in my programm
playSound("sound1", 1);
问题是,我想添加一个“死亡”声音 - 但是两个怪物也可以在同一时间死亡,或者只是一秒钟死亡。当发生这种情况时,要么没有任何反应,要么声音只播放一次。
为什么呢?我想我在自己的线程中创建一个相同文件的新AudioClip?那为什么它不工作呢?
答案 0 :(得分:1)
首先,您可以调试方法以显示是否发出声音&#39;是为了确保它不重叠,所以你不能听到是否真的同时播放了相同的声音?
我认为可能在这里发生的是,在播放SAME剪辑时,其中一个线程将尝试访问另一个线程当前正在访问的相同数据,从而导致您正在描述的错误。您可能希望在Java中查看同步。
答案 1 :(得分:0)
当您演奏两次相同的声音时,音量会大一些吗?在完全相同的时间播放精确的声音与将单个声音的振幅加倍相同。我认为两个相同的声音在一起播放时听起来可能无法听到个别声音。
答案 2 :(得分:0)
原因很简单:阅读Clip.play()
的Javadoc。它清楚地表明,无论何时播放,该方法都不会执行任何操作。 setFramePosition
的 Javadoc 说“当剪辑下次开始播放时,它将从在此位置播放帧开始。”因此,它不能保证帧指针在请求时立即移动;它只说指针将在您想要的位置,无论何时播放剪辑。
Clip 在内部使用 InputStream,它将在播放时指向当前的音频帧。如果向 Clip.play()
发出两个请求,该指针应该做什么?开发人员选择什么都不做,这是一个很好的设计选择,因为它比播放随机音频帧更受欢迎,因为它可以并行访问相同的输入流。
解决方案:对于每个播放音频的请求,构造一个新的 Clip
并为其提供一个新的 InputStream
(包装成一个 AudioInputStream
)。它还减少了额外的工作,例如重置帧指针,因为您使用 Clip
只播放一次。
为了提高效率,请读取音频文件一次并将其存储到 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();
注意资源也需要清理,这在示例中没有显示。