1

我有一个 Sound 类,其中包含一个方法,当调用该方法时,该方法使用 Clip 对象(在本例中为clip)播放声音。

public static void play() {
    clip.stop();                // The purpose of the first three lines
    clip.flush();               // is to restart the Clip object so it
    clip.setFramePosition(0);   // can be played multiple times.
    clip.start();
}

Clip 对象的实例化发生在一个单独的静态方法中,该方法在此方法之前调用,这就是上述方法可以声明为静态的原因。

另一个实现的类KeyListener包含以下代码:

public void keyPressed(KeyEvent e) {
    Sound.play(); // Sound is the class that implements the previous method.
}

因此,我的代码应该播放与clip每次按下键相关的声音。但是,如果我快速反复按下某个键,声音有时会不播放。这在一段时间后尤其明显(似乎每次按键后问题都会变得更糟)。

为什么会发生这种情况,我该如何规避这个问题?

4

2 回答 2

1

我过去也遇到过同样的问题,对我有用的东西是在一行完成时添加一个线路监听器,然后关闭它。

下面的代码是我使用的精简版:

music = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.getAudioInputStream(Sound.class.getResource("/sounds" + filename));
music.open(ais);

music.addLineListener(new LineListener(){
    public void update(LineEvent e){
        if(e.getType() == LineEvent.Type.STOP){
            e.getLine().close();
        }
    }
});

music.start();

创建剪辑时,只需添加线路侦听器。当您使用播放功能重置剪辑时,它应该可以正常播放。我希望这对你有用!

于 2015-05-06T16:41:32.910 回答
0

我是通过类似问题中的参考资料看到这篇文章的。

是的,一次播放的剪辑数量会导致延迟,但我不知道如何预测它会产生多大的影响,因为这取决于 JVM 与操作系统的交互方式。

您可以通过减小剪辑的缓冲区大小来帮助解决这种情况。SourceDataLine 和 Clip 似乎都只允许在缓冲区边界与传入请求进行交互(我不确定这是 100% 准确的声明)。指定剪辑的缓冲区大小有点迂回,因为它需要以 PCM 数组的形式获取数据。但是,如果您想尝试一下,API 就在这里

减少行数的一个好方法是使用像TinySound这样的声音库。Java-gaming.org的许多程序员都成功地使用了这个库。

我正在推广的另一种选择是AudioCue,这是我最近为并发Clip播放编写的一个类。许可证是 BCD,提供源代码,因此请随意检查、修改和使用代码。AudioCue不会减少输出线的数量(还)。但是,如果您正在做管理同一提示的多个副本的常见事情,那么在这方面它可能会有所帮助,因为所有并发实例都被混合为单个输出。基本原理:文件被加载到一个数组中,并通过游标播放,游标遍历数组并将其输出合并到一个SourceDataLine. 此设置还允许实现平滑、实时的音量、声像和音调衰减。

于 2017-07-19T17:36:34.253 回答