java - 音频剪辑偶尔无法播放

标签 java audio

我使用以下代码创建了一个音频剪辑 ( javax.sound.sampled.Clip ):

public Clip getClip() throws Exception {
    AudioInputStream in = AudioSystem.getAudioInputStream(getClass().getResource("test.wav"));
    Clip clip = AudioSystem.getClip();
    clip.open(in);
    return clip;
}
...
this.clip = getClip();

我反复触发 the clip 的播放与:

public void play() {
    clip.stop();
    clip.flush();
    clip.setFramePosition(0);
    clip.start();
}

我正在通过使用 JFrame 并在每次按键时调用 play() 来对此进行测试 ( full test class here )。大多数情况下,每次按键都会发出声音,无论按键速度有多快。但有时,当快速连续按下按键时,声音会跳过其中一个按键,根本不会播放。这是在游戏中实现的,因此一致的声音播放非常重要。

研究这个问题让我想到 this question ,建议每次播放结束时关闭该行,如下所示:

clip.addLineListener(e -> {
    if (e.getType() == LineEvent.Type.STOP) e.getLine().close();
});

但是在第一次之后就完全停止了播放。

我尝试过的其他事情:

我测试了几台电脑,这个问题在高端电脑上似乎不太突出,或者至少不太明显。如果是这样的话,有什么办法可以提高低端系统上的播放一致性吗?如果这里的问题是实现,那么实现这个问题的正确方法是什么?

最佳答案

Clip 可能无法提供您所需的粒度级别。我认为 Clip 在这方面没有任何特殊要求。如果缓冲区大小太大,SourceDataLine 将阻塞,因此 Clip 可能会发生类似的情况,但 Clip 不会。 t 让您指定内部缓冲区大小。

如果是我,我会使用 SourceDataLine 编写自己的 Clip 类对象,这样我就可以指定一个特定的缓冲区大小,可能是一个大约写入的缓冲区大小与游戏相同或部分帧速率。

int bytesPerSecond = (int) fmt.getSampleRate()
                         * fmt.getFrameSize();
int targetGameFPS  = 30;
int bufferSize     = bytesPerSecond / targetGameFPS;

请注意,使用的缓冲区可能会导致在速度较慢的计算机上出现点击或撕裂等问题。

然后您一定要调用 sourceDataLine.open(audioFmt, bufferSize)具有此缓冲区大小。

缺点是您需要自己编写startstop控件,使用后台线程和同步。 (这并不难,但这确实意味着它不完全是一个简单的解决方案。)

我不能肯定地说这会解决问题,但这可能是我接下来会尝试的。 (从长远来看,编写自己的音频播放器确实具有更加灵活的好处。Clip 首先并没有令人印象深刻的功能集。)

关于java - 音频剪辑偶尔无法播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45179495/

相关文章:

audio - 更改mp3文件的采样率

vb.net - vb.net在不使用Windows Media Player的情况下播放声音

iphone - 如何在iPhone中以特定频率放大声音?

java - 声明类类型实例变量并在 Esper 中调用实例方法时未调用实例方法

java - 从 JSP 打开 PDF 的最佳方式是什么?

java - 从 JavaScript 代码调用 Java 函数?

Android 从视频中剥离音频

java - 无法从 Play 框架发送电子邮件

java - 吃 bean 人游戏 : how to let the monesters follow the player?

ios - 使用 AVAudioSession 设置麦克风增益时出现不稳定行为