2

C++ と Windows API を使用して Windows プログラムを作成しており、MIDI ストリームで MIDI メッセージをキューに入れようとしていますが、そうしようとすると奇妙なエラーが発生します。midiOutShortMsgキューに入れられていない MIDI メッセージをストリームに送信していた場合、正しく動作します。ただし、midiStreamOut常にエラー コード 68 を返します。これは#defined ~MCIERR_WAVE_OUTPUTUNSPECIFIEDです。midiOutGetErrorTextエラーの次の説明を示します。

現在の MIDI マッパー セットアップは、システムにインストールされていない MIDI デバイスを参照しています。MIDI Mapper を使用して設定を編集します。

Windows 7 (64 ビット) を使用しており、システム上の MIDI_MAPPER と 4 つの MIDI 出力デバイスすべてのデバイス ID を使用して MIDI ストリームを開こうとしましたが、まったく同じエラー メッセージが表示されます。

MIDI ストリームを開くコードは次のとおりです。

UINT device_id = MIDI_MAPPER; //Also tried 0, 1, 2 and 3
midiStreamOpen( &midi, &device_id, 1, ( DWORD_PTR )hwnd, 0, CALLBACK_WINDOW );

MIDI メッセージを送信するコードは次のとおりです。

MIDIHDR header;
MIDIEVENT *event;

event = ( MIDIEVENT * )malloc( sizeof( *event ) );
event->dwDeltaTime = delta_time;
event->dwStreamID = 0;
event->dwEvent = ( MEVT_F_SHORT | MEVT_SHORTMSG ) << 24 | ( msg & 0x00FFFFFF );

header.lpData = ( LPSTR )event;
header.dwBufferLength = sizeof( *event );
header.dwBytesRecorded = sizeof( *event );
header.dwUser = 0;
header.dwFlags = 0;
header.dwOffset = 0;

midiOutPrepareHeader( ( HMIDIOUT )midi, &header, sizeof( header ) );
midiStreamOut( midi, &header, sizeof( header ) );

この問題を解決するにはどうすればよいですか?

4

1 に答える 1

2

問題は、イベント構造全体を MIDI ストリームのバッファとして使用していたことです。構造体の 4 番目のメンバー は、dwParms実際にはショート メッセージから省略されるべきであることがわかりました。投稿された質問のコードを修正するには、コードの 2 行を次のように変更します。

header.dwBufferLength = sizeof( *event ) - sizeof( event->dwParms );
header.dwBytesRecorded = sizeof( *event ) - sizeof( event->dwParms );

ストリームに複数のイベントを追加する場合、構造体DWORDを気にするよりも、単に s の配列を使用する方が実際にははるかに簡単です。MIDIEVENT

Windows API を使用して MIDI プログラミングを行っている他の人は、MSDN のドキュメントの一部が誤解を招く、不十分である、または完全に間違っていることに注意してください。

構造のドキュメントにMIDIEVENTは、次のように記載されています。

dwParms

dwEvent が MEVT_F_SHORT を指定する場合、ストリーム バッファーでこのメンバーを使用しないでください。

「使用」が「指定」ではなく「含む」ことを意味することを意図していることが明確でないため、これはあいまいです。

プログラマーが注意する必要があるドキュメントのその他の 2 つの欠陥を次に示します。

dwイベント

イベント コードとイベント パラメータまたは長さ。[...] このメンバーの上位バイトには、フラグとイベント コードが含まれます。MEVT_F_LONG または MEVT_F_SHORT フラグを指定する必要があります。MEVT_F_CALLBACK フラグはオプションです。

ヘッダー ファイルがチェックされると、MEVT_F_プリプロセッサの定義は実際にDWORDは個々のフラグではなく完全な s を指定するため、問題の私のコードでは、このメンバーを指定する行は次のようになります。

event->dwEvent = MEVT_F_SHORT | MEVT_SHORTMSG << 24 | ( msg & 0x00FFFFFF );

これに加えて、MIDIHDR 構造体を含むメモリは、バッファの再生が終了するまで保持する必要があることが判明したため、ほとんどの実装ではスタックではなくヒープに割り当てる必要があります。

于 2010-01-22T00:03:12.767 に答える