The following article (plus a bit more editing, actually) appeared in The Perl Journal. Reprinted with permission.

NAME

Simple Languages, Easy Music -- Sean M. Burke


Introduction

MIDI (Musical Instrument Digital Interface), is a standard, dating from the mid-1980s, for representing music as series of notes, rather than as raw audio data. To use a graphic metaphor, MIDI is to an audio format (.au/.wav/.aiff) as a vector graphic format (PostScript) is to a bitmap format (.png/.gif).

With MIDI, you can make music without actually having to do waveform synthesis, the same way that PostScript lets you draw circles, without having to do what you'd have to do with bitmap formats -- having to do trigonometry to get (x,y) for ``every'' point on the circle, deciding how many points will suffice for approximating ``every point'', and so on, to say nothing of aliasing. For the purposes of this article, MIDI represents music as consisting of events -- where each event is basically ``turn a note on [or off]'' -- which happen at certain times, on a certain channel (what other sound synthesis terminologies call a ``voice'' or a ``track''), with a certain note number, at a certain volume.

When I first started reading up on the MIDI internals, it seemed an ideal format for composing music in Perl, and so I set out to make routines for encoding to and decoding from the binary format used in MIDI files. In early August 1998, I sent to CPAN my first release of the imaginatively named ``MIDI-Perl'', a mostly object-oriented interface to these encoding/decoding routines (Burke 1998).

However, as I stood back from the pile of code, I realized that while I had created a fine object model for representing MIDI files, the most basic data structure, the MIDI event, was no more suited to musical composition than editing raw PostScript is for making architectural blueprints.

And so I found myself in the not-entirely-anticipated position of designing and implementing a language that would provide an interface for musical composition, a language that would at some level use the MIDI encoding routines for output, but which would necessarily be several levels higher in abstraction from them.

Now, it is the work of language designers to make their languages so that they will -- to quote Larry Wall -- ``make easy things easy, and hard things possible.'' What's implicit in this idea is that there's two domains that a programming language bridges -- the way we think of a problem, and the way we need to code up the program that solves the problem. Making ``hard things possible'' is a matter of making the language open-ended enough that one can do just about anything with it, while making ``easy things easy'' is a matter of making sure that things easy to think of (whether ``I want to replace all the times I say 'Jimmy' with 'James''', or ``I want to sort these words by the last letter'') are easy to code, probably by being codable concisely, and in the same terms as we think of them in.

In the remainder of this article I'll first explain my ideas about types of simple languages, and then from that I'll show how these ideas led me to design the MIDI::Simple language the way I did. The style here is clearly diaristic, because my goal is not to document MIDI::Simple, but instead to illustrate haw specific problems in language design, over time, led me to make MIDI::Simple the way it is. Readers whose interests do not include both language theory and music, can skip sections as they wish. But I hope that my points here are not specific to just these specific problems.


Hard Things Possible

Imagine you need to (for whatever reason) capture each of several addresses' finger outputs, and, if the content matches some regexp, save it to a specific file. You could do that with a program like this:

  while(<DATA>) {
    next if /^\s*\#/s;
    chomp;  my($addr, $file, $re) = split(/\s+/, $_, 3);
    next unless length($addr) && length($file) && length($re);
    save_finger_if_matching($address, $output, $regexp);
     # which we'll pretend we got from elsewhere; say, via require()
  }
  print "Done\n";
  __END__
  # list of addresses, in the format:
  #  address  file  regexp
  foo@bar.com fooey.txt office
  # hm, not any more: zazy@bar.com zazout1.txt phone
  pati@lebar.fr patipata.txt ici

This program basically implements a language, and then has, after its ``__END__'', instructions in that language. Now, the language is simple: lines that start with optional whitespace and then a hash-mark, are ignored (so you can use them for comments), and lines that can be split into three non-null fields are considered commands to save that field-1's finger output in file field-2, if it matches field-3. And this language doesn't have anything like what we'd expect in a real programming language -- it has no flow-control structures, no variables, no ability to define procedures. But it is a language in the sense that it has a syntax -- i.e., an order things have to be in to make sense -- and it has semantics -- i.e., elements in the language have a certain order they appear in, and when they do, they do something or mean something.

Now, even by that token, this language's semantics are quite restricted, so it's a ``language'' only in the same way that a simple markup language like HTML is a language, or the way that the notation for recording chess moves is a language, or the way that common music notation is a language. None of these are languages you could write a program to calculate 5 * 12 in, but each is good at what it's for.

And none of these languages, in fact, make hard things possible. If, for example, you wanted to represent in the finger-capturer language ``save the finger output of foo@bar.com to fooey.txt if it matches office and if today is Tuesday'', you'd be out of luck. You could change the code that implements the language to support an optional ``day of week'' field, and that would work, and that may be the end of your need to extend the language.

But if you needed to denote an arbitrary criterion, not just ``is today a particular day of the week'', but anything at all, whether ``does this address match /\.fr$/'', or, who knows, ``is there an even number of vowels before the @ in the address?'', then you've hit a wall in your approach to the language -- because the basic approach has been to implement a language in Perl, but basically independent of it. It's a Novel Language. In other words, the language is self-contained, and never gets to use the features of Perl (or whatever language you're implementing the parser/evaluator in). For example, Perl has variables, but that doesn't mean this language gets to have variables.

Now, there's two ways to go here in expanding the functionality of the little language you've got so far:


Approach 1: A Novel Language

A Novel Language is what you have already, as discussed above: a language independent of the language you implement its interpreter in. Now, if you want the language to do more, you can bear down and write the Perl implementation of the language such that it has flow control (like ``if..then..'', ``while...'', etc.) and variables and whatnot. If you've never done anything like this before, it seems quite daunting, with some good reason; but just think -- designing a language starting from nothing can't be too hard, or there wouldn't be so many programming languages around (granted, only a few see widespread use, but that's another issue altogether). Think of all the early-80s PC BASICs written in machine language, that fit in a few K of ROM!

Now, this is not to say that implementing just any high-level language in Perl (or any other language) is a trivial prospect -- not by a long shot -- but implementing in Perl a language with simple syntax and simple semantics, like a LOGO dialect, or even a simple Lisp dialect (as in Abelson & Sussman 1996), is quite doable. And then there's the other approach:


Approach 2: An Extensional Language

An ``Extensional Language'' is what I call a language that is really just semantic extensions to Perl, provided as subs or methods from a Perl library/module/class. Now, it may strike you as cheating to say that Perl plus five subroutines you get from require(``my_great_lib.pl'') makes a new language. First off, I didn't say it was a entirely new language. Second, it does what you want (i.e., you have the semantics), and that's probably all you're interested in, right? Now, the advantage to using an Extensional Language is that you are really still in Perl, so you get to use all the features of Perl -- Perl's conceptions of variables, flow control, and so on. The disadvantage is that you have to be within the confines of Perl syntax. (However, Perl syntax is so free-form that this is as great a problem as it sounds.)

There's a parallel here in the creation of jargons (and remember what Larry Wall keeps saying about Perl having a basis in natural languages): Chemists, when they decided they needed a language to talk very precisely about chemical structures, could have decided to make up a whole new rich Novel Language, with verb tenses and noun compounding and and all the goodies we expect in a natural language, but also with exact ways to describe chemical structures. But this would mean having to figure out the best way to implement predicate argument structure, and pronoun binding, and phonology, and all the unpleasant cruft of natural language -- the same way that making a Java virtual machine in Perl would mean having to actually write code implementing exception handling and whatnot.

So instead, chemists implemented chemical names as an Extensional Language based on English (or whatever language they're speaking). Now, ``boron trifluoride'' isn't exactly core English, but it's more English than it is Thai or Klingon; and, I admit, when the chemical ``extension'' to English starts spawning forms like ``dichloro-1,2-ethane'' and ``2-chloro-4-ethylamino-6-isopropylamino-1,3,5-triazine'', it begins to leave any natural language behind. But when a chemist says ``boron trifluoride is an inorganic gas'', you understand that something is an inorganic gas, even if you can't picture what a boron trifluoride molecule looks like. Similarly, if you're reading Perl code and you see &funk_it, or $this->thingify, you probably can't guess what funk_it or thingify do, but at least you can tell they're subroutines, whereas this might not be clear if you were reading an unfamiliar language.

(The astute reader may have already noted that you can actually mix the approaches of a Novel Language and an Extensional Language. I'll give an example of this later.)


Easy Things Easy

Consider these MIDI events, expressed as they would be sent to the MIDI encoder in MIDI::Event:

  # event, wait-time, channel, note number, volume
  ['note_on', 0, 1, 25, 96],
  ['note_off', 96, 1, 25, 0],
  ['note_on', 0, 1, 29, 96],
  ['note_off', 96, 1, 29, 0],
  ['note_on', 0, 1, 27, 96],
  ['note_off', 96, 1, 27, 0],
  ['note_on', 0, 1, 20, 96],
  ['note_off', 192, 1, 20, 0],

...and so on, for a total of thirty-three such lines.

I won't explain the exact details of this format, as it's not relevant to the rest of this article, but suffice it to say that requiring a composer to represent notes in the above format was clearly not making ``easy things easy'', because this is not how composers (or anyone) think of notes. A more human conception of notes is that they have these qualities:

 * duration: expressed as a quarter note, half note, etc.
 * pitch: expressed as a note-letter and octave number, e.g., "A5"
 * volume: expressed either numerically or as one of the common
   abbreviations from sheet music, e.g., "mf" for "medium-loud"
 * and, for purposes of MIDI, a logical channel number between 0
   and 15

And in an early attempt at a music language (implemented as a Novel Language, with an interpreter written in Perl, not shown), the above code turned into:

 note c1 f qn Cs2
  # Cs2 = C sharp, octave 2
  # qn = quarter note
 note c1 f qn F2
 note c1 f qn Ds2
 note c1 f hn Gs1
  # yup, hn = half note
 note c1 f qn Cs2
 note c1 f qn Ds2
  # ...and so on...

(Incidentally, this tune I'm trying to represent is the Westminster Chimes, better known as that tune most fancy clocks play when they chime the hour. See Sturdy 1998.)

Now, what makes these typical lines of note-making code especially different from typical lines of code written in a high-level programming language, is the high degree of redundancy between them. The typical event's parameters of duration, pitch, volume, and channel, are mostly the same from one event to the next. So, in the name of brevity, I decided that each note's properties should be inherited from the previous note, overridden with whatever new properties are defined in this call. And so, in the new language thus defined, the above code can be rephrased as:

 note c1 f qn Cs2
 note F2
 note Ds2
 note hn Gs1
 note qn Cs2
 note Ds2
 # ...and so on...

I was on the way to developing a workable language. But then, as I came to want to expand the language, I arrived at the same question raised in the above example of the finger-output capturer -- should I continue implementing the language as a Novel Language, probably ending up with a moderately simple language as far as flow control, functions provided, and variables and data structures; or should I implement it as an Extensional Language?

I had two considerations:

1. I wanted whatever language I ended up with, to be sufficient to the task of algorithmic composition -- composition where the notes are at least partially determined by the output of algorithms that the composer develops, and which may be arbitrarily complex. Composers like Xenakis (1992) use algorithms that involve some fairly complex algebra. If I wanted my simple Novel Language to be able to do anything like that, I'd need to bear down and implement algebraic functionality for that language. Ditto for providing mathematical functions like sines and logarithms, and at least scalars and lists as data structures, and functions to manipulate them. That sounded like a lot of work.

2. There are both kinds of music languages around already -- very simple languages, notably the language ``abc'' (Walshaw 1998); and composition extensions to high-level languages, notably the Forth-extension HMSL (Burk 1998). (I don't mean to suggest that these are all that's out there; rather, I use them here as representative of the field as I understand it. See Roads (1996:783-818) for a good survey.) But, I asked myself, which kind of language would it be most useful to the world (or, for that matter, me) to have now? The abc language seemed rather well thought-thru, implemented, and supported by various ports and utilities. So implementing a simple Novel Language for music, in Perl, would essentially be a mere duplication of the effort that went into (and continues to go into) abc. As to Extensional Languages based on high-level languages, HMSL seemed to me the richest. I was even willing to learn Forth to deal with it! However, the implementation of Forth that it's based on apparently works well only under MacOS and AmigaOS. So that ruled it right out, as I don't have either OS at my disposal. As to other such compositional languages that I'd heard of and could find information on, some were based on languages I wouldn't want anyone to have to compose in (e.g., C++), or they focused on acoustics and digital signal generation (e.g., Common Lisp Music) more than I would ever want to (and, incidentally, more than is practical in MIDI).

So, I thought, if I implemented my music language as an Extensional Language based on Perl, users/composers could write their programs and be able to run them on any Perl interpreter, on all the varied platforms Perl has been ported to. People new to programming who wanted to learn my Extensional Language, would have at their disposal all the documentation and support that all Perl learners have. Algorithmic composers would have at their disposal all the data structures and mathematical functions Perl provides. And -- no small consideration -- it'd save me a ton of work that'd otherwise go into working out the Novel Language's even rudimentary data structures and functions.

So the Extensional Language approach won. I scrapped the Novel Language and reimplemented its semantics (plus a lot more) as the MIDI::Simple module that comes in the MIDI-Perl suite, version 0.7 or later. The remainder of this article given a guided (and not entirely exhaustive) tour of the features of MIDI::Simple, with notes as to the line of thought that led to some features come out the way they did.


Behold MIDI::Simple!

For all the tortured thought I put into the design of it, MIDI::Simple turned out terribly easy and straightforward to actually implement. (It was almost anticlimactic. Maybe I should have done it in C++ so that it would have taken vastly longer, giving me a heroic sense of accomplishment!) MIDI::Simple is only about six hundred lines of relatively unsurprising code -- much of it highly repetitive, at that. Its only quirk is that it provides simultaneously a procedural and an object-oriented interface -- I wanted beginning and novice users to be able to use a purely procedural interface, and advanced users to be able to use the power of object-oriented design, if they so desired.

MIDI::Simple basically deals with a data structure I call a ``score'', which is basically a list of events, each with a time-offset; and some state variables that are mostly for storing defaults for notes. This is a partial list of the state variables, which will do for the moment:

* $Time -- the time (in a notional unit called ``ticks'', which is usually 1/96th of a quarter note) at which the next score event will take place. * $Duration -- the duration, in ticks, of the next note/rest, by default. * $Channel -- the channel number the next note will occur on, by default. * $Volume -- the volume, as a number 0 to 127, the next note will have by default. * @Notes -- the pitches (stored as MIDI note numbers) that will be added, by default, to the score by the next call to the n routine, discussed below. Now, I expect that only the most advanced user will have to deal with the contents of a score directly, because I have supplied these functions that give the user an interface for manipulating it:

* the function new_score which initializes a ``score object'' -- i.e., a score along with some incidental state variables I'll discuss later.

* the functions n and r, to add notes and (virtual) rests to the score with various parameters (duration, pitch, volume, time, channel). (And there's also a function noop, whose interaction with n and r is explained later.)

* functions to add arbitrary MIDI events to the score -- e.g., patch_change, to set the patch (i.e., a simulated instrument, like piano, or banjo) for a given channel.

* a function write_score to write the newly composed score as a MIDI file.

* a function read_score to read a single-track MIDI file as a score, which the user can add to.

* a function synch, to take the output of several user-provided functions, and place them in the score at the same time -- useful for making a score's measure out of the output of a few different ``instruments''.

Using the language specified as above, the Westminster Chimes could be notated like this:

 use MIDI::Simple;
 new_score;
 patch_change 1, 8;  # set Channel 1 to Patch 8 = Celesta
 n c1, f, qn, Cs2;   n F2;   n Ds2;   n hn, Gs1;
 n qn, Cs2;  n Ds2;  n F2;   n hn, Cs2;
 n qn, F2;   n Cs2;  n Ds2;  n hn, Gs1;
 n qn, Gs1;  n Ds2;  n F2;   n hn, Cs2;
 write_score 'chimes.mid';

Much more concise than the forty-odd lines that this same thing takes if expressed as low-level MIDI events and calls!


"Relative" Note Specification

Now, at this point I noticed that the notes are thought of (at least for many purposes) not as each being on such-and-such octave, but instead that there's a notion of ``current octave'', which notes being composed are thought of as being in -- or as being in an octave above, or below. So I added yet another way to specify pitches: besides by number (``n25'') or by note-and-octave (``Cs2''), one can specify them in terms of just note-letter: ``Cs'' -- meaning, ``C sharp in the current octave''. I call this a ``relative'' note specification, in distinction to ``Cs2'' and ``n25'' which I call absolute.

As to where the value ``current octave'' comes from: it's a number stored in a state variable called $Octave, which can be set directly, or which can be set by calling n or r with a parameter in the form ``o6'' (where ``6'' can be replaced by any number ``0'' to ``10''), and incidentally will be set as a side-effect of calling n or r with any absolute note specifications.

So in other words, these lines of code all end up setting $Octave to 2, whether directly, or as a side-effect.

  $Octave = 2;
  $Octave = 3;  --$Octave;
  n o2 Cs;
  n Cs2;  # Or even...
  r n25;

I've established that ``Cs'' would mean, not very surprisingly, ``C sharp in the current octave''. To this I added a way to mean ``... an octave above the current one'' or ``... an octave below the current one'':

 * Cs_u1  ("u" for "up")
 * Cs_d1  ("d" for "down")

...where ``1'' can be replaced by any positive integer, just so long as the resulting note is within the note range of MIDI devices, C0 to G10.

So the upshot of this, is that this line of code:

 n c1, f, qn, Cs2;   n F2;  n Ds2;  n hn, Gs1;

can be expressed as:

 $Octave = 2;
 n c1, f, qn, Cs;   n F;   n Ds;   n hn, Gs_d1;

or as:

 n c1, f, qn, Cs2;  n F;   n Ds;   n hn, Gs_d1;

In this latter case, only the first note is specified absolutely, and sets the current octave to 1, for all the following notes to use. This means that all you have to do to move all these notes up two octaves, is to change the ``Cs2'' to ``Cs4''.


Percussion, Uniformity, and noop

MIDI has a special reserved channel, channel 9, where numbers for pitches are interpreted as each a special percussive instrument-sound. For example, ``n35'' (i.e., ``B2'') on channel 9 doesn't mean a B2 on the current patch for channel 9, but instead it means a (basically untuneable) note on an acoustic bass drum. So, lines of code to generate bunches of percussion notes often look like this:

 n c9, ff, n41, qn;  r; n; r; n; r;

which adds to the score a quarter note, a quarter rest, a quarter note, and a quarter rest, all played on the acoustic bass drum.

However, the way this is coded, above, looked to me a perfect violation of ``uniformity'', a concept I first saw expressed in Weinberg's The Psychology of Computer Programming, in the chapter ``Some Principles for Programming Language Design'' (1971:219). To Weinberg's way of thinking, uniformity is a psychological principle, where users/programmers expect that things that look similar should do similar things, and conversely that things that look different should do different things. But the first call to n, above, and the second and third calls to n, look very different, even though all they do the same thing. What I wanted was a way to set up all the state variables, and then be able to just say ``n;r;n;r;''. Now, I could just say:

 $Channel = 9; $Volume = 112; $Duration = 96; @Notes = (41);
 n; r; n; r;

But that seemed inelegant. What I ended up doing was adding another function, called noop (for ``no-operation''), which parses options just the same as n and r, and thereby has all the side-effects, but doesn't actually affect the score. For example, consider these three lines of code:

 n qn, C3;  # C3 = n36, by the way
 r qn, C3;
 noop qn, C3;

The first one has the main effect of adding a note to the score, and incrementing $Time by the duration of a quarter note. The second one adds nothing to the score, but has the main effect of incrementing $Time (this is how I implement rests -- just time consumed). And the third one alters neither the score, nor $Time. But it does have all the same side-effects as the first two: it sets $Duration to the duration of a quarter note, and it sets @Notes to (36). With noop, you get to write code like:

 noop c9, ff, n41, qn;  # The setup...
 n; r; n; r;            # ...and the work.

This not to say that you have to do it this way; but allowing for the organization of code to reflect different ways of organizing thought is the Perl way: ``there's more than one way to do it''.

(Incidentally, I do not mean to imply that ``noop'' is to be used only for dealing with percussion; it's simply that ``noop'' is meant to solve the kinds of non-uniformity problems which became most apparent to me in percussion code.)


The Object-Oriented Interface

So far I've described functions (or procedures, really, seeing as how they don't have typically useful return values, and they have more side-effects than radical chemotherapy) for manipulating a score, for setting the state variables (like @Notes, $Duration, etc.) that ride along with the score.

It may have occurred to the reader that this is sufficient for manipulating only one score at once (although I expect that that is the typical case), but that this doesn't let one manipulate several scores at once. For this purpose, I've provided an OOP interface, summarized in this chart:

 Procedural             OOP
 ----------------       ------------------------------
 new_score              $score = MIDI::Simple->new_score
 $Channel = 3           $score->Channel(3)
 $Octave = 4            $score->Octave(4)
 @Notes = (30,34)       $score->Notes(30,34)
 push @Notes, 36        push @{ $score->Notes_r }, 36
                         or: $score->Notes( $score->Notes, 36 )
 n qn, Cs3              $score->n(qn, Cs3)
 noop o7, ff            $score->noop(o7, ff)
 write_score 'X.mid'    $score->write_score('X.mid')

(In point of fact, $score->n and n actually call the same sub, &MIDI::Simple::n, which does double-duty as a procedure and as a method. Readers interested in how this is done should read the source for MIDI::Simple. It is not for the faint of heart, and I by no means hold it up as a model of how this is done -- to say nothing of whether this should ever even be done this way again!)


Using "synch", and Some Actual Music

synch is a procedure which takes a list of code references (generally of the form \&foo, where foo is a sub the user has defined for adding notes to the score). For each one of these, synch sets $Time back to whatever it is when you called synch, calls the user's routine, and then notes the value of $Time. After calling all the routines, synch sets $Time as far ahead as any of the user's routines ended up setting it. In other words, it makes the effects of given routines synchronous -- i.e., occurring (well, at least starting) at the same time. In other words, synch orchestrates (literally as well as figuratively) several routines, each of which would generate a measure's (or really any size interval's) worth of notes or rests for a given virtual instrument.

Each user routine, incidentally, should expect its first parameter to be the score object it should add to, and should add to that score object via the object-oriented interface to MIDI::Simple instead of the procedural interface.

Now, its simplest use for synch would be something like:

  use MIDI::Simple 0.7;
 Main:
  new_score;
  @subs = (\&tom_two, \&double_clap);
  foreach (1 .. 10) { synch(@subs) }
  write_score("rhythm1.midi");
  exit;

 Subs:
  sub tom_two { 
    my $it = shift; 
     # n41 on c9  =  low floor tom
    $it->n(c9, ff, n41, qn);    $it->r;
    # qn = 1/4 note, ff = very loud
    $it->n(f);                  $it->r;
    # f = loud
  }

  sub double_clap {
    my $it = shift;
    # n39 on c9 = hand-clap
    $it->n(c9, ff, n39, sn); # sn = a 16th note
    $it->n;
    # This only takes up 2 16th-notes
    #  of time, but that's fine.
  }

Now, this generates twenty exactly identical measures. Minimalism aside, most music should vary from measure to measure. (This is not to say that measurewise composition is the way to go about making music, but it does seem to work well for percussive examples like I'm using here.) The way I go about having my instrument subs vary their effect from instrument to instrument is to have the first sub be a call to a measure counter, and to have the other subs be sensitive to the output of this. For example, add this sub:

  sub measure_counter {
    my $it = shift;   $it->r(wn); # a whole rest
    ++$measure;
  }

and change tom_two to the following, to make it do two different things, depending in whether or not $measure is greater than 4:

  sub tom_two { 
    my $it = shift;
    if($measure < 5) {
      # For the first four measures...
      $it->n(c9, f, n41, qn);
    } else {
      # For measures after that...
      $it->n(c9, ff, n41, qn);  $it->r;
      $it->n(f);                $it->r;
    }
  }

Then we just change this line in the program:

  @subs = (\&measure_counter, \&tom_two, \&double_clap);

And voilà, simple percussion. From there it's not hard to get more ornate really quickly:

  use MIDI::Simple 0.7;
 Main:
  new_score;
  @subs = ( \&measure_counter, \&boom, \&tboom, \&clap );
  foreach (1 .. 24) { synch(@subs) }
  write_score("rhythm2.midi");
  exit;

 Subs:
  sub measure_counter {
    my $it = shift;
    $it->r(wn); # a whole rest
    ++$measure;
  }
 
  sub boom {
    my $it = shift;
    return if $measure % 4 < 2;
    $it->n(c9, ff, n41, qn);  $it->r;
    $it->n(f);  r;
  }
 
  sub tboom {
    my $it = shift;
    return if $measure % 4 < 2;
    # 42 = 'Closed Hi-Hat' ; 43 = 'High Floor Tom'
    # In quick succession...
    $it->n( c9, ff, n43, sn); $it->n( n42 ); $it->r(dqn);
    # dqn = dotted quarter note/rest
    $it->r( c9, ff, n43, sn); $it->n( n42 ); $it->r(dqn);
  }
 
  sub clap {
    my $it = shift;
    return if  $measure < 4;
    $it->n(c9, ff, n39, sn); $it->n;
    $it->r(dqn);
    $it->r(hn);
  }

Now, I promised that I'd show you a little Novel Language based on an Extensional language. While I was tossing together up the above code, originally just to test synch's functionality, I decided I wanted a more complex instrument. For some reason, I had the rhythm track to The Talking Heads' ``Psycho Killer'' stuck in my mind, and decided to try to code it up. I tried it with combinations of eighth notes and rests and whatnot, but couldn't put my finger an it. So I tried making up a very simple Novel Language where whitespace is ignored, ``!'' means to hit the ``side stick'' (note 37 on that magic channel 9) for a sixteenth note, and anything else makes a sixteenth rest:

  sub psycho {
    my $it = shift;
    my $pattern =
      "  !.!. !.!. !.!. !.!. " ; # just a start
    $pattern =~ tr<\cm\cj\t ><>d; # kill whitespace
    warn "<$pattern> doesn't add up to a whole measure\n"
      unless length($pattern) == 16;
    $it->noop(c9, mf, n37, sn);
    # setup: n37 on c9 = side stick
    foreach (split('', $pattern)) {
      if($_ eq '!') { $it->n }
      else { $it->r }
    }
  }

From here I just monkeyed around with the quoted string on the line after my $pattern. I eventually arrived at:

  "  !.!.!.   !!!!!!   !.!.  " ;

...which indeed seemed to be the rhythm I was thinking of! To hear it, paste the psycho sub into the program above, and add it to the @subs line, like so:

  @subs = ( \&measure_counter, \&psycho, \&boom, \&tboom, \&clap );


Mod, Canons, and Rounds

Having your subs use $measure (or whatever you call it) to decide what notes to produce is the most straightforward way to produce higher-level structures in music in measurewise composition. You've already seen, above, a sub that uses the expression

  $measure % 4 < 2

to control what notes it adds to the score. The ``%'' operator (``modula'' or ``mod'', a.k.a. ``remainder'' -- so that X % Y means ``the remainder of dividing X by Y'') is one that a surprising number of people are unfamiliar with, so let's spell out just what it does here, for various values of $measure.

  $measure = 1  |  1 % 4 = 1  |  1 < 2 is True
  $measure = 2  |  2 % 4 = 2  |  2 < 2 is False
  $measure = 3  |  3 % 4 = 3  |  4 < 2 is False
  $measure = 4  |  4 % 4 = 0  |  0 < 2 is True
  $measure = 5  |  5 % 4 = 1  |  1 < 2 is True
  $measure = 6  |  6 % 4 = 2  |  2 < 2 is False
  $measure = 7  |  7 % 4 = 3  |  3 < 2 is False
  $measure = 8  |  8 % 4 = 0  |  0 < 2 is True

The ``phase'' (i.e., the starting point of the repeating pattern) of this T-T-F-F pattern can be changed by using a positive or negative number N in an expression ($measure + N) % 4. Consider that with for N = 1, you get a F-T-T-F pattern:

  $measure = 1  |  (1+1) % 4 = 2  |  2 < 2 is False
  $measure = 2  |  (2+1) % 4 = 3  |  3 < 2 is True
  $measure = 3  |  (3+1) % 4 = 0  |  0 < 2 is True
  $measure = 4  |  (4+1) % 4 = 1  |  1 < 2 is False
  $measure = 5  |  (5+1) % 4 = 2  |  2 < 2 is False
  $measure = 6  |  (6+1) % 4 = 3  |  3 < 2 is True
  $measure = 7  |  (7+1) % 4 = 0  |  0 < 2 is True
  $measure = 8  |  (8+1) % 4 = 1  |  1 < 2 is False

For N = -1, you get T-T-F-F.

  $measure = 1  |  (1+-1) % 4 = 0  |  0 < 2 is False
  $measure = 2  |  (2+-1) % 4 = 1  |  1 < 2 is True
  $measure = 3  |  (3+-1) % 4 = 2  |  2 < 2 is True
  $measure = 4  |  (4+-1) % 4 = 3  |  3 < 2 is False
  ...etc...

These structures for cyclically queuing or out, or alternating between two kinds of measures, are most useful for controlling rhythm tracks -- but the same expression, ($measure + N) % 4 (or for whatever integer in place of 4), can be used for repeating an 4-measure sequence. Consider the Westminster Chimes' four measures:

  my @phrases =(
    [ Cs, F,  Ds, Gs_d1 ],  [Cs,    Ds, F, Cs],
    [ F,  Cs, Ds, Gs_d1 ],  [Gs_d1, Ds, F, Cs]
  );

These four measures can be repeated ad infinitum (starting, appropriately, with the first measure), with code such as:

  sub first {
    my $it = shift;
    $it->noop(c1,mf,o3,qn); # setup
    my $phrase_number = ($measure + -1) % 4; # There it is!
    my @phrase = @{$phrases[$phrase_number]};
    foreach my $note (@phrase) { $it->n($note) }
  } 

If you change ($measure + -1) % 4 to ($measure + 0) % 4, you get a measure that does everything one measure later than before. Change 0 to 1 and it's another measure later. That way, when the piece starts, with a $measure of 1, you get the third element of @phrases. Since you probably want it to keep quiet until measure 3, where it can start at the beginning of @phrases, just add a line to the effect of:

  return if $measure < 3;

at the start of the sub. Now, you can have several subs, just like &first, above, that play all the same notes, from @phrases, but just in different measures. This structure, called a ``canon'', may seem very abstract, but it's common in songs, where it's called a ``round''. If you remember singing:

 Group 1: Row row row your boat / Gently down the stream / Merrily...
 Group 2:                         Row row row your boat  / Gently...
 Group 3:                                                  Row row...
 [and so on]

Then you were singing exactly the same kind of musical structure you get out of &first, copied and adjusted for different Ns in ($measure + N) % 4. Namely, compare the subs &first, &second, &third, and &fourth, in the this program, which plays a round based on the Westminster Chimes:

[Presumably this'll be in a greybox]

  use MIDI::Simple .68;
  my $measure = 0; # changed by &counter
  my @phrases =(
   [ Cs, F,  Ds, Gs_d1 ], [Cs,    Ds, F, Cs],
   [ F,  Cs, Ds, Gs_d1 ], [Gs_d1, Ds, F, Cs]
  );
  @bass_line = ( F,  Cs, Ds, Gs_d1, Gs_d1, Ds, F, Cs);
  new_score;
  # Some MIDI meta-information:
  copyright_text_event "1998 Sean M. Burke";
  text_event "Title: Westminster Round";
  
  # Patch inits:
  #  patch 16 = Drawbar Organ.  8 = Celesta.
  patch_change 0, 16;
  patch_change 1, 8; patch_change 2, 8;
  patch_change 3, 8; patch_change 4, 8;
  
  for(1 .. 8) {
    synch(\&count, \&bass,
          \&first, \&second, \&third, \&fourth
         );
  }
  r hn; # pause. take a bow!
  write_score("round2c.mid");
  dump_score;
  exit;
  
  sub count {
    my $it = shift;
    ++$measure;
    $it->r(wn); # whole rest
  }
  
  sub first {
    my $it = shift;
    $it->noop(c1,mf,o3,qn);
    my $phrase_number = ($measure + -1) % 4;
    my @phrase = @{$phrases[$phrase_number]};
    foreach my $note (@phrase) { $it->n($note) }
  }
  
  sub second {
    my $it = shift;
    return if $measure < 2 or $measure > 5;
    $it->noop(c2,mf,o4,qn);
    my $phrase_number = ($measure + 0) % 4;
    my @phrase = @{$phrases[$phrase_number]};
    foreach my $note (@phrase) { $it->n($note) }
  }
  
  sub third {
    my $it = shift;
    return if $measure < 3 or $measure > 6;
    $it->noop(c3,mf,o5,qn);
    my $phrase_number = ($measure + 1) % 4;
    my @phrase = @{$phrases[$phrase_number]};
    foreach my $note (@phrase) { $it->n($note) }
  }
  
  sub fourth {
    my $it = shift;
    return if $measure < 4 or $measure > 7;
    $it->noop(c4,mf,o6,qn);
    my $phrase_number = ($measure + 2) % 4;
    my @phrase = @{$phrases[$phrase_number]};
    foreach my $note (@phrase) { $it->n($note) }
  }
  
  sub bass {
    my $it = shift;
    my $basis_note = $bass_line[($measure - 1) % 4];
    $it->noop(c0,fff,o3, wn); # fff = REAL LOUD.
    $it->n($basis_note);
  }
  
  __END__


Future Features

MIDI::Simple is by no means a finished work -- there are three areas where I hope to improve the language:

* The language has plenty of functions (only some of which are discussed in this article) for dealing with notes, or characteristics of notes. However, functions for larger structures are either oddly implemented (as with set_tempo and time_signature) or missing (there are no functions implementing ``crescendo'' or ``sostenuto'', for example).

* Currently, n/r/noop accepts abbreviations like ``qn'', ``hn'', ``den'', for quarter note, half note, dotted eighth note, and so on. However, these abbreviations assume that you have just these names for these notes. But these abbreviations may prove counterintuitive if, for example, you call a quarter note not ``quarter note'', but a ``crotchet'' (as much of the English-speaking world does), or, for that matter, a ``Viertelnote'', ``semiminima'', ``negyed hangjegy'', or a ``neljännesnuotti''. Future versions of MIDI::Simple should provide a simple, documented interface for adding or changing abbreviations.

* Currently, MIDI-Perl encodes only to MIDI files. However, the MIDI event format is also (in fact, is primarily) used as the basis of a serial communications protocol connecting computers, synthesizers, drum machines, and other devices. The ability to interface with devices attached to a MIDI port will likely require OS- and hardware-specific programming well beyond what I can produce or support. But at least in the case of Unixes that provide /dev/midi and /dev/sequencer, it should be possible, with a little experimentation, to provide straightforward support for real-time access, which can be incorporated into MIDI::Simple. As an example of a useful application based on real-time MIDI access, a program using MIDI::Simple could generate a stream of ``music'' as a rendering of an incoming numeric data stream, such as stock market data, or the status of a computer network.

But finally, I don't want to suggest that MIDI::Simple is by any means the definitive approach to music languages. As the Perl motto goes, ``there's more than one way to do it'' -- and I hope that others will take this to heart and implement their own MIDI-based languages, according to their own ideas of musical structure and language design.


References

Abelson, Harold, and Gerald Sussman. 1996. Structure and Interpretation of Computer Programs. MIT Press. Burk, Phil. 1998. HMSL, The Hierarchical Music Specification Language. <http://www.softsynth.com/hmsl/>

Burke, Sean M. 1998. MIDI-Perl (including MIDI::Simple). <http://www.cpan.org/authors/id/S/SB/SBURKE/ > or <http://www.cpan.org/~sburke/ >

Sturdy, John C. G. 1998. The Cambridge Chimes. <http://www.ely.anglican.org/parishes/camgsm/chimes.html >

Walshaw, Chris. 1998. The abc Music Notation Language Home Page. <http://www.gre.ac.uk/~c.walshaw/abc/ >

Weinberg, Gerald M. 1971. The Psychology of Computer Programming. New York: Van Nostrand Reinhold.

Xenakis, Iannis. 1992. Formalized Music: Thought and Mathematics in Composition. Stuyvesant, NY: Pendragon Press.