rationale behind n/r/noop

[email protected] ("Sean M. Burke") Sun, 20 May 2001 18:21:28 -0600
Newsgroups perl.midi
Message-ID <[email protected]>
The previous post explains how n/r/noop behave currently.  However, to
actually understand why they are that way, below I've pasted in exerpts
from my TPJ article about MIDI-Perl,
  http://www.speech.cs.cmu.edu/~sburke/midi-perl/tpj_13_midi.html
...which I think I'll bundle in the next dist.  The whole article is long,
but quite worth reading and rereading, since it gives a lot of necessary
backstory on MIDI-Perl.



The typical event's [i.e., note'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.

[...]

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. 

[...]

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.)


--
Sean M. Burke  [email protected]  http://www.spinn.net/~sburke/