有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在Javasound中播放多个示例

我想用Javasound编写一个简单的MIDI驱动的音频序列器

我有多个样本(每个MIDI音高一个)作为一个(全局可访问的)Map<MidiPitch,AudioInputStream>加载到内存中

javax.sound.midi.Receiver的自定义子类对传入的MIDI事件做出如下响应:

如果事件是一个注释,则获得一个剪辑并按如下方式播放:

Clip clip = AudioSystem.getClip();
clip.open(lookupAIS(pitch));
clip.start();

然后将该片段添加到全局可访问的Map<MidiPitch,List<Clip>>,表示开始的片段,即如上所述调用了start()但尚未收到注释事件的片段

如果事件是一个注释,则从上面的地图中获得相应的开始剪辑列表。列表开头的剪辑将被删除,并对其调用stop()close()

上面的Receiver以通常的方式连接到MidiSystem.getSequencer(),然后调用以下函数:

sequencer.setSequence(MidiSystem.getSequence(new File(myMidFile)))
sequencer.open()
sequencer.start()

Thread.sleep(aLongTime())

sequencer.stop()
sequencer.close()

当驱动MIDI序列的节奏较慢时,上述方法有效,但在更高的节奏下,音符只会挂起(即使是包含非常少量音符的序列)

我的理解是clip.start()在幕后由Javasound API在一个单独的线程中运行

有人能提出为什么会发生这种情况吗?这可能是一个同步问题吗

编辑:所谓“挂起”,我的意思是一些注释被卡住了,尽管日志输出报告相应的“停止”方法已被调用

EDIT2:当第二次播放某个音符时,似乎第一次挂起。即使MIDI序列是单声道的,也会发生这种情况,即上一个音符已停止


共 (1) 个答案

  1. # 1 楼答案

    你为每场比赛加载剪辑的方法将是一个相当大的可变延迟来源。每次调用此命令时,都会重新读取文件,直到整个文件加载完毕后才会开始播放

    我建议预先加载所有剪辑并将其保存在内存中。调用note on时,将剪辑光标设置为零,然后播放:

    clip[mapIndex].setFramePosition(0);
    clip[mapIndex].start();
    

    这些剪辑应该已经打开了。我将它们放在一个数组中,并使用“mapIndex”作为一种合理的方式来选择正确的剪辑,它可能与您已经设置的映射一起工作

    在整个序列完成之前,您可能不需要“停止”或“关闭”这些剪辑,除非这些剪辑相当长,并且设计为在播放过程中停止,或者它们是作为循环播放的

    这将大大改善情况。我不能说它是否能解决所有问题。cpu可能正在执行一些线程多路复用,在当前代码中,偶尔会出现片段。close是在一个线程上调用的,在剪辑加载完另一个线程之前