除非我添加延迟,否则使用pyportmidi发送大量数据会停止工作

时间:2011-11-19 23:23:17

标签: python midi pyportmidi

我正在尝试用pyportmidi与Novation Launchpad交谈。我注意到,如果我继续使用midiOut.WriteShort()发送指令,它将处理前100个左右,然后松开其余部分。

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

1 个答案:

答案 0 :(得分: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个 第二。 (我可能在这里错了,但如果我不对的话,我会非常接近)

然而,有希望:一个简单的解决方法是,你可以在大多数情况下睡到2毫秒 操作系统没有搞乱。

time.sleep(.002) # 2 millisecond sleep

但是,由于您使用的是write_short(),因此每秒只能提供500条消息。 所以你可能想做一些像每隔.002秒轮询一次的队列 传出消息,从堆栈弹出16,写入然后再睡眠。那样的话,如果你的整体 MIDI堆栈支持速度快,每秒可以获得8000条消息。

我注意到在下面的代码中,如果我将睡眠时间降低到低于.002,那么将不会发送任何MIDI,直到我退出程序,然后所有事件都喷到MIDI上总线。因此可能存在portmidi速率限制或OSX的问题。

另外要注意的是,如果你真的在爆炸MIDI - 很可能是控制变化值,如果你修改像高通滤波器这样的东西,那么'1'的值听起来很像'2' ',所以如果你的消息不那么精细(递增或递减2或4),你可以减少消息的数量 没有明显的音频差异。这是一个次优的解决方案,很可能你的MIDI堆栈可能支持比31250波特更快。

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

祝你好运!

-n

PPQN Clock MIDI 1.0