我的iOS應用程序使用PGMidi(一個Core MIDI庫)將MIDI庫和程序更改發送到其他設備。一些用戶報告說,這些消息有時以錯誤的順序到達 - 程序更改隨後是銀行更改。如何確保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函數被調用後會發生這種情況嗎?如果是這樣,我需要另一種解決方案。
我不能在自己的測試中重複這個問題,所以我想知道問題是什麼,所以我有更好的機會來修復它。
「你不能指望他們按照你創建的順序運行。」這正是我所尋找的,謝謝。我將所有這些消息合併爲一條消息。但是我仍然在後臺發送消息,因爲這是在PGMidi示例項目中完成的。你認爲這不是必需的嗎? – arlomedia
試試看看。我不認爲這是必要的,但是我對PGMidi不熟悉,並且我沒有在iOS上使用過很多MIDI(只是OS X有更多的性能空間)。 –
看着[PGMIDI中的代碼](https://github.com/petegoodliffe/PGMidi/blob/master/Sources/UI/MidiMonitorViewController.mm),我認爲它在後臺線程上的唯一好理由就是它可以睡覺0.1秒而不會阻塞用戶界面。你不會在真正的應用程序中這樣做 - 你最好給CoreMIDI指定時間戳。 –