2012-06-14 49 views
1

我的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函數被調用後會發生這種情況嗎?如果是這樣,我需要另一種解決方案。

我不能在自己的測試中重複這個問題,所以我想知道問題是什麼,所以我有更好的機會來修復它。

回答

0

根據the documentation,-performSelectorInBackground:withObject:創建一個新的後臺線程。你不應該對OS如何安排這些線程做任何假設。你不能指望他們按照你創建的順序運行。

什麼讓你覺得你需要在後臺做到這一點?發送一些簡短的MIDI消息不太可能會阻止您的主線程時間很長。創建三個獨立的線程對於少量工作來說是一個難以置信的開銷。

如果您確實需要在後臺執行此操作,請考慮使用類似GCD的dispatch_async或帶有串行隊列的NSOperation,和/或在一次方法調用中完成所有工作而不是三次。

+0

「你不能指望他們按照你創建的順序運行。」這正是我所尋找的,謝謝。我將所有這些消息合併爲一條消息。但是我仍然在後臺發送消息,因爲這是在PGMidi示例項目中完成的。你認爲這不是必需的嗎? – arlomedia

+0

試試看看。我不認爲這是必要的,但是我對PGMidi不熟悉,並且我沒有在iOS上使用過很多MIDI(只是OS X有更多的性能空間)。 –

+0

看着[PGMIDI中的代碼](https://github.com/petegoodliffe/PGMidi/blob/master/Sources/UI/MidiMonitorViewController.mm),我認爲它在後臺線程上的唯一好理由就是它可以睡覺0.1秒而不會阻塞用戶界面。你不會在真正的應用程序中這樣做 - 你最好給CoreMIDI指定時間戳。 –