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:
12 | def note_on(channel, note, velocity = 64 ) |
13 | message( ON | channel, note, velocity) |
16 | def note_off(channel, note, velocity = 64 ) |
17 | message( OFF | channel, note, velocity) |
20 | def program_change(channel, preset) |
21 | message( PC | channel, preset) |
25 | if ( RUBY_PLATFORM .include?( 'mswin' ) || RUBY_PLATFORM .include?( 'w32' )) |
32 | extern "int midiOutOpen(HMIDIOUT*, int, int, int, int)" |
33 | extern "int midiOutClose(int)" |
34 | extern "int midiOutShortMsg(int, int)" |
38 | @device = DL .malloc( DL .sizeof( 'I' )) |
39 | C .midiOutOpen( @device , - 1 , 0 , 0 , 0 ) |
43 | C .midiOutClose( @device .ptr.to_i) |
46 | def message(one, two = 0 , three= 0 ) |
47 | message = one + (two << 8 ) + (three << 16 ) |
48 | C .midiOutShortMsg( @device .ptr.to_i, message) |
52 | elsif RUBY_PLATFORM .include?( 'darwin' ) |
56 | elsif RUBY_PLATFORM .include?( 'linux' ) |
61 | raise "Couldn't find a LiveMIDI implementation for your platform" |
64 | def play_note(channel, note, velocity, sleep_time, midi) |
65 | midi.note_on(channel, note, velocity) |
67 | midi.note_off(channel, note) |
70 | def play_chord(channel, notes, velocity, sleep_time, midi) |
72 | midi.note_on(channel, note, velocity) |
75 | notes. each { |note| midi.note_off(channel, note)} |
87 | midi.program_change( 1 , 32 ) |
88 | play_note( 1 , 64 , 100 , 1 ,midi) |
89 | play_note( 1 , 64 , 100 , 0 . 25 ,midi) |
90 | play_note( 1 , 64 , 100 , 0 . 25 ,midi) |
91 | play_note( 1 , 64 , 100 , 0 . 25 ,midi) |
94 | midi.program_change( 0 , 3 ) |
100 | play_chord( 0 , [ 55 , 64 ], 100 , 0 . 25 ,midi) |
101 | play_note( 0 , 48 , 100 , 0 . 25 ,midi) |
103 | midi.note_off( 1 , 64 , 100 ) |
106 | play_chord( 0 , [ 57 , 65 ], 100 , 0 . 25 ,midi) |
107 | play_note( 0 , 50 , 100 , 0 . 25 ,midi) |
111 | play_chord( 0 , [ 60 , 69 ], 100 , 0 . 25 ,midi) |
112 | play_note( 0 , 53 , 100 , 0 . 25 ,midi) |
116 | play_chord( 0 , [ 64 , 67 ], 100 , 0 . 25 ,midi) |
117 | play_note( 0 , 48 , 100 , 0 . 25 ,midi) |
121 | play_chord( 0 , [ 64 , 69 , 72 ], 100 , 0 . 25 ,midi) |
122 | play_note( 0 , 57 , 100 , 0 . 25 ,midi) |
126 | play_chord( 0 , [ 62 , 71 ], 100 , 0 . 25 ,midi) |
127 | play_note( 0 , 55 , 100 , 0 . 25 ,midi) |
131 | play_chord( 0 , [ 64 , 67 , 72 ], 100 , 0 . 25 ,midi) |
132 | play_note( 0 , 48 , 100 , 0 . 25 ,midi) |
134 | 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