Created
June 30, 2017 13:27
-
-
Save mmalex/c5b61f824d55cf6dff8a53b451af3392 to your computer and use it in GitHub Desktop.
This file contains 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
/* | |
quick midi 2 osc hack by @mmalex, use at your own risk etc | |
reads midi messages, forward them to osc messages on your network. | |
barely tested but works for me in windows 7, compiled with msvc 2015 sp2 | |
stick a midi2osc.ini file in the same folder as the exe to configure it, with lines like these: | |
IP=43.193.207.78 | |
Port=9000 | |
Log=1 | |
Device=0 | |
Device sets the midi device number (as enumerated by windows, sorry). | |
Log dumps midi messages to console window | |
IP and Port say where to send the osc messages, which are all just addressed to /midi with a single integer parameter with the 3 byte standard midi message packed into it. | |
*/ | |
#define _WINSOCK_DEPRECATED_NO_WARNINGS | |
#define _CRT_SECURE_NO_WARNINGS | |
#include <winsock2.h> // for sockets | |
#include <conio.h>// for _getch | |
#include <stdio.h> // for printf | |
#include <ws2tcpip.h> // for getaddrinfo | |
#pragma comment(lib,"winmm.lib") // for midi | |
#pragma comment(lib,"ws2_32.lib") // for sockets | |
const char *GetIniSetting(const char *key, const char *default_value); // simple ini file parser (see the end of this file) | |
int log=0; | |
SOCKET fd; | |
struct addrinfo* addr=0; | |
void CALLBACK midicb( HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { | |
if (wMsg==MIM_DATA) { | |
char oscmsg[16]="/midi\0\0\0,i\0\0\0\0\0"; | |
oscmsg[15]=(unsigned char)dwParam1; | |
oscmsg[14]=(unsigned char)(dwParam1>>8); | |
oscmsg[13]=(unsigned char)(dwParam1>>16); | |
if (log) printf("%02x %02x %02x\r",oscmsg[15],oscmsg[14],oscmsg[13]); | |
if (sendto(fd,oscmsg,16,0,addr->ai_addr,addr->ai_addrlen)<0) | |
printf("failed to send udp packet!\n"); | |
} | |
} | |
int main(int argc, char **argv) { | |
WSADATA wsadata={}; | |
WSAStartup(MAKEWORD(2,2),&wsadata); | |
const char *ip=GetIniSetting("IP","127.0.0.1"); | |
const char *port=GetIniSetting("Port","9000"); | |
UINT devid=atoi(GetIniSetting("Device","0")); | |
log=atoi(GetIniSetting("Log","0")); | |
printf("midi2osc - sending to %s:%s, logging=%d, device=%d\npress escape to quit\n",ip,port,log,devid); | |
struct addrinfo hints={}; | |
hints.ai_family=AF_UNSPEC; | |
hints.ai_socktype=SOCK_DGRAM; | |
hints.ai_protocol=0; | |
hints.ai_flags=AI_ADDRCONFIG; | |
if (getaddrinfo(ip,port,&hints,&addr)!=0) return printf("failed to resolve remote socket address"); | |
fd=socket(addr->ai_family, addr->ai_socktype,addr->ai_protocol); | |
if (fd<0) return printf("failed to open socket %s\n",strerror(errno)); | |
UINT numdevs=midiInGetNumDevs(); | |
for (UINT d=0;d<numdevs;++d) { | |
MIDIINCAPS caps; | |
if (midiInGetDevCaps(d,&caps, sizeof(caps))==MMSYSERR_NOERROR) { | |
printf("%c%d: %s\n",d==devid?'*':' ',d,caps.szPname); | |
} | |
} | |
HMIDIIN hmidi={}; | |
if (midiInOpen(&hmidi, devid, (DWORD_PTR)midicb, 0, CALLBACK_FUNCTION)!=MMSYSERR_NOERROR) return printf("failed to midiInOpen\n"); | |
if (midiInStart(hmidi)!=MMSYSERR_NOERROR) return printf("failed to midiInStart\n"); | |
while (_getch()!=27) ; | |
midiInStop(hmidi); | |
midiInClose(hmidi); | |
return 0; | |
} | |
////////////////////////////// simple ini parser | |
char *settings=0; | |
void LoadIniSettings() { | |
settings=""; | |
FILE *f=fopen("midi2osc.ini","rb"); | |
if (!f) return ; | |
fseek(f,0,SEEK_END); | |
int l=ftell(f); | |
char *dst=settings=(char*)calloc(1,l+4); | |
fseek(f,0,SEEK_SET); | |
while (!feof(f)) { | |
char *odst=dst; | |
char linebuf[256]={}; | |
if (!fgets(linebuf,255,f)) break; | |
const char *src=linebuf; | |
while (*src && isspace(*src)) ++src; // skip white space | |
if (*src=='#') continue; // comment | |
const char *ks=dst; | |
while (*src && !isspace(*src) && *src!='=') *dst++=*src++; // copy key | |
if (dst==ks) {dst=odst; continue; } // empty key | |
*dst++=0; // null terminate key | |
while (*src && isspace(*src)) ++src; // skip white space after key | |
if (*src++!='=') {dst=odst; continue; } // no equals sign | |
while (*src && isspace(*src)) ++src; // skip white space after = | |
const char *vs=dst; | |
while (*src && *src!='\r' && *src!='\n' && *src!='#') *dst++=*src++; // copy value to end of line | |
while (dst>vs && isspace(dst[-1])) --dst; // trim trailing spaces | |
*dst++=0; // null terminate value | |
} | |
fclose(f); | |
*dst++=0; *dst++=0; // empty string to terminate settings | |
} | |
const char *GetIniSetting(const char *key, const char *default_value) { | |
if (!settings) LoadIniSettings(); | |
for (const char *s=settings;*s;) { | |
const char *val=s+strlen(s)+1; | |
if (strcmp(s,key)==0) return val; | |
s=val+strlen(val)+1; | |
} | |
return default_value; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment