2010-01-21 35 views
2

我在寫一個使用C++和Windows API的Windows程序,並且試圖在MIDI流中排列MIDI消息,但是當我嘗試這樣做時收到奇怪的錯誤。如果我使用midiOutShortMsg將未排隊的MIDI消息發送到流,它將正常工作。但是,midiStreamOut總是返回錯誤代碼68,即#define d到MCIERR_WAVE_OUTPUTUNSPECIFIEDmidiOutGetErrorText給出了錯誤的如下描述:在Windows中使用MIDI流的問題

The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.

我使用Windows 7(64位),並嘗試打開與兩個MIDI_MAPPER的設備ID的MIDI流,我的系統上所有四個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)); 

我怎樣才能解決這個問題呢?

回答

2

問題是我正在使用整個事件結構作爲MIDI流的緩衝區。事實證明,該結構的第四個成員dwParms實際上應該從短消息中省略。要糾正在貼出的問題的代碼,兩行代碼的可改爲如下:

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

加入多個事件流,它實際上是一個更容易,只需使用的DWORD秒的陣列而不是對MIDIEVENT結構感到困擾。

對於使用Windows API進行MIDI編程的其他人,請注意某些MSDN文檔具有誤導性,不足或完全錯誤。

MIDIEVENT結構文檔說以下內容:

dwParms

If dwEvent specifies MEVT_F_SHORT, do not use this member in the stream buffer.

這是不明確的,因爲它不是明確表示「使用」是指「包括」而不是「指定」。

以下是文件中的其他兩個缺陷,程序員需要注意的:

dwEvent

Event code and event parameters or length. [...] The high byte of this member contains flags and an event code. Either the MEVT_F_LONG or MEVT_F_SHORT flag must be specified. The MEVT_F_CALLBACK flag is optional.

在頭文件被選中,MEVT_F_預處理器定義實際上指定完整DWORD做得相當不僅僅是個人的標誌,所以在我在問題代碼,指定該構件的線本來應該如下:

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

除此之外,它也證明,含有MIDIHD存儲器R結構應該保留,直到緩衝區結束播放爲止,所以它應該在堆中分配,而不是在大多數實現中分配給堆棧。