Midi Proxy

I don't have an access to my MIDI keyboard from the browser because there doesn't exist an API for that. Since it has disappointed me for some while today I wrote a proxy which would relay the MIDI events to the browser. Midi Proxy is the outcome.

What's it doing exactly?

It will look for files beginning with midi from /dev/snd -directory. It opens every file into nonblocking mode, and starts reading them concurrently. Meanwhile it constructs a websocket server. Connected websockets are added into a list. The MIDI events it understands are translated into json-messages and broadcasted to every connected websocket. If browser accesses server, it will get the demonstration files in the www/ -directory.

MIDI messages are an amazing protocol

MIDI's been around for a long time. I think it has managed because it's one of the simplest, nicest protocols I've seen. It makes you wonder what went wrong with other HID devices that aren't nearly as simple to access. Specs were easy to find even today.

asyncio

The midi proxy has lot of things that happen in parallel, entirely asyncronously. The code itself is deceivingly simple. I'm using codeflow.org's asyncio. It is collection of modules built over python greenlets.

When you're using asyncio, you're basically writing code just as if it was plain old syncronous code. When the execution reaches a socket read, or some other method defined by asyncio, a greenlet switch happens which turns the program to the event loop. The event loop pick the next task which can be evaluated. It's bit like a small operating system within your process, which is doing co-operative multitasking.

asyncio has not been documented in any way, so you have to read how it works from the source. You end up with better idea about it's internals, which has some benefits. For instance the asyncio did not provide asyncronous file access by default, so I wrote myself enough support. That's the stream.py -file in my repository.

How to use it?

So how to use the Midi Proxy? First get it running, the repository has some install instructions. After install, you can write the following coffeescript code to access the messages:

ws = new WebSocket('ws://localhost:9898/')
ws.onopen = (evt) ->
    info 'connected'
ws.onclose = (evt) ->
    info 'disconnected'
ws.onmessage = (evt) ->
    message = JSON.parse(evt.data)
    switch message.type
        when 'note'
            if message.press
                console.log "press",   message.note, message.velocity
            else
                console.log "release", message.note, message.velocity
ws.onerror = (evt) ->
    info "error: #{evt.data}"

It only supports note press and release now. The beautiful thing is that the midi-proxy.py is just 65 lines long and it contains all the logic alone. Feel free to peek in. You may very well understand how to make it support larger set of messages fitting the MIDI instruments you own.

That's it. I hope you enjoy the results.

Similar posts