2017-02-20 42 views
0

我正在寻找使用Javasound编写简单的MIDI驱动音频音序器。在Javasound中播放多个样本

我有多个样本(每个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()在Javaound API的幕后由一个单独的线程运行。

任何人都可以提出为什么会发生这种情况吗?这可能是同步问题吗?

编辑:'挂',我的意思是一些笔记被卡住,尽管事实上日志输出报告,相应的'停止'方法已被调用。

编辑2:它看起来好像当第二次播放给定音符时挂起的第一个音符发生。即使MIDI序列是单声道的,即前一个音符已停止,也会发生这种情况。

+0

“挂”是否意味着一些剪辑继续播放?你能证明(例如,记录)你的代码实际上试图停止该剪辑吗? –

+0

@CL上面已阐明。 – NietzscheanAI

+0

嗯,我们不会玩猜谜游戏只是发布你的代码你在每一步做什么都是未知的 - 理论上一切正常 – gpasch

回答

1

您为每个播放加载剪辑的方法将成为可变延迟的重要来源。每次您调用此文件时,都会重新读取该文件,并且在整个文件加载完成之前不会开始播放。

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

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

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

您可能不需要“停止”或“关闭”剪辑,直到整个序列完成,除非剪辑非常长并且设计为在进行中停止,或者如果它们正在播放循环。

这应该会大大改善。我不能说它是否能解决所有问题。cpu可能正在进行一些线程复用,并且偶尔在您当前的代码中,剪辑在另一个线程上完成加载之前,将在一个线程上调用clip.close。