-
MIDI in.
I am trying to write a simple Windows program in Code::Blocks (as a foundation to write a larger program) but everything I try just doesn't compile for a variety of cryptic reasons.
For instance this code here gives the following errors that are simply beyond me. Some error seems to be causing errors in the compilation of header files.
I'm having real trouble just getting this simple act of I/O to work - can anyone help here? Or if there's another way of interfacing with MIDI devices then I'd love to know.
I've tried getting the linker to link winmm.lib (I've tried typing "winmm.lib" into the Link Libraries (in the Linker Settings in the Project Settings) and "-lwinmm" into Other Linker Options in the same dialog but to no avail.
I think what I need is to understand the fundamentals of how Windows interfaces with MIDI devices, are there any good guides out there? Are there other libraries that I need to have (.NET or MFC, etc?)
I'd appreciate any help on the subject.
Code:
#include <SDKDDKVer.h>
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <mmsystem.h>
//#pragma comment(lib, "winmm.lib")
void PrintMidiDevices()
{
UINT nMidiDeviceNum;
MIDIINCAPS caps;
nMidiDeviceNum = midiInGetNumDevs();
if (nMidiDeviceNum == 0) {
fprintf(stderr, "midiInGetNumDevs() return 0...");
return;
}
printf("== PrintMidiDevices() == \n");
for (unsigned int i = 0; i < nMidiDeviceNum; ++i) {
midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
printf("\t%d : name = %s\n", i, caps.szPname);
}
printf("=====\n");
}
void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch(wMsg) {
case MIM_OPEN:
printf("wMsg=MIM_OPEN\n");
break;
case MIM_CLOSE:
printf("wMsg=MIM_CLOSE\n");
break;
case MIM_DATA:
printf("wMsg=MIM_DATA, dwInstance=%08x, dwParam1=%08x, dwParam2=%08x\n", dwInstance, dwParam1, dwParam2);
break;
case MIM_LONGDATA:
printf("wMsg=MIM_LONGDATA\n");
break;
case MIM_ERROR:
printf("wMsg=MIM_ERROR\n");
break;
case MIM_LONGERROR:
printf("wMsg=MIM_LONGERROR\n");
break;
case MIM_MOREDATA:
printf("wMsg=MIM_MOREDATA\n");
break;
default:
printf("wMsg = unknown\n");
break;
}
return;
}
int main(int argc, char* argv[])
{
HMIDIIN hMidiDevice = NULL;;
DWORD nMidiPort = 0;
UINT nMidiDeviceNum;
MMRESULT rv;
PrintMidiDevices();
nMidiDeviceNum = midiInGetNumDevs();
if (nMidiDeviceNum == 0) {
fprintf(stderr, "midiInGetNumDevs() return 0...");
return -1;
}
rv = midiInOpen(&hMidiDevice, nMidiPort, (DWORD)(void*)MidiInProc, 0, CALLBACK_FUNCTION);
if (rv != MMSYSERR_NOERROR) {
fprintf(stderr, "midiInOpen() failed...rv=%d", rv);
return -1;
}
midiInStart(hMidiDevice);
while(true) {
if (!_kbhit()) {
Sleep(100);
continue;
}
int c = _getch();
if (c == VK_ESCAPE) break;
if (c == 'q') break;
}
midiInStop(hMidiDevice);
midiInClose(hMidiDevice);
hMidiDevice = NULL;
return 0;
}
Code:
-------------- Build: Debug in midi in test (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -fexceptions -g -I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared" -IC:\dev_libs\portaudio\include -IC:\dev_libs\portaudio\src\common -IC:\dev_libs\SDL2-2.0.9\i686-w64-mingw32\include\SDL2 -IC:\dev_libs\midi_wrapper -c "C:\dev\midi in test\main.cpp" -o obj\Debug\main.o
mingw32-g++.exe -LC:\dev_libs\portaudio\bindings\cpp\lib -o "bin\Debug\midi in test.exe" obj\Debug\main.o -lwinmm -lwinmm
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/unknwn.h:15:0,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/commdlg.h:470,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:86,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/oaidl.h:225:3: error: pasting "/" and "/" does not give a valid preprocessing token
_VARIANT_BOOL *pbool;
^
In file included from C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/minwindef.h:182:0,
from C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/windef.h:24,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:48,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:2420:3: error: '_ANONYMOUS_STRUCT' does not name a type
_ANONYMOUS_STRUCT struct {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:2433:3: error: '_ANONYMOUS_STRUCT' does not name a type
_ANONYMOUS_STRUCT struct {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:2751:2: error: '_ANONYMOUS_STRUCT' does not name a type
_ANONYMOUS_STRUCT struct {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:2755:4: error: 'DUMMYSTRUCTNAME' does not name a type
} DUMMYSTRUCTNAME;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3146:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3149:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3220:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3223:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3271:1: error: '_ANONYMOUS_STRUCT' does not name a type
_ANONYMOUS_STRUCT typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3287:3: error: 'IMAGE_RESOURCE_DIRECTORY_ENTRY' does not name a type
} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3389:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3392:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3436:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3439:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3447:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winnt.h:3466:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:49:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/wincon.h:110:1: error: expected initializer before 'KEY_EVENT_RECORD'
KEY_EVENT_RECORD;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/wincon.h:124:3: error: 'KEY_EVENT_RECORD' does not name a type
KEY_EVENT_RECORD KeyEvent;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/wincon.h:189:34: error: 'PCVOID' has not been declared
BOOL WINAPI WriteConsoleA(HANDLE,PCVOID,DWORD,PDWORD,PVOID);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/wincon.h:190:34: error: 'PCVOID' has not been declared
BOOL WINAPI WriteConsoleW(HANDLE,PCVOID,DWORD,PDWORD,PVOID);
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:50:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:613:16: error: redefinition of 'struct _FILETIME'
typedef struct _FILETIME {
^
In file included from C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/windef.h:24:0,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:48,
from C:\dev\midi in test\main.cpp:2:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/minwindef.h:271:16: error: previous definition of 'struct _FILETIME'
typedef struct _FILETIME {
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:50:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:616:3: error: conflicting declaration 'typedef int FILETIME'
} FILETIME,*PFILETIME,*LPFILETIME;
^
In file included from C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/windef.h:24:0,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:48,
from C:\dev\midi in test\main.cpp:2:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/minwindef.h:274:3: note: previous declaration as 'typedef struct _FILETIME FILETIME'
} FILETIME, *PFILETIME, *LPFILETIME;
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:50:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:616:13: error: conflicting declaration 'typedef int* PFILETIME'
} FILETIME,*PFILETIME,*LPFILETIME;
^
In file included from C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/windef.h:24:0,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:48,
from C:\dev\midi in test\main.cpp:2:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/minwindef.h:274:14: note: previous declaration as 'typedef struct _FILETIME* PFILETIME'
} FILETIME, *PFILETIME, *LPFILETIME;
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:50:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:616:24: error: conflicting declaration 'typedef int* LPFILETIME'
} FILETIME,*PFILETIME,*LPFILETIME;
^
In file included from C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/windef.h:24:0,
from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:48,
from C:\dev\midi in test\main.cpp:2:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared/minwindef.h:274:26: note: previous declaration as 'typedef struct _FILETIME* LPFILETIME'
} FILETIME, *PFILETIME, *LPFILETIME;
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:50:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1017:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1023:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1104:2: error: '_ANONYMOUS_UNION' does not name a type
_ANONYMOUS_UNION union {
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1115:4: error: 'DUMMYUNIONNAME' does not name a type
} DUMMYUNIONNAME;
^
In file included from C:/Program Files (x86)/CodeBlocks/MinGW/include/Windows.h:50:0,
from C:\dev\midi in test\main.cpp:2:
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1482:1: error: 'DECLSPEC_NORETURN' does not name a type
DECLSPEC_NORETURN WINBASEAPI void WINAPI ExitProcess(UINT);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1483:1: error: 'DECLSPEC_NORETURN' does not name a type
DECLSPEC_NORETURN WINBASEAPI void WINAPI ExitThread(DWORD);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1536:53: error: 'PCVOID' has not been declared
WINBASEAPI BOOL WINAPI FlushInstructionCache(HANDLE,PCVOID,DWORD);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1537:40: error: 'PCVOID' was not declared in this scope
WINBASEAPI BOOL WINAPI FlushViewOfFile(PCVOID,DWORD);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1537:52: error: expected primary-expression before ')' token
WINBASEAPI BOOL WINAPI FlushViewOfFile(PCVOID,DWORD);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1537:52: error: expression list treated as compound expression in initializer [-fpermissive]
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1538:46: error: 'PCVOID' has not been declared
WINBASEAPI DWORD WINAPI FormatMessageA(DWORD,PCVOID,DWORD,DWORD,LPSTR,DWORD,va_list*);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1539:46: error: 'PCVOID' has not been declared
WINBASEAPI DWORD WINAPI FormatMessageW(DWORD,PCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list*);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1543:1: error: 'DECLSPEC_NORETURN' does not name a type
DECLSPEC_NORETURN WINBASEAPI void WINAPI FreeLibraryAndExitThread(HMODULE,DWORD);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1795:40: error: 'PCVOID' was not declared in this scope
WINBASEAPI HGLOBAL WINAPI GlobalHandle(PCVOID);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1821:47: error: 'PCVOID' has not been declared
WINBASEAPI DWORD WINAPI HeapSize(HANDLE,DWORD,PCVOID);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1823:50: error: 'PCVOID' has not been declared
WINBASEAPI BOOL WINAPI HeapValidate(HANDLE,DWORD,PCVOID);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1866:41: error: 'PCVOID' was not declared in this scope
WINBASEAPI BOOL WINAPI IsBadHugeReadPtr(PCVOID,UINT);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1866:52: error: expected primary-expression before ')' token
WINBASEAPI BOOL WINAPI IsBadHugeReadPtr(PCVOID,UINT);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1866:52: error: expression list treated as compound expression in initializer [-fpermissive]
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1868:37: error: 'PCVOID' was not declared in this scope
WINBASEAPI BOOL WINAPI IsBadReadPtr(PCVOID,UINT);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1868:48: error: expected primary-expression before ')' token
WINBASEAPI BOOL WINAPI IsBadReadPtr(PCVOID,UINT);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1868:48: error: expression list treated as compound expression in initializer [-fpermissive]
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1878:38: error: 'PCVOID' was not declared in this scope
WINBASEAPI BOOL WINAPI IsTextUnicode(PCVOID,int,LPINT);
^
C:/Program Files (x86)/CodeBlocks/MinGW/include/winbase.h:1878:45: error: expected primary-expression before 'int'
Process terminated with status 1 (0 minute(s), 20 second(s))
50 error(s), 0 warning(s) (0 minute(s), 20 second(s))
-
Do you have any reason to think the headers in "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared" are compatible with Mingw GCC you are using?
Tim S.
-
-
Thanks very much, I managed to get it sorted in the end. I started a fresh project small - at first a "Hello World" project to which I added the line #include <mmsystem.h>, then declared the callback function (the same one I used before), etc.
This time it worked in the end and the only difference in the project's settings was the inclusion of "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared" as a search directory in the older project, so you were right to point that out.
I'm not sure why that was there - I don't remember putting it there (but I must have).
Removing it fixed it!
I then re-acquainted myself with the structure of MIDI messages, made a union to quickly convert the 32-bit ints from the callback into individual bytes, and filled in the callback function to echo info on the messages being received:
Code:
== PrintMidiDevices () ==
0 : name = UMA25S
=====
Message is a channel message for Ch 0 at timestamp 2034ms
Note ON! Key no 60, velocity 106
Message is a channel message for Ch 0 at timestamp 2161ms
Note OFF! Key no 60, velocity 15
Message is a channel message for Ch 0 at timestamp 7923ms
Controller change! Volume changed to 1
Message is a channel message for Ch 0 at timestamp 8008ms
Controller change! Volume changed to 2
Message is a channel message for Ch 0 at timestamp 8134ms
Controller change! Volume changed to 3
Message is a channel message for Ch 0 at timestamp 22125ms
Pitch bend! Value = 8320
Message is a channel message for Ch 0 at timestamp 22182ms
Pitch bend! Value = 8448
Message is a channel message for Ch 0 at timestamp 22520ms
Pitch bend! Value = 8320
It's going well on the MIDI side now, this could form the basis of a software synth but I'm having a ton of trouble with the audio side. After struggling with Port Audio, not being able to find a lib file I then found out that you were meant to compile your own.
Not knowing how I just kept adding Port Audio source files to the project (a different project, for testing audio) until it eventually compiled. Now it generates a runtime error saying it can't find the default sound device.
But that's another story for another thread.
-
Thanks very much, I managed to get it sorted in the end. I started a fresh project small - at first a "Hello World" project to which I added the line #include <mmsystem.h>, then declared the callback function (the same one I used before), etc.
This time it worked in the end and the only difference in the project's settings was the inclusion of "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared" as a search directory in the older project, so you were right to point that out.
I'm not sure why that was there - I don't remember putting it there (but I must have).
Removing it fixed it!
I then re-acquainted myself with the structure of MIDI messages, made a union to quickly convert the 32-bit ints from the callback into individual bytes, and filled in the callback function to echo info on the messages being received:
Code:
== PrintMidiDevices () ==
0 : name = UMA25S
=====
Message is a channel message for Ch 0 at timestamp 2034ms
Note ON! Key no 60, velocity 106
Message is a channel message for Ch 0 at timestamp 2161ms
Note OFF! Key no 60, velocity 15
Message is a channel message for Ch 0 at timestamp 7923ms
Controller change! Volume changed to 1
Message is a channel message for Ch 0 at timestamp 8008ms
Controller change! Volume changed to 2
Message is a channel message for Ch 0 at timestamp 8134ms
Controller change! Volume changed to 3
Message is a channel message for Ch 0 at timestamp 22125ms
Pitch bend! Value = 8320
Message is a channel message for Ch 0 at timestamp 22182ms
Pitch bend! Value = 8448
Message is a channel message for Ch 0 at timestamp 22520ms
Pitch bend! Value = 8320
It's going well on the MIDI side now, this could form the basis of a software synth but I'm having a ton of trouble with the audio side. After struggling with Port Audio, not being able to find a lib file I then found out that you were meant to compile your own.
Not knowing how I just kept adding Port Audio source files to the project (a different project, for testing audio) until it eventually compiled. Now it generates a runtime error saying it can't find the default sound device.
But that's another story for another thread.