如何确保MIDI信息以正确的顺序到达?

时间:2012-06-14 16:57:11

标签: ios multithreading coremidi

我的iOS应用程序使用核心MIDI库PGMidi将MIDI库和程序更改发送到其他设备。有些用户报告说,这些消息有时会以错误的顺序到达 - 程序更改后随后更改银行。

对于每个银行/程序更改,我正在组装一个NSArray数值,然后将该数组传递给后台线程中的sendMidiDataInBackground方法:

int MSBStatus = 0xB0;
int MSBController = 0;
int MSBValue = 1;
NSArray *MSBValues = [NSArray arrayWithObjects:[NSNumber numberWithInt:MSBStatus], [NSNumber numberWithInt:MSBController], [NSNumber numberWithInt:MSBValue], nil];
[self performSelectorInBackground:@selector(sendMidiDataInBackground:) withObject:MSBValues];

int LSBStatus = 0xB0;
int LSBController = 32;
int LSBValue = 2;
NSArray *LSBValues = [NSArray arrayWithObjects:[NSNumber numberWithInt:LSBStatus], [NSNumber numberWithInt:LSBController], [NSNumber numberWithInt:LSBValue], nil];
[self performSelectorInBackground:@selector(sendMidiDataInBackground:) withObject:LSBValues];

int programStatus = 0xC0;
int programValue = 3
NSArray *programValues = [NSArray arrayWithObjects:[NSNumber numberWithInt:programStatus], [NSNumber numberWithInt:programValue], nil];
[self performSelectorInBackground:@selector(sendMidiDataInBackground:) withObject:programValues];

sendMidiDataInBackground方法将值更改为C数组并将它们传递给PGMidi的sendBytes方法,该方法将它们组装成数据包列表并通过MIDISend发送出去。我注意到时间戳设置为0,这意味着“现在”:

- (void) sendBytes:(const UInt8*)bytes size:(UInt32)size {
    Byte packetBuffer[size+100];
    MIDIPacketList *packetList = (MIDIPacketList*)packetBuffer;
    MIDIPacket     *packet     = MIDIPacketListInit(packetList);
    packet = MIDIPacketListAdd(packetList, sizeof(packetBuffer), packet, 0, size, bytes);
    OSStatus s = MIDISend(midi.outputPort, endpoint, packetList);
}

但是在某些时候,显然有些消息会被延迟,所以它们会以错误的顺序结束。这是因为后台线程没有按照它们的启动顺序完成吗?如果是这样,我可以组合MSB,LSB和程序数组,并将组合数组发送到sendMidiDataInBackground,而不是启动三个单独的线程,这应该解决它。

或者在调用MIDISend函数后会发生这种情况吗?如果是这样,我需要另一种解决方案。

我不能在自己的测试中重复这个问题,所以我想知道问题是什么,所以我有更好的机会实际修复它。

1 个答案:

答案 0 :(得分:0)

根据the documentation-performSelectorInBackground:withObject:创建了一个新的后台线程。您不应该对操作系统如何安排这些线程做出任何假设。您不能指望它们按照您创建它们的顺序运行。

是什么让你认为你需要在后台执行此操作?发送一些简短的MIDI信息不太可能在很长一段时间内阻止你的主线程。创建三个独立的线程对于少量工作来说是一笔令人难以置信的开销。

如果您确实需要在后台执行此操作,请考虑使用GCD的dispatch_asyncNSOperation之类的串行队列,和/或在一次方法调用中完成所有工作而不是三次