Skip to content

Instantly share code, notes, and snippets.

@mmalex
Created June 30, 2017 13:27
Show Gist options
  • Save mmalex/c5b61f824d55cf6dff8a53b451af3392 to your computer and use it in GitHub Desktop.
Save mmalex/c5b61f824d55cf6dff8a53b451af3392 to your computer and use it in GitHub Desktop.
/*
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