<< >>
justin = { main feed , music , code , askjf , pubkey };
[ <<< last (older) article | view in index | next (newer) article >>> ]

November 14, 2013
another quick project - Cockos midi2osc

Making installers and web pages is too much of a pain for a small project, so:

Here's another project, this one took less than 24 hours to make. It's a little win32 program called "midi2osc" (license: GPL, binary included, code requires WDL to compile), and it simply listens to any number of MIDI devices, and broadcasts to any number of destinations via OSC-over-UDP.

MIDI and OSC use completely different types of encoding -- MIDI consists of 1-3 byte sequences (excluding sysex), and OSC is encoded as a string and any number of values (strings, floats, integers, whatever). It would be very easy to make a simplistic conversion of every MIDI event, such as 90 53 7f being converted to "/note/on/53" with an integer value of 7f, and so on. This would be useful, but also might be somewhat limited.

In order to make this as useful as possible, I made it use EEL2 to enable user scripting of events. EEL2 is a fast scripting engine designed for floating point computation, that was originally developed as part of Nullsoft AVS, and evolved as part of our Jesusonic/JSFX code. EEL2 compiles extremely quickly to native code, and can have context that is used by code running in multiple threads simultaneously.

For this project the EEL2 syntax was extended slightly, via the use of a preprocessor, so that you can specify format strings for OSC. For example, you can tell REAPER to set a track's volume via:

    oscfmt0 = trackindex;
    oscsend(destination, { "/track/%.0f/volume" }, 0.5);
Internally, { xyz } is stored to a string table and inserted as a magic number which refers to that string table entry. It is cheap, but it works.

Other than that pretty much everything else was a matter of copying and pasting some tedious bits (win32 MIDI device input, OSC message construction and bundling) and writing small bits of glue.

Since writing this, I've found myself fixing a lot of small OSC issues in REAPER. I always tell people how using the thing you make is very important -- I should update that to include the necessity of having good test environments (plural).

Why did I make this? My Zoom R24. This is a great device, but the Windows 7/64 driver has some issues. Particularly:
  • If the MIDI input device of the R24 is not opened, audio playback is not reliable. This includes when listening to Winamp or watching YouTube. So basically, for this thing to be useful, I need something to keep hitting the MIDI device constantly. So for you Zoom R24 win64 users who have this problem, midi2osc might be able to fix your problems.
  • If REAPER crashes or is otherwise debugged with the MIDI device open, the process hangs and it's a pain to continue. Moving the MIDI control to a separate process that can run in the system tray = win.
  • (not midi2osc related): I wish the drum pads would send MIDI too... *ahem*
As a result of this, the midi2osc.cfg that comes in the .zip represents basic support for the R24:
// @input lines:
// usage: @input devicenameforcode "substring match" [skip]
// can use any number of inputs. devicenameforcode must be unique, if you specify multiple @input lines
// with common devicenameforcode, it will use the first successful line and ignore subsequent lines with that name
// you can use any number of devices, too

@input r24 "ZOOM R"

// @output lines
// usage: @output devicenameforcode "" [maxpacketsize] [sleepamt]
// maxpacketsize is 1024 by default, can lower or raise depending on network considerations
// sleepamt is 10 by default, sleeps for this many milliseconds after each packet. can be 0 for no sleep.

@output localhost ""


// called at init-time
destdevice = localhost; // can also be -1 for broadcast

// 0= simplistic /track/x/volume, /master/volume
// 1= /r24/rawfaderXX (00-09)
// 2= /action/XY/cc/soft (tracks 1-8), master goes to /r24/rawfader09


// called around 100Hz, after each block of @msg


// special variables:
// time (seconds)
// msg1, msg2, msg3 (midi message bytes)
// msgdev == r24  // can check which device, if we care

(msg1&0xf0) == 0xe0 ? (

  // using this to learn for monitoring fx, rather than master track
  fader_mode > 0 ? (
     fmtstr = { f/r24/rawfader%02.0f }; // raw fader
     oscfmt0 = (msg1&0xf)+1;

     fader_mode > 1 && oscfmt0 != 9 ? (
       fmtstr = { f/action/%.0f/cc/soft }; // this is soft-takeover, track 01-08 volume
       oscfmt0 = ((oscfmt0-1) * 8) + 20;

     val=(msg2 + (msg3*128))/16383;
  ) : (
     fmtstr = (msg1&0xf) == 8 ? { f/master/volume } : { "f/track/%.0f/volume"};
     oscfmt0 = (msg1&0xf)+1;
     oscsend(destdevice,fmtstr,(msg2 + (msg3*128))/16383);

msg1 == 0x90 ? (
  msg2 == 0x5b ? oscsend(destdevice, { b/rewind }, msg3>64);
  msg2 == 0x5c ? oscsend(destdevice, { b/forward }, msg3>64);

  msg3>64 ? (
    oscfmt0 = (msg2&7) + 1;

    msg2 < 8 ?  oscsend(destdevice, { t/track/%.0f/recarm/toggle }, 0) :
      msg2 < 16 ?  oscsend(destdevice, { t/track/%.0f/solo/toggle }, 0) :
        msg2 < 24 ?  oscsend(destdevice, { t/track/%.0f/mute/toggle }, 0) : 
      msg2 == 0x5e ? oscsend(destdevice, { b/play }, 1);
      msg2 == 0x5d ? oscsend(destdevice, { b/stop }, 1);
      msg2 == 0x5f ? oscsend(destdevice, { b/record }, 1);

msg1 == 0xb0 ? (
  msg2 == 0x3c ? (
    oscsend(destdevice, { f/action/992/cc/relative }, ((msg3&0x40) ? -1 : 1));

The 9th fader sends "/r24/rawfader09" because I have that OSC string mapped (with soft-takeover) to a volume plug-in in my monitoring FX chain.

Posted by gio on Fri 15 Nov 2013 at 03:30 from 94.66.14.x
this post is definitely better than p0rn. it has been a while to hear something completely out of the norm. many thanks, it looks like the weekend is approaching with lots of fun.

Posted by tronic on Fri 15 Nov 2013 at 03:57 from 151.20.182.x
oscvolution for all

Posted by Will on Fri 15 Nov 2013 at 07:55 from 70.173.80.x


Posted by Justin on Sat 16 Nov 2013 at 20:20 from 24.164.139.x
I just updated this to have it try to periodically re-open MIDI devices that go away (or didn't exist to begin with). Set and forget ftw.

Posted by Justin on Sun 17 Nov 2013 at 16:09 from 24.164.139.x
and once more for a couple of bugfixes

Posted by Jeffos on Tue 03 Dec 2013 at 09:40 from 46.218.205.x
Thank you (again) for sharing such code examples, Justin!
For the record... Here's another osc2midi config file example:
=> MIDI with 14 bit resolution in REAPER FTW!
=> vague explanations here: forum.cockos.com/showpost.php?p=12...

Add comment:
Human?: (no or yes, patented anti crap stuff here)
search : rss : recent comments : Copyright © 2023 Justin Frankel