2011-11-19 70 views
3

我试图与pyportmidi Novation Launchpad谈谈。我注意到,如果我只是继续使用midiOut.WriteShort()发送说明,它会处理前100个左右,然后松开剩下的部分。发送大量的数据pyportmidi停止工作,除非我添加延迟

我想有一个缓冲区已经满了,一旦它满了,指令就会丢失。我可以通过在每封邮件后添加一个time.sleep(.1)来解决这个问题,但这显然会让事情变得非常缓慢。有没有办法测试缓冲区是否已满,只有在需要时才会睡眠?或者在发送更多数据之前等待缓冲区清空的方法?

回答

4

当我看看SVN repo时,我在包装代码中遇到了这个问题,注意'为什么bufferSize是0?'评论..

def __init__(self, OutputDevice, latency=0): 
...stuff... 
    # Why is bufferSize 0 here? 
    err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency) 

API文档显示具有以下签名Pm_OpenOutput

PmError Pm_OpenOutput (
    PortMidiStream **stream, 
    PmDeviceID outputDevice, 
    void *outputDriverInfo, 
    long bufferSize, 
    PmTimeProcPtr time_proc, 
    void *time_info, 
    long latency 
) 

似乎没有要找出当前缓冲区堆栈长度的任何明显的方法,更重要的是,它看起来Python包装完全忽略缓冲区设置。

portmidi.c讲述了一个稍微不同的故事:

if (bufferSize <= 0) bufferSize = 256; /* default buffer size */ 
    midi->queue = Pm_QueueCreate(bufferSize, sizeof(PmEvent)); 
    if (!midi->queue) { 
     /* free portMidi data */ 
     *stream = NULL; 
     pm_free(midi); 
     err = pmInsufficientMemory; 
     goto error_return; 
} 

那么,256是默认的。这将解释为什么你遇到大约100左右的问题。

然而,有些东西要记住 - MIDI极其缓慢,31250个波特(31250个比特每秒), 由于MIDI信息是(通常)2个字节(16位),这意味着最大的每 1953条的消息第二。 (我在这里可能是错的,但是如果我不对,我会非常接近)

但是,有一个简单的解决方法,你可以在大多数 操作系统上睡2ms,而不会搞砸。

time.sleep(.002) # 2 millisecond sleep 

但是,由于您使用的是write_short(),每秒只能发送500条消息。 所以你可能想要做一些事情,比如让一个队列每隔0.002秒轮询一次,传出消息,弹出16个堆栈,写入然后休眠。这样,如果整个MIDI堆栈支持的速率可以达到每秒8000条消息的速度。

我注意到,在下面的代码中,如果我将睡眠时间降低到0.002以下,则根本不会发送任何MIDI 直到我退出程序,然后所有事件喷到MIDI总线上。所以Portmidi速率限制或OSX上可能存在问题。

要记住,如果你真的爆破MIDI另一件事 - 最有可能的控制变化值,如果你修改类似的高通滤波器,“1”的值听起来很像“ 2',所以如果你的消息不那么精细(递增或递减2或4),你可以减少消息的数量 而不会有明显的音频差异。这是一个不太理想的解决方案,很可能你的MIDI堆栈支持的速度可能比31250波特快得多。

要考虑的另一件事是,如果你将你的portmidi应用程序从属于MIDI时钟,你可以从MIDI主机获得可靠的刻度流,你可以用它作为触发器来写回MIDI数据(no睡觉必要)。

祝你好运!

-n

PPQN Clock MIDI 1.0

+0

意想不到的答案,谢谢! – tomcat23