Created
January 2, 2019 07:15
-
-
Save antlauzon/b56ec72f3a4cce1fcfbf663eb98893cd to your computer and use it in GitHub Desktop.
WinMM Midi Latency Test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <stdio.h> | |
#include <mmsystem.h> | |
#include <mmreg.h> | |
#include <conio.h> | |
#define BUFFERSIZE 200 | |
#define BUFFEROUTSIZE 120 | |
#define NUM_SEND 500 | |
HANDLE ghMutex; | |
int processedCount = 0; | |
int finished = 0; | |
unsigned char SysXBuffer[256]; | |
unsigned char SysXFlag = 0; | |
LARGE_INTEGER start; | |
LARGE_INTEGER end; | |
LARGE_INTEGER frequency; | |
__int64 sum_latencies = 0; | |
void PrintMidiInErrorMsg(unsigned long err); | |
void PrintMidiOutErrorMsg(unsigned long err); | |
void CALLBACK midiCallback(HMIDIIN handle, | |
UINT uMsg, | |
DWORD dwInstance, | |
DWORD dwParam1, | |
DWORD dwParam2); | |
void sendMidi(UINT deviceId); | |
void listenMidi(UINT deviceId); | |
void listDevices(); | |
void PrintMidiInErrorMsg(unsigned long err) { | |
char buffer[BUFFERSIZE]; | |
if (!(err = midiInGetErrorText(err, &buffer[0], BUFFERSIZE))) { | |
printf("%s\r\n", &buffer[0]); | |
} | |
else if (err == MMSYSERR_BADERRNUM) { | |
printf("Strange error number returned!\r\n"); | |
} | |
else if (err == MMSYSERR_INVALPARAM) { | |
printf("Specified pointer is invalid!\r\n"); | |
} | |
else { | |
printf("Unable to allocate/lock memory!\r\n"); | |
} | |
} | |
void PrintMidiOutErrorMsg(unsigned long err) { | |
char buffer[BUFFEROUTSIZE]; | |
if (!(err = midiOutGetErrorText(err, &buffer[0], BUFFEROUTSIZE))) { | |
printf("%s\r\n", &buffer[0]); | |
} | |
else if (err == MMSYSERR_BADERRNUM) { | |
printf("Strange error number returned!\r\n"); | |
} | |
else { | |
printf("Specified pointer is invalid!\r\n"); | |
} | |
} | |
void CALLBACK midiCallback(HMIDIIN handle, | |
UINT uMsg, | |
DWORD dwInstance, | |
DWORD dwParam1, | |
DWORD dwParam2) | |
{ | |
QueryPerformanceCounter(&end); | |
LPMIDIHDR lpMIDIHeader; | |
unsigned char * ptr; | |
TCHAR buffer[80]; | |
unsigned char bytes; | |
if (uMsg == MIM_DATA) { | |
UCHAR bdata = (UCHAR) (dwParam1 & 0x000000FF); | |
if (bdata == (UCHAR) 0x90 ||bdata == (UCHAR) 0x80) { | |
sum_latencies += (end.QuadPart - start.QuadPart); | |
if (processedCount == NUM_SEND - 1) { | |
__int64 sum_latency_nanos = | |
(sum_latencies* 1000000000)/frequency.QuadPart; | |
__int64 sum_latency_micros = | |
(sum_latencies * 1000000)/frequency.QuadPart; | |
__int64 avg_latency_ticks = sum_latencies / NUM_SEND; | |
__int64 avg_latency_nanos = (sum_latency_nanos / NUM_SEND); | |
__int64 avg_latency_micros = (sum_latency_micros / NUM_SEND); | |
printf("sum_latencies: %lld\n", sum_latencies); | |
printf("avg_latency_ticks: %lld\n", avg_latency_ticks); | |
printf("avg_latency_nanos: %lld\n", avg_latency_nanos); | |
printf("avg_latench_micros: %lld\n", avg_latency_micros); | |
printf("freq: %lld\n", frequency.QuadPart); | |
midiInClose(handle); | |
finished = 1; | |
} | |
processedCount += 1; | |
ReleaseMutex(ghMutex); | |
} | |
} | |
} | |
void sendMidi(UINT deviceId) { | |
HMIDIOUT handle; | |
unsigned long err; | |
union { | |
DWORD dwData; | |
UCHAR bData[4]; | |
} u; | |
u.bData[0] = (UCHAR)0x90; | |
u.bData[1] = (UCHAR)60; | |
u.bData[2] = (UCHAR)127; | |
u.bData[3] = 0; | |
if (!(err = midiOutOpen(&handle, deviceId, 0, 0, CALLBACK_NULL))) { | |
for (int i = 0; i < NUM_SEND; i++) { | |
WaitForSingleObject(ghMutex, INFINITE); | |
QueryPerformanceCounter(&start); | |
if ((err = midiOutShortMsg(handle, u. dwData))) { | |
PrintMidiOutErrorMsg(err); | |
} | |
Sleep(1); | |
if (u.bData[0] == (UCHAR)0x90) { | |
u.bData[0] = (UCHAR)0x80; | |
u.bData[1] = (UCHAR)0x3C; | |
u.bData[2] = (UCHAR)0x7F; | |
} else { | |
u.bData[0] = (UCHAR)0x90; | |
u.bData[1] = (UCHAR)60; | |
u.bData[2] = (UCHAR)127; | |
} | |
} | |
midiOutClose(handle); | |
} else { | |
printf("Error opening the default MIDI Out device!\r\n"); | |
PrintMidiOutErrorMsg(err); | |
} | |
} | |
void listenMidi(UINT deviceId) { | |
HMIDIIN handle; | |
MIDIHDR midiHdr; | |
unsigned long err; | |
if (!(err = midiInOpen(&handle, | |
deviceId , | |
(DWORD)midiCallback, | |
0, | |
CALLBACK_FUNCTION))) { | |
midiHdr.lpData = (LPBYTE)&SysXBuffer[0]; | |
midiHdr.dwBufferLength = sizeof(SysXBuffer); | |
midiHdr.dwFlags = 0; | |
err = midiInPrepareHeader(handle, &midiHdr, sizeof(MIDIHDR)); | |
if (!err) { | |
err = midiInAddBuffer(handle, &midiHdr, sizeof(MIDIHDR)); | |
if (!err) { | |
err = midiInStart(handle); | |
if (!err) { | |
printf("\r\nListening!\n"); | |
} | |
} | |
} | |
if (err) PrintMidiInErrorMsg(err); | |
} else { | |
printf("Error opening the default MIDI In Device!\r\n"); | |
PrintMidiInErrorMsg(err); | |
} | |
} | |
void listDevices() { | |
MIDIOUTCAPS moc; | |
MIDIINCAPS mic; | |
long iNumDevs, i; | |
char buffer[80]; | |
unsigned char chr; | |
MMRESULT mmerr; | |
// Midi Mapper is -1 Device | |
iNumDevs = midiOutGetNumDevs(); | |
printf("numOutDevs %d\n", iNumDevs); | |
for (i = 0; i < iNumDevs; i++) { | |
if (!i) printf("MIDI Output Devices =======================\r\n\n"); | |
if (!midiOutGetDevCaps(i, &moc, sizeof(MIDIOUTCAPS))) { | |
printf("\r\n Device ID #%ld: %s\r\n", i, moc.szPname); | |
} | |
} | |
iNumDevs = midiInGetNumDevs(); | |
for (i = 0; i < iNumDevs; i++) { | |
if (!i) printf("\r\nMIDI Input Devices =======================\r\n"); | |
if (!midiInGetDevCaps(i, &mic, sizeof(MIDIINCAPS))) { | |
printf("\r\n Device ID #%ld: %s\r\n", i, mic.szPname); | |
} | |
} | |
} | |
int main(int argc, char **argv) { | |
ghMutex = CreateMutex(NULL, FALSE, NULL); | |
if (argc < 3) { | |
listDevices(); | |
} else { | |
UINT deviceIdIn = (UINT) atoi(argv[1]); | |
UINT deviceIdOut = (UINT) atoi(argv[2]); | |
start.QuadPart = 0; | |
end.QuadPart = 0; | |
QueryPerformanceFrequency(&frequency); | |
listenMidi(deviceIdIn); | |
sendMidi(deviceIdOut); | |
while (!finished) { | |
Sleep(0); | |
} | |
CloseHandle(ghMutex); | |
} | |
return(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment