1

私の 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 メソッドに渡します。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);
}

しかし、ある時点で明らかに一部のメッセージが遅れているため、間違った順序になってしまいます。これは、バックグラウンド スレッドが開始された順序で終了しないためですか? もしそうなら、3 つの別々のスレッドを開始するのではなく、MSB、LSB、およびプログラム配列を組み合わせて、組み合わせた配列を sendMidiDataInBackground に送信することができ、それで解決するはずです。

または、MIDISend 関数が呼び出された後にこれが発生する可能性はありますか? もしそうなら、私は別の解決策が必要です。

私自身のテストで問題を再現することはできないので、実際に修正できる可能性が高くなるように、問題が何であるかを確認したいと思います.

4

1 に答える 1

0

ドキュメントによると-performSelectorInBackground:withObject:、新しいバックグラウンド スレッドを作成します。OS がこれらのスレッドをどのようにスケジュールするかについて、仮定を立てるべきではありません。それらが作成した順序で実行されるとは期待できません。

バックグラウンドでこれを行う必要があると考える理由は何ですか? いくつかの短い MIDI メッセージを送信しても、メイン スレッドがかなりの時間ブロックされることはほとんどありません。3 つの個別のスレッドを作成することは、わずかな作業量に対して信じられないほどのオーバーヘッドになります。

dispatch_async本当にバックグラウンドで実行する必要がある場合は、GCDやシリアル キューを使用したものを使用するかNSOperation、3 つではなく 1 つのメソッド呼び出しですべての作業を行うことを検討してください。

于 2012-06-20T04:02:00.260 に答える