Tag Archives: Ruby

A video game music composer has put up a pretty cool tutorial for people interested in making tunes.  It starts from absolute basics and builds up a simple piece.  If only I had the budget to get that kind of music into my flash games!  Once I get to where I can earn anything significant out of them, .

He did the tutorial with Garage Band. Since, I don't have an iPad,  that piece of software isn't an option for me.  I have been working through some ruby tutorials, though, and so I figured I'd give it a shot in MIDI.  It turns out that it's not that much of a pain to access C libraries from within Ruby. It breaks platform independence, but hey, this is just a fun project, so why not?

It took me a little while to get used to MIDI's notation. A note value of 60 is middle C. 59 is half a step lower, 61 is a half step up, and so on. That means that to go up an octave, it's necessary to increase the note value by 12 instead of 8. After adjusting to this, it wasn't too tough to get the chords Whitaker used in his blog post. Well, hopefully they're right! I also started listening to the sound files further down the post, but didn't get that far in deciphering the melody. Here's the ruby code to generate what I've gotten so far:

 


require 'dl/import'

class LiveMIDI
   ON = 0x90
   OFF = 0x80
   PC = 0xC0
   
   def initialize
      open
   end
   
   def note_on(channel, note, velocity = 64)
      message(ON | channel, note, velocity)
   end
   
   def note_off(channel, note, velocity = 64)
      message(OFF | channel, note, velocity)
   end
   
   def program_change(channel, preset)
      message(PC | channel, preset)
   end
end

if (RUBY_PLATFORM.include?('mswin') || RUBY_PLATFORM.include?('w32'))
   class LiveMIDI
      #Windows code
      module C
         extend DL::Importable
         dlload 'winmm'
         
         extern "int midiOutOpen(HMIDIOUT*, int, int, int, int)"
         extern "int midiOutClose(int)"
         extern "int midiOutShortMsg(int, int)"
      end
      
      def open
         @device = DL.malloc(DL.sizeof('I'))
         C.midiOutOpen(@device, -1, 0, 0, 0)
      end
      
      def close
         C.midiOutClose(@device.ptr.to_i)
      end
      
      def message(one, two = 0, three=0)
         message = one + (two << 8) + (three << 16)
         C.midiOutShortMsg(@device.ptr.to_i, message)
      end
      
   end
elsif RUBY_PLATFORM.include?('darwin')
   class LiveMIDI
      #Mac code here someday
   end
elsif RUBY_PLATFORM.include?('linux')
   class LiveMIDI
      #Linux code here someday
   end
else
   raise "Couldn't find a LiveMIDI implementation for your platform"
end

def play_note(channel, note, velocity, sleep_time, midi)
   midi.note_on(channel, note, velocity)
   sleep(sleep_time)
   midi.note_off(channel, note)
end

def play_chord(channel, notes, velocity, sleep_time, midi)
   notes.each do |note|
      midi.note_on(channel, note, velocity)
   end
   sleep(sleep_time)
   notes.each { |note| midi.note_off(channel, note)}
end

midi = LiveMIDI.new
#Middle C chords, Middle C is 60 and each number up or down is a half-step
I = [60,64,67]
ii = [62,65,69]
iii = [64, 67,71]
IV = [65, 69, 72]
V = [67, 71, 74]
vi = [69, 73, 76]

midi.program_change(1,32) #to use for the melody if I can figure it out
play_note(1,64,100,1,midi)
play_note(1,64,100,0.25,midi)
play_note(1,64,100,0.25,midi)
play_note(1,64,100,0.25,midi)


midi.program_change(0, 3) # set channel 0 to piano

sleep(1)

midi.note_on(1,64,100)
4.times do ||
   play_chord(0, [55,64],100,0.25,midi)
   play_note(0,48,100,0.25,midi)
end
midi.note_off(1,64,100)

4.times do ||
   play_chord(0, [57,65],100,0.25,midi)
   play_note(0,50,100,0.25,midi)
end

4.times do ||
   play_chord(0, [60,69],100,0.25,midi)
   play_note(0,53,100,0.25,midi)
end

4.times do ||
   play_chord(0, [64,67],100,0.25,midi)
   play_note(0,48,100,0.25,midi)
end

4.times do ||
   play_chord(0, [64,69,72],100,0.25,midi)
   play_note(0,57,100,0.25,midi)
end

4.times do ||
   play_chord(0, [62,71],100,0.25,midi)
   play_note(0,55,100,0.25,midi)
end

4.times do ||
   play_chord(0, [64,67,72],100,0.25,midi)
   play_note(0,48,100,0.25,midi)
end
play_chord(0,[48,52,55,60],100,1,midi)

Download it and run it on Windows to hear it play!

Tune from Whitaker Blackall

I think the best introductory book to programming that I've ever seen is Learn to Program, by Chris Pine.  My buddy I was staying with last summer went through it while I was there and made absolutely fantastic progress.  Despite never having programmed before, really, he tore through it in a week or two and got enough out of it to start programming simple scripts to help with his research job.

The entire book is taught in Ruby, but I don't think the language used matters that much.  The thing is it teaches concepts basic to almost any kind of programming -- functions, classes, recursion, blocks, etc...   And more importantly, it makes them fun!  Even the very simple exercises, such as "deaf Grandma" and "angry boss" were amusing.  My friend has ended up working almost entirely with Python, but everything in the book was still useful and there was little pain in switching to a new language compared to the difficulty of getting started.

When I first got curious about Ruby myself three years ago, I tried the Pick-axe book and gave up out of boredom.  It really could have used regular programming challenges or problems at throughout the book.  Unfortunately almost all the other resources that were around at the time were focused on Rails.  I really wish I'd found this book back then.

Some free online lessons that later became part of the book can be found here: http://pine.fm/LearnToProgram/