I've started to play around a bit with Linux as a music studio of late.
Some
stuff is up to scratch, some stuff is better and some stuff is way
behind. Its the commercial stuff that is behind, or rather way ahead on
Windows but in the case of music making this means VST plugins are a
pain on Linux. No VST mean no instruments which makes sound quite dull.
I
recently purchased a midi keyboard which comes
with a bunch of analog soft-synths in VST format which I quite fancy
using. The plugin failed to load in the VSTi plugin in LMMS. There was
no claim from the manufacturer that they might work. With that fail I
needed to hook up my LMMS / Hydrogen / Jack setup up running on my main
PC to a Vista box I have that can run the VST plugins.
I started
by spending a day shopping for midi hardware before coming up with
nothing under 100€ and needing two of them. This struck me as too much
for an ameture tekno hack like myself. On the way back from the shops I
resolved to write some midi over IP software since it was not going to
be hard, I figured. It is not a tricky job midi over IP you need to sent
4 bytes of digital data across the wire and Ethernet speeds nowadays
are easily fast enough.
Before I got started I checked what was
out there on the net to see if there was anything that would just work
out of the box. It seems there is progress.
Mac has midi over IP built in to the operating system which is handy for mac users.
Linux
has a couple of options that work fine, multimidicast is nice and
simple and does exactly what I wanted it too. Trouble is, the Windows
side is a pay tool to be found at http://nerds.de, not free software.
There
are plenty of options if you fancy paying up real money but we are
talking about 4 bytes of un-modified data over the wire so I thought Id
rectify the Lin-Win interop issues myself. multimidicast is designed to
be compatible with ipMidi from nerds.de so that was my starting point.
I
thought I'd try to just port multimidicast code to Windows, but in the
end that was not going to happen. The ALSA part (the midi side of
things) is obvioulsy Linux specific thats half the code anyway. The
network side should be posix compatible but writing C in for Windows you
always end up getting sucked in to proprietory stuff there is really no
point trying to write portable code IMHO. It was only going to be 1000
lines of code anyway, so I started with a blank page. A blank page has
the advantage of meaning I can apply GPLv3 to the code I write.
Windows
MultiMedia has some failrly straight-forward midi APIs with some really
shitty documentation, as usual and no example code. Once you get it
working it all looks pretty simple. In the world of open source you get
used to the fact that you have top quality example code for everything
you might like to do. Not so with Windows C, its a dark art. It took me
too long to find out that the header I needed was called mmsystem.h and
the DLL is called winmm.dll and the linking should be done with -lwinmm.
For winsock I have to include winsock2.h Ws2tcpip.h mswsoc.h the dll is WINSOCK.DLL and you link with -lwsock32.
Perhaps
there is some logic to Microsoft naming conventions, but it seems there
just is no convention at all. Case is significant in C code and MS
libraries are all over the shop so it is impossible to take educated
guesses at where to start googling.
After spending a while day
with firefox open and textpad to write the C I found a few good
articles, notably, nothing hosted at MSDN. With some example code I had
enough to search MSDN and from there could bash out the first few lines
of code. MSDN docs there are perhaps sufficient if you have plenty of C
on Windows experience, but I dont. After about half a days scribbling I
had something up and running that would read packets from the LAN and
send them to midi. I wasted a lot of time on the fact that Linux APIs
return error codes and Windows return random numbers, again no
conventions, and WSAGetLastError() is where the real error is to be
found. Turns out I was listening to multicast about 2 hours before I
new I was, since the return code was not as I expected it to be. Winsock
is based on Berkley sockets, but that base was taken a long time ago
and the similarites are now lost and just confuse more than they help.
Next
step was to hook up the midi to a "real" soft-synth, and here we enter
frustrating terriroy. It turns out to talk to the instrument a piece of
the puzzle is missing, you need a virtual midi device and this is a
software driver. Presumably one that does very little, but a driver
none the less and that means kernel code. I've been down this route
before and its a pain in the arse, essentially Microsoft reserve the
right to tell you what you are doing is not allowed and to get your
driver work in you have to have it signed, that costs money. You can
not write you own code on your own PC in the world of Microsoft they
still own your hardware. Slightly scared I would hit a brick wall again
I scoured the net for virtual midi software and came up with,
thankfully, a few options. The rtsMidi tool that is a mac compatible
midi over IP thing works in Windows and has a virtual midi driver you
can download for free. Nerds.de also have a virtual midi device that you
can download for free and the basic version does not have a 60 minutes
usage limit. This enabled me to skip the driver writing and plug in my
VST instruments onto the network. A bit more fiddling and another 100
lines of frustrating code and LMMS can trigger my VST soft synths, nice.
Since
I'd got this far, I figured it made sense to get the app to work in the
other direction, taking midi from a real or virtual device and
broadcasting it onto the network. This was as frustrating a job too.
Mostly because to read midi you can only have ONE line of code in you
APP that opens the device, not two. This is wierd since it is farily
mormal to have multiple sources and sinks in the world of middi. Having
one APP with a main loop listenting for midi events and another for
listening for network events meant two threads. In Linux since ALSA
uses the same APIs that the network does you only need one. Threading is
C is a dark art too it seems. There are APIs that just dont work. You
find this out by googling, MSDN makes no mention of the fact that the
seemingly handly looking method called CreateThread will break your C
app if you use it. The much clearer named _beginthreadex is the method
you want. This was the first function I have found all day that starts
with an underscore; wins points for originality I suppose.
The Windos
midi APIs are split down the middle with IN and OUT very seprate so
despite having two threads there was nothing shared and no need to
synchronize. This is good since I don't fancy writing thread safe code
with guess work. To write thread safe code you need to know that what
you are doing is correct. You can't test it, it could run for days
before blowing up just by chance.
At the end of the day I have
got somewhere, I now have Linux and Windows talking happily over midi. I
can plug the hardware device in either PC and bang the keys and make
that trigger whatever I like. Latency in Linux is exceptionally low, not
so in Windows. Tomorrow's job is to get Windows midi to play the note
when I tell it to not 100ms after.
Code is here, there is an exe there too with a
README. The code is fairly ledgibubble if you feel like modding it.
No comments:
Post a Comment