Hello,
In one of my projects I need to retrieve the Midi input for regular Midi messages such as “Note on” (up to 3 bytes) and
also system exclusive messages (more than 3 bytes).
I am using the example code below to do so.
I have 2 Midi interfaces available, Emagic’s Unitor 8 and M-Audio Firewire Audiophile.
The code works very well with Unitor 8. No problems at all.
Only if I use the M-Audio interface, I got crashes as soon as I feed long system exclusive messages (267 bytes) and short regular messages
into the input simultaneously.
It would be very nice if somebody could check the code to point me to the culprit.
Thank you very much in advance!
Joerg
In one of my projects I need to retrieve the Midi input for regular Midi messages such as “Note on” (up to 3 bytes) and
also system exclusive messages (more than 3 bytes).
I am using the example code below to do so.
I have 2 Midi interfaces available, Emagic’s Unitor 8 and M-Audio Firewire Audiophile.
The code works very well with Unitor 8. No problems at all.
Only if I use the M-Audio interface, I got crashes as soon as I feed long system exclusive messages (267 bytes) and short regular messages
into the input simultaneously.
It would be very nice if somebody could check the code to point me to the culprit.
Thank you very much in advance!
Joerg
Code:
<script type="text/javascript"> <!-- #COMPILE EXE #DIM ALL %USEMACROS = 1 #INCLUDE "Win32API.inc" '============================================================================== FUNCTION WINMAIN (BYVAL hInstance AS DWORD, _ BYVAL hPrevInstance AS DWORD, _ BYVAL lpCmdLine AS ASCIIZ PTR, _ BYVAL iCmdShow AS LONG) AS LONG '------------------------------------------------------------------------------ ' Program entry point '-------------------------------------------------------------------------- LOCAL Msg AS tagMsg LOCAL wce AS WndClassEx LOCAL szAppName AS ASCIIZ * 80 LOCAL hWnd AS DWORD ' Setup and register a window class for the main window ' CODEPTR is used to pass the address of the function that will ' receive all messages sent to any window created with this class szAppName = "Midi In Test" wce.cbSize = SIZEOF(wce) wce.STYLE = %CS_HREDRAW OR %CS_VREDRAW wce.lpfnWndProc = CODEPTR(WndProc) wce.cbClsExtra = 0 wce.cbWndExtra = 0 wce.hInstance = hInstance wce.hIcon = %NULL wce.hCursor = LoadCursor(%NULL, BYVAL %IDC_ARROW) wce.hbrBackground = %COLOR_BTNFACE + 1 wce.lpszMenuName = %NULL wce.lpszClassName = VARPTR(szAppName) wce.hIconSm = LoadIcon(hInstance, BYVAL %IDI_APPLICATION) RegisterClassEx wce ' Create a window using the registered class hWnd = CreateWindow(szAppName, _ ' window class name "Midi In Test", _ ' window caption %WS_OVERLAPPEDWINDOW, _ ' window style %CW_USEDEFAULT, _ ' initial x position %CW_USEDEFAULT, _ ' initial y position 400, _ ' initial x size 200, _ ' initial y size %NULL, _ ' parent window handle %NULL, _ ' window menu handle hInstance, _ ' program instance handle BYVAL %NULL) ' creation parameters IF hWnd = 0 THEN ' exit on failure MSGBOX "Unable to create window" EXIT FUNCTION END IF ' Display the window on the screen ShowWindow hWnd, iCmdShow UpdateWindow hWnd ' Main message loop: ' Messages sent to HELLOWIN while it has the focus are received by ' GetMessage(). This loop translates each message and dispatches it ' to the appropriate handler. When PostQuitMessage() is called, the ' loop terminates which ends the application. DO WHILE GetMessage(Msg, %NULL, 0, 0) TranslateMessage Msg DispatchMessage Msg LOOP FUNCTION = msg.wParam END FUNCTION '============================================================================== FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _ BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG '------------------------------------------------------------------------------ ' WndProc is the message handler for all windows creating using the HelloWin ' class name. A single WndProc procedure can handle multiple windows by ' testing the hWnd variable passed to it. '-------------------------------------------------------------------------- LOCAL midiErr AS LONG LOCAL ptMidiInHdr1 AS MIDIHDR PTR LOCAL ptMidiInHdr2 AS MIDIHDR PTR LOCAL ptMidiInHdrRet AS MIDIHDR PTR LOCAL hdrDummy AS MIDIHDR LOCAL lMidiIn AS LONG STATIC hWndIn AS DWORD STATIC hWndOut AS DWORD LOCAL lBuffSize AS LONG LOCAL sStatus AS STRING * 2 LOCAL sNote AS STRING * 2 LOCAL sVelo AS STRING * 2 STATIC lBuffRet AS LONG STATIC lInreset AS LONG LOCAL lcount AS LONG ' The SELECT CASE is used to catch only those messages which the message ' handler needs to process. All other messages are passed through the ' tests to the default handler. SELECT CASE wMsg CASE %WM_CREATE lMidiIn = 8 lBuffSize = 384 midiErr = midiInOpen(hWndIn, BYVAL lMidiIn, BYVAL hWnd, 0, %CALLBACK_WINDOW OR %MIDI_IO_STATUS) 'no input available IF ISTRUE midiErr OR ISFALSE hWndIn THEN lBuffRet = 3 SetWindowText hWnd, "No valid input available!" EXIT FUNCTION END IF ptMidiInHdr1 = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, LEN(hdrDummy)) ptMidiInHdr2 = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, LEN(hdrDummy)) 'prepare Midi header1 @ptMidiInHdr1.lpdata = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, lBuffSize) @ptMidiInHdr1.dwbufferlength = lBuffSize @ptMidiInHdr1.dwbytesrecorded = 0 @ptMidiInHdr1.dwUser = 1 'indicates buffer number @ptMidiInHdr1.dwFlags = 0 'prepare Midi header2 @ptMidiInHdr2.lpdata = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, lBuffSize) @ptMidiInHdr2.dwbufferlength = lBuffSize @ptMidiInHdr2.dwbytesrecorded = 0 @ptMidiInHdr2.dwUser = 2 'indicates buffer number @ptMidiInHdr2.dwFlags = 0 midiErr = midiInPrepareHeader(BYVAL hWndIn, BYREF @ptMidiInHdr1, LEN(hdrDummy)) midiErr = midiInPrepareHeader(BYVAL hWndIn, BYREF @ptMidiInHdr2, LEN(hdrDummy)) midiErr = midiInAddBuffer(BYVAL hWndIn, BYREF @ptMidiInHdr1, LEN(hdrDummy)) midiErr = midiInAddBuffer(BYVAL hWndIn, BYREF @ptMidiInHdr2, LEN(hdrDummy)) midiErr = midiInStart(BYVAL hWndIn) CASE %MM_MIM_DATA sStatus = MID$(HEX$(lParam, 6), 5, 2) sNote = MID$(HEX$(lParam, 6), 3, 2) sVelo = MID$(HEX$(lParam, 6), 1, 2) 'display regular midi events SetWindowText hWnd, sStatus & "," & sNote & "," & sVelo EXIT FUNCTION CASE %MM_MIM_LONGERROR ptMidiInHdrRet = lParam midiErr = midiInAddBuffer(BYVAL hWndIn, BYREF @ptMidiInHdrRet, BYVAL LEN(hdrDummy)) CASE %MM_MIM_LONGDATA ptMidiInHdrRet = lParam IF ISFALSE(lInReset) THEN 'display SysEx midi events SetWindowText hWnd, CHR$(@ptMidiInHdrRet.lpdata) midiErr = midiInAddBuffer(BYVAL hWndIn, BYREF @ptMidiInHdrRet, BYVAL LEN(hdrDummy)) ELSE lBuffRet = lBuffRet + @ptMidiInHdrRet.dwUser midiErr = midiInUnprepareHeader(BYVAL hWndIn, BYREF @ptMidiInHdrRet, LEN(hdrDummy)) midiErr = HeapFree(GetProcessHeap(), %HEAP_NO_SERIALIZE, @ptMidiInHdrRet.lpdata) midiErr = HeapFree(GetProcessHeap(), %HEAP_NO_SERIALIZE, ptMidiInHdrRet) END IF EXIT FUNCTION CASE %WM_CLOSE lInReset = %TRUE midiErr = midiInReset(BYVAL hWndIn) WHILE lBuffRet <> 3 DIALOG DOEVENTS 1 TO lCount WEND midiErr = midiInClose(BYVAL hWndIn) CASE %WM_DESTROY PostQuitMessage 0 EXIT FUNCTION END SELECT ' Any message which is not handled in the above SELECT CASE reaches this ' point and is processed by the Windows default message handler. FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam) END FUNCTION //--> </script>
Comment