Representing Data as MIDI Music


You want to represent a series of data points as a musical piece, or just create music algorithmically.


Jim Menards midilib library makes it easy to generate MIDI music files from Ruby. Its available as the midilib gem.

Heres a simple method for visualizing a list of numbers as a piano piece. The largest number in the list is mapped to the highest note on the piano keyboard (MIDI note 108), and the smallest number to the lowest note (MIDI note 21).

	require midilib # => false

	class Array
	 def to_midi(file, note_length=eighth)

	 midi_max = 108.0
	 midi_min = 21.0

	 low, high = min, max
	 song =

	 # Create a new track to hold the melody, running at 120 beats per minute.
	 song.tracks << (melody = <<

	 # Tell channel zero to use the "piano" sound. <<, 0)

	 # Create a series of note events that play on channel zero.
	 each do |number|
	 midi_note = (midi_min + ((number-midi_min) * (midi_max-low)/high)).to_i <<, midi_note, 127, 0) <<, midi_note, 127,

	 open(file, w) { |f| song.write(f) }

Now you can get an audible representation of any list of numbers:

	((1..100).collect { |x| x ** 2 }).to_midi(squares.mid)


The midilib library provides a set of classes for modeling a MIDI file: you can parse a MIDI file, modify it with Ruby code, and write it back to disk.

A MIDI file is modeled by a Sequence object, which contains track objects. A track is a mainly a series of Event objects: for instance, each note in the piece has a NoteOnEvent and a NoteOffEvent.

Array#to_midi works by transforming each number in the array into a corresponding MIDI note. A standard piano keyboard can produce notes ranging from MIDI note 21 to MIDI note 108, with middle C being at MIDI note 60. Array#to_midi scales the values of the array to fit into this range as closely as possible, using the same formula youd use to convert between two temperature scales.

Working directly with the MIDI classes is difficult, especially if you want to compose music instead of just transfering a data stream into MIDI note events. Heres a subclass of MIDI::Track that provides some simplifying assumptions and some higher-level musical functions, making it easy to compose simple multitrack tunes. Each TimedTrack uses its own MIDI channel and makes sounds from only one instrument. A TimedTrack can sound chords (this is very difficult with stock midilib), and instead of having to remember the MIDI note range, you can refer to notes in terms of half-steps away from middle C.

	class TimedTrack < MIDI::Track
	 MIDDLE_C = 60

	 def initialize(number, song)
	 @sequence = song
	 @time = 0
	 @channel = @@channel_counter
	 @@channel_counter += 1

	 # Tell this tracks channel to use the given instrument, and
	 # also set the tracks instrument display name.
	 def instrument=(instrument)
	 @events <<, instrument)

	 # Add one or more notes to sound simultaneously. Increments the per-track
	 # timer so that subsequent notes will sound after this one finishes.
	 def add_notes(offsets, velocity=127, duration=quarter)
	 offsets = [offsets] unless offsets.respond_to? :each
	 offsets.each do |offset|
	 event(, MIDDLE_C + offset, velocity))
	 @time += @sequence.note_to_delta(duration)
	 offsets.each do |offset|
	 event(, MIDDLE_C + offset, velocity))

	 # Uses add_notes to sound a chord (a major triad in root position), using the
	 # given note as the low note. Like add_notes, increments the per-track timer.
	 def add_major_triad(low_note, velocity=127, duration=quarter)
	 add_notes([0, 4, 7].collect { |x| x + low_note }, velocity, duration)


	 def event(event)
	 @events << event
	 event.time_from_start = @time

Heres a script to write a randomly generated composition with two tracks. The melody track (a trumpet)takes a random walk around the musical scale, and the harmony track (an organ) plays a matching chord at the beginning of each measure.

	song =
	song.tracks << (melody =, song))
	song.tracks << (background =, song))

	melody.instrument = 56 # Trumpet
	background.instrument = 19 # Church organ << <<,
	 A random Ruby composition)

	# Some musically pleasing intervals: thirds and fifths.
	intervals = [-5, -1, 0, 4, 7]

	# Start at middle C.
	note = 0
	# Create 8 measures of music in 4/4 time
	(8*4).times do |i|
	 note += intervals[rand(intervals.size)]

	 #Reset to middle C if we go out of the MIDI range
	 note = 0 if note < -39 or note > 48

	 # Add a quarter note on every beat.
	 melody.add_notes(note, 127, quarter)

	 # Add a chord of whole notes at the beginning of each measure.
	 background.add_major_triad(note, 50, whole) if i % 4 == 0

andom.mid, w) { |f| song.write(f) }

See Also

  • midilib has a comprehensive set of RDoc, available online at
  • The librarys examples/ directory has several good programs that demonstrate how to create and "play" MIDI files
  • The TimedTrack class presented takes several ideas from Emanuel Borsbooms Midi Scripter application; the Midi Scripter generates MIDI files from Ruby code that incorporates musical notationits not really designed for use as a library, but it would make a good one (
  • The names of the standard MIDI instrument and drum sounds are kept in the arrays MIDI::GM_PATCH_NAMES and MIDI::GM_DRUM_NOTE_NAMES; this isn as useful as it could be, because youll usually end up referring to instruments by their numeric IDs; the Wikipedia has a good mapping of numbers to names (



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration

Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399 © 2008-2020.
If you may any questions please contact us: