在它们之间延迟播放一系列剪辑

时间:2012-03-22 15:29:03

标签: java javasound

假设我有很多声音(想象一下钢琴/吉他音符)。

我希望在给定的间隔后播放每个声音,例如200毫秒。

但我想让之前的声音“振铃”。

虽然下面的方法适用于较长的延迟(700-1000 ms),但它并不太精确。

对于短暂的延迟,有时声音“聚集”并快速连续播放。

我尝试过的(伪代码):

for (Clip clip: clipList){
  clip.start(); 
  Thread.sleep(500);
}

我的猜测这与JVM / OS的线程调度有关...

有什么想法吗?

修改

正如评论中所建议的那样,我也尝试过计时器:

final Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {

  @Override
  public void run() {
    try{
      Clip clip = clipList.remove();
      clip.start();
    }catch (NoSuchElementException e) {
      timer.cancel();
    }
  }
};
timer.schedule(timerTask, 0, delay);

当我有7-8个声音和500毫秒延迟时,我仍然会得到相同的行为。

1 个答案:

答案 0 :(得分:1)

让音符“振铃”是一件很棒的事情,也是推动我使用Java Sound的研究和试验的东西。我不确定我可以提供具体帮助,但我可以分享一两个经验。

我制作了一个剪辑播放器,允许用户在完成播放之前重新触发剪辑(允许第一个播放而另一个播放时播放),以及不同的采样率。这是通过为剪辑提供多个游标并使它们独立地增加内部存储的样本数据来完成的。 (当光标落在两个样本之间时,高速或低速播放使用线性插值来获取音频值。)输出汇集到一个SourceDataLine中。

奇怪的是,当这个剪辑播放器被多次调用时,作为一个独立的程序,会发生一个类似于你所描述的聚束。然而,我还写了一个音频混音器,能够播放这些片段和一个sourceDataLine .wav文件以及一些现场FM合成声音,将它们全部混合到一个SINGLE SourceDataLine输出中,并且这个时间非常准确。好!

这真让我感到困惑,因为剪辑部分(以及剪辑的触发器)实际上是相同的代码。一个关键的区别可能是我写的AudioMixer被设置为连续运行,因此一些可能的时序问题可能来自于从字节码到内存运行代码。 HotSpot编译器会将代码作为字节码运行几次,然后再将其放入内存中,以便更快地运行,这将解决一些时序问题。

我发现了一篇关于您可能想要查看的时间问题的好文章: http://quod.lib.umich.edu/cgi/p/pod/dod-idx?c=icmc;idno=bbp2372.2007.131

基本上,java不提供“实时”保证,这是实现低延迟性能的重大挑战。方差来源包括:HotSpot或其他任何决定从字节码或内存,垃圾收集,vm线程切换运行的问题。

拥有“播出”的剪辑将是进行分支音乐的关键组成部分,例如,允许在游戏中的某个时刻进行zig而不是zag,并且音乐或sfx将保持“无缝”。这是我想象的一部分。当然,如果有一个DAW可以采用一个轨道并指定它被保存为多个音频图块(重叠/播出),而不是单独导出每个图块,那也是很好的。但这是领先于游戏......这是你正在考虑的一般方向吗?或者您还有其他应用吗? (只是好奇。)