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.