midifile.rb

Midifile access for Ruby

— Updated May 2010 —

midifile.rb is a small library script for Ruby that provides facilities for reading and writing standard midifiles. It lets you use very simple code to read a midifile, breaking it out into elements (headers and events) in convenient form for further processing. It reads directly from the file, without storing it all in memory first.

New files can be created as well, usually by building an object in memory, adding elements as desired, and writing the complete sequence to a file at the end. 'Generator' methods are supplied for easy creation of most kinds of events. Simple alterations (such as transposing all the notes) can actually be done without building a new object — elements can be written out immediately they are read from the input.


This release fixes the rather lamebrained sorting of output events done by previous versions. 'Simultaneous' events no longer get shuffled, and the occasional mistiming of the last note is fixed.

New 'channel' accessor methods havce been added to the MidiItem class that work with 'user' numbering (1..16) rather than the internal 0..15 range of the 'chan' attribute, which should make it easier to avoid confusion.

There is a Ruby bug (versions 1.9.1 and 1.9.2) that will prevent midifile.rb working as supplied. See below for details and the fix.


The code places few restrictions on the user. It will read and write both Format 0 and Format 1 (even Format 2...) files. It is intended to be minimal yet flexible. (Which means probably that you could generate an invalid file fairly easily, but it is straightforward enough that you should be able to avoid this.)

As a taster, here is an absolutely trivial lister for "myfile.mid" (using the basic 'to_s' methods provided):

      require 'midifile.rb'
      open("myfile.mid", "r") {|f|
        mf = Midifile.new(f)
        mf.each {|elem|
          puts elem
        }
      }

The downloadable archives below contain the following:

midifile.rb
The script itself (self contained — install anywhere in your Ruby library path).
README
Some documentation on the classes and methods in the package.
EXAMPLES
A folder with some short demos (the last three are new, Feb 2010):
Transpose
reads a midifile and writes a new one with all notes (except ch. 10 percussion) transposed by a desired amount. It copies the file directly without storing in memory.
SMFformat0
Writes out a Format-0 (single-track) midifile from a source Format-1 (multitrack) file.
SMFformat1
The reverse of the above -- creates a Format-1 from Format-0
makeachord
A short demo of how to create a file from scratch — just builds a C-major chord.
GMlister
This attempts to be a complete listing utility for General Midi files.
GMsummary
A modification of the above that accumulates and summarizes the events in the file rather than printing them individually. It can accept several filenames in the command line, and will list them in sequence.
SMPTEtoSMF
A utility to fill a need... Turns an "SMPTE" style header — not understood by many apps — into the more standard style with the tick division in "ticks per beat". The rest of the file is output unchanged.
ChanTran
Translates selected channels of midievents to others.
Quantize
Aligns all events in a file on exact divisions, to the precision desired.
Resustain
Replaces Sustain Pedal (Controller 64) events with suitably lengthened note durations.

[The scripts above are tailored for **ix systems, and can need trivial modification to run under Windows and others. See the README for details.]

Downloads:

You can download the package here:
midifile_rb.tgz — gzipped tar, 21 KB
midifile_rb.zip — zip archive, 31 KB

BUG -- Ruby 1.9.x(!):

I've been notified (thanks Thomas!) that midifile.rb fails in Ruby 1.9.1 and 1.9.2. This is actually caused by a bug in the getc method in those versions of Ruby:
http://redmine.ruby-lang.org/issues/show/3179
The problem is that getc is returning a (single-character) string instead of the byte-value it should. If this is happening to you, you can replace the two occurrences of 'getc()' (lines 303 and 498) in midifile.rb with 'getc()[0]', to have the correct value returned. (According to the bug report, the issue has been fixed, so later versions of Ruby should work with midifile.rb as supplied.)

Author:

                                Pete Goodeve
                                Berkeley, California

                e-mail: pete@GoodeveCa.NET
                         pete.goodeve@computer.org

Programs for BeOS
My Home Page