/twilio-keyboard

🎹 An (old) tutorial detailing how to control a USB-enabled MIDI keyboard via SMS, using the Twilio API.

Primary LanguageRubyOtherNOASSERTION

Although Twilio is well-known to developers, it has yet to make a mark in the world of music. This is a shame, because (with a little help) Twilio can lay down a funky solo that would make Billy Joel proud. We'll make an app which will let you text a tune to a Twilio number, and have it played on your keyboard almost instantly. It's sort of the 21st century equivalent of teaching a monkey to play the piano.

Monkey on piano

You'll need

  • A Twilio account
  • A MIDI keyboard hooked up to your dev machine (I'm using a Casio LK-300TV connected via USB)
  • Ruby 1.9+

Making sweet music

First clone the repo and install the necessary gems:

git clone https://github.com/alexpeattie/twilio-keyboard.git
cd twilio-keyboard/
bundle install

The app works its magic with a simple 30-line ruby file: server.rb - we're going to remake it from scratch, so rename the existing version server_old.rb and create a blank server.rb in your favourite text editor.

First we'll need to require the awesome micromidi gem, which we'll use to interact our with keyboard:

require 'midi'

Next we need to load our MIDI device:

output = UniMIDI::Output[0]

(If you have more than one device - you lucky thing - you might need to change 0 to the index of your desired output). micromidi uses a cool DSL with a wealth of commands, we'll only use two for now: note and off:

MIDI.using(output) do
  note "G"
  sleep 0.5  # wait for half a second
  off  # end the note
end

Run your script with ruby server.rb. Hopefully you'll hear your keyboard play half a second of G! If not, you might have to use a different MIDI channel:

note "G", channel: 5

One note does not a melody make, however, so let's add the ability to play a tune. We'll iterate through a simple string of notes like "C Ab E E G C#", playing each in turn:

tune = "C Ab E E G C#"
MIDI.using(output) do

  tune.split(" ").each do |n|
    note n
    sleep 0.5
    off
  end

end

One final thing we're missing is the ability to add pauses - let's use an underscore to skip a beat:

note n unless n == "_"

Come fly with me

Now we've got control of our keyboard, we need a way to let it talk to Twilio. Let's make a simple web server using the appropriately-named Sinatra.

We'll also launch the server on top of Rack, which means we can get rid of require 'midi' - Rack will load our gems automatically from our Gemfile. Let's create a class to contain our app:

class MidiServer < Sinatra::Base
  # ..existing code
end

Now, all that's left to do is wrap our code in a get block:

class MidiServer < Sinatra::Base
  get '/play' do
    # ...existing code 
  end
end

That's it! Run rackup from your console, and go to www.local.host:4567/play - your keyboard should automatically play your ditty.

Tunneling out

We're almost ready to add Twilio to the mix. But we want Twilio to be able to play an arbitrary tune, based on the body of the SMS message we send. Twilio's going to send the data by POST rather than GET, in a parameter called "Body". So we want our code to look like:

post "/play" do
  output = UniMIDI::Output[0]
  
  tune = params["Body"]
  MIDI.using(output) do
    # blah blah...
  end
end

Let's also move the output = UniMIDI::Output[0] outside of the post block, so we're only loading our MIDI device once (when the server starts).

The last problem is that localhost is only accessible on our dev machine - i.e. Twilio won't have access to it. Luckily the localtunnel gem solves that - see the Twilio docs for full instructions.

localtunnel 4567
Port 4567 is now publicly accessible from http://4jns.localtunnel.com ...

You can test everything's working using curl:

curl --data "Body=C A G" http://4jns.localtunnel.com/play

Twilio time!

You'll need to buy a Twilio number if you don't already have one. Go to the settings for the number you want to use (via the Numbers dashboard) - and set the SMS Request URL to your localtunnel URL (e.g. http://4jns.localtunnel.com/play).

You're done! Sit back, text a tune to your Twilio number and enjoy.

Turning it up to eleven

So you've turned Twilio into a musical prodigy. Now what?

If you open up server_old.rb you can see I've added a couple of extra tweaks. There's a hash called OPTS which sets the device, MIDI channel, octave and tempo. I've also added some very basic exception handling when loading the MIDI device.

Twilio isn't limited to SMS - with some tweaking from an intrepid hacker, the app could let you call up and play a tune with the keypad...

And in the near-future, we might be able to accomplish this on the client-side with the newly-proposed Web MIDI API. See the W3C spec here.