- Enumerable: Saving Your Life, One Array at a Time
- Ruport an ActiveRecord
- Ruport!
- Joining the Ranks
- 12 Days of Stupid Ruby Tricks
- IDEs, Text Editors, and Bears, Oh My!
- Presenter: S5 for Ruby, among other things.
- Microformats in Ruby
- Mongrel Security, Projects Past And New, and general Ruby Goodness
- Marshal Me!
- More MinneBar
- MinneBar 07
- Goodbye, RedHanded
- Say Goodbye to those Wacky Colons!
- Musical Live Coding in Ruby?
Musical Live Coding in Ruby?
June 3rd, 2007 20:29
I am working on a project of turning History into Song. Sounds exciting, huh? When we were recording our Watergate song, we decided to spice it up with a lot of synth. My companion broke out his MIDI controller, and a bunch of cables, and I grabbed a 1/8” jack, and hooked it up to my macbook. First I started my JRuby synth, JTalk.
JTalk
JTalk is a really simple script. It starts a MIDI synthesizer in Java, and exposes a few convenience methods via DRb. Very simple stuff, but lets me play some notes pretty easily. The script is about 150 lines long, because I include a complete MIDI value => Note/Octave mapping hash, so I am going to drop it on pastie. You can find it here: http://pastie.caboo.se/67444.
Now this script works pretty, I just open up an irb session, make the connection, and start playing notes. But my friend already has those musical notes covered with all his keyboards and cords and things I only pretend to understand. But his magic devices can’t get a womans robotic voice saying “Watergate”. That’s my domain.
VoiceSynth
So now I fire up my next Synth script, this one all about voice. This lovely script started out as just a couple of system() calls to the say command, but I felt that was too simple. _why posted a great, very obfuscated way of accessing the voice stuff in OS X, and after a little while, I was able to abstract it out into something useful.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
require 'dl/import' require 'drb' module Talk include DRbUndumped extend DL::Importable dlload "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/SpeechSynthesis.framework/SpeechSynthesis" %w[SpeechBusy() SpeakString(void*)].each do |function| extern "int #{function}" end def self.speak(string) speakString [string.size,string].pack("Ca*") sleep(0.1) until speechBusy == 0 end end if __FILE__ == $0 DRb.start_service('druby://0.0.0.0:9001', Talk) puts "Server started on #{DRb.uri}" DRb.thread.join end |
It is a pretty simple [ab]use of the DL library in the Ruby stdlib, and is quite fast. The use is also very simple.
1 2 3 4 5 6 7 |
>> require 'drb' => true >> DRbObject.new(nil,"druby://localhost:9001") => #<DRb::DRbObject:0x157546c @ref=nil, @uri="druby://localhost:9001"> >> Talk = _ => #<DRb::DRbObject:0x157546c @ref=nil, @uri="druby://localhost:9001"> >> Talk.speak "Hello, World!" |
Tada! irb can talk! But I need to do more than just saying “Hello, World!” once. We need a lot of Watergate, and a lot of Nixon.
1 2 3 4 5 6 7 8 |
>> Thread.new { loop do ?> Talk.speak "Watergate" >> Talk.speak "Nixon" >> end >> } => #<Thread:0x1563a3c run> >> _.kill => #<Thread:0x1563a3c dead> |
With a little bit of work, we can make a simple server out of it. But first, we need the Ruby/EventMachine gem. sudo gem install eventmachine Then pop back into our irb session, and lets code up a server!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
>> require 'eventmachine' => true >> module TalkServer >> def receive_data(data) >> Talk.speak data.to_str >> send_data ">> #{data}" >> close_connection if data =~ /quit|exit/i >> end >> end => nil >> EventMachine::run { ?> EventMachine.start_server "127.0.0.1", 8081, TalkServer >> } |
Now open up a new Terminal window, and telnet into your server!
saurasaurusrex:~ cdcarter$ telnet localhost 8081 Trying ::1... telnet: connect to address ::1: Connection refused Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hi >> Hi quit Connection closed by foreign host.
You now have a TalkServer! Pretty easy huh? You can do a lot in irb, not just testing things. I am going to start playing around more with EventMachine, and DL. Ruby has a lot of power in its libraries!


