WindowsでMIDIストリームを使用する問題
質問
私はC ++とWindows APIを使用してWindowsプログラムを書いています。MIDIストリームでMIDIメッセージをキューに入れようとしていますが、そうしようとすると奇妙なエラーを受け取っています。使用する場合 midiOutShortMsg
クロックでないMIDIメッセージをストリームに送信するために、正しく機能します。でも、 midiStreamOut
常にエラーコード68を返します #define
d to MCIERR_WAVE_OUTPUTUNSPECIFIED
. midiOutGetErrorText
エラーの次の説明を示します。
現在のMIDIマッパーセットアップは、システムにインストールされていないMIDIデバイスを指します。 MIDIマッパーを使用してセットアップを編集します。
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 ) );
この問題を解決するにはどうすればよいですか?
解決
問題は、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を指定している場合、このメンバーをStream Bufferで使用しないでください。
これは、「使用」が「指定」ではなく「」を意味することを意図していることは明らかではないため、あいまいです。
ドキュメントには、プログラマーが認識する必要がある他の2つの欠陥があります。
dwevent
イベントコードとイベントパラメーターまたは長さ。 [...]このメンバーの高いバイトには、フラグとイベントコードが含まれています。 MEVT_F_LONGまたはMEVT_F_SHORTフラグのいずれかを指定する必要があります。 MEVT_F_CALLBACKフラグはオプションです。
ヘッダーファイルがチェックされると、 MEVT_F_
プリプロセッサの定義は実際に完全に指定します DWORD
s個々のフラグだけではなく、質問の私のコードでは、このメンバーを指定する行は次のとおりであるべきでした。
event->dwEvent = MEVT_F_SHORT | MEVT_SHORTMSG << 24 | ( msg & 0x00FFFFFF );
これに加えて、MIDIHDR構造を含むメモリをバッファーの再生が終了するまで保持する必要があるため、ほとんどの実装のスタックではなくヒープに割り当てる必要があることが判明しました。