2013-03-09

Raspberry Pi midi driven solenoid bell

This is completely pointless but a bit of fun I had to share. I've been thinking about hooking my Roland TD9 v-drum kit up to a Raspberry Pi for a while for another project so I bought a really cheap Midi to USB gadget: USB Midi Cable Lead Adaptor

To my surprise this worked out-the-box, nothing to install. I made sure my Raspbian OS was up to date before I started but that was it. I have never done anything with Midi before but I knew it was a simple serial protocol and so assumed I'd be able to open some kind of tty device. In fact the ALSA driver on the OS detects it correctly as a USB-Midi input/ouput device. You can see this by running the amidi command:
pi@raspberrypi ~ $ amidi -l
Dir Device    Name
IO  hw:1,0,0  USB2.0-MIDI MIDI 1
 O  hw:1,0,1  USB2.0-MIDI MIDI 2

There are probably loads of proper Midi tools you can use since it has been discovered correctly by I just wanted to look at the raw bytes coming in. The device node that's been created in the file system can be found in /dev/snd:
pi@raspberrypi ~ $ ls /dev/snd
by-id  by-path  controlC0  controlC1  midiC1D0  pcmC0D0p  seq  timer

So all my program has to do is read bytes from /dev/snd/midiC1D0. To get this to work I didn't need to understand or decode much of the protocol - I'm basically just looking for a sequence when an "instrument" is hit. In this case it is a sequence (in hex) of 99 XX where XX is the instrument code, 26 for snare drum, 24 for kick drum etc. There's a lot more going on but I can ignore the rest apart from a useful continual pulse of FE. This is known as "Active sense" and you get this once every 300ms. I'm using this to switch the GPIO off again as you'll see in the code later. In order to ring the bell you need a quick on/off motion. You can read more about the solenoid bell in my previous post: Raspberry Pi solenoid alarm bell.

Anyway, here's a rather shakey video (sorry) and the code. Enjoy!


import RPi.GPIO as GPIO

inst = {
        '\x26':'snare',
        '\x28':'snare rim',
        '\x30':'tom1',
        '\x32':'tom1 rim',
        '\x2d':'tom2',
        '\x2f':'tom2 rim',
        '\x2b':'tom3',
        '\x3a':'tom3 rim',
        '\x24':'kick',
        '\x1a':'hi-hat rim',
        '\x2e':'hi-hat head',
        '\x2c':'hi-hat close',
        '\x31':'crash head',
        '\x37':'crash rim',
        '\x33':'ride head',
        '\x3b':'ride rim',
        '\x35':'ride bell',
}

f=open('/dev/snd/midiC1D0')

note=False

GPIO_NUM = 18
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_NUM, GPIO.OUT)

while True:
        b = f.read(1)
        if b == '\xfe':
                GPIO.output(GPIO_NUM, False)
        else:
#               if b == '\x40':
#                       print hex(ord(b))
#               else:
#                       print hex(ord(b)),
                if b == '\x99':
                        note=True
                elif note:
                        if b in inst:
                                print inst[b]
                                if b == '\x26':
                                        GPIO.output(GPIO_NUM, True)
                        else:
                                print hex(ord(b))
                        note=False

No comments: