我想和一个有pyportmidi的Novation Launchpad聊天。我注意到,如果我一直使用midiOut.WriteShort()向它发送指令,它会处理前100个左右的指令,然后释放其余的指令。
我猜在某个地方有一个缓冲区已经满了,一旦它满了,指令就会丢失。我可以通过在每条消息后添加一个time.sleep(.1)来解决这个问题,但这显然会使事情变得非常缓慢。是否有一种方法可以测试缓冲区是否已满,并且只有在需要时才休眠?或者在我发送更多数据之前等待缓冲区清空的方法?
发布于 2011-11-21 17:14:49
当我查看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条消息。因此,您可能想要做一些事情,比如让队列每隔.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
https://stackoverflow.com/questions/8198145
复制相似问题