我正在尝试用pyportmidi与Novation Launchpad交谈。我注意到,如果我继续使用midiOut.WriteShort()
发送指令,它将处理前100个左右,然后松开其余部分。
我猜有一个缓冲区已经满了,一旦它已经满了,指令就会丢失。我可以通过在每条消息之后添加time.sleep(.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