1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-04-30 15:49:41 +02:00
audacity/lib-src/portsmf/allegro.htm
2010-01-24 09:19:39 +00:00

815 lines
28 KiB
HTML

<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<title>Allegro Music Representation Language</title>
</head>
<body>
<center>
<h1>Allegro Music Representation Language</h1>
</center>
Allegro is a simple, declarative, text-based language for music
representation.
Allegro is very similar to Adagio, but it is extended somewhat to make
the representation of beats and attributes simpler and more uniform.
Allegro
is also intended to represent Standard MIDI files, and there are
standard
attribute names and encodings in Allegro for metadata found in Standard
MIDI
files.
<p>Allegro is designed for use with Aura, and there is a mapping from
Allegro
to messages in Aura. There is an internal, object representation
of Allegro as well, which is implemented in both C++ and Serpent (the
Aura
scripting language).
</p>
<h2>Basic Concepts</h2>
Allegro represents notes, attribute/value pairs (typically updates to
notes),
and timing information in the form of tempo and beats. Allegro is a
free-form
ascii text language similar to Adagio (a notation introduced in the CMU
MIDI Toolkit). In its simplest usage, every line of text represents a
note.
Every note is a set of attributes separated by white space and ending
with
a newline.&nbsp; For example, the following indicates a quarter note at
middle C:
<blockquote>
<pre>Q C4</pre>
</blockquote>
Allegro allows each note to be tagged so that the note can be
referenced
by updates at a later time.
<h2>Standard Attributes and MIDI Data</h2>
Notes have a set of fields that correspond more-or-less to MIDI data.
The fields are:
<ul>
<li>key - the key number or tag for this note. In MIDI, the key
indicates
the pitch,
but in Allegro, the key can be any number. For example, key can be a
sequence
number so every note can have a unique name. </li>
<li>chan - the MIDI channel. In Allegro, the channel can be any
integer.
This creates
a two-dimentional name space for notes: &lt;chan, key&gt; </li>
<li>time - the starting time of the note. This can be in beats or
seconds.
The Allegro
data structure can convert from seconds to beats and back. </li>
<li>pitch - the pitch of a note, expressed in the same units as MIDI,
but
this is a float rather than an integer so that precise tuning can be
expressed. Note that in MIDI, pitch is implied by the key, but in
Allegro, the key is just a name or a way to refer to a particular
sound. The pitch can be specified separately. (If you are working with
MIDI, you will probably want to specify pitch symbolically, e.g. C4, or
as an integer, e.g. P60. The key number will default to the pitch.) </li>
<li>loud - a parameter corresponding to MIDI velocity, but this is a
float rather than
an integer. </li>
</ul>
In addition, notes can have attribute/value pairs. In Allegro, the last
letter
of the attribute conveys the type of its value. For example,
"bendr" should be read as attribute "bend" of type "r"eal. An "r"
suffix
is for "r"eal values (double precision floats). When used with Aura,
notes attributes
are represented by a sequence of messages, each generally
conveying an attribute/value
pair along with the &lt;chan, key&gt; note name. If an update applies
to all notes
on a channel, the key value is specified as -1. Some standard
attributes are listed below:
<center>
<table style="width: 75%;" border="1">
<tbody>
<tr>
<td align="left" height="13" width="50%"><b>MIDI Message Type</b></td>
<td align="left" height="13" width="50%"><b>Allegro attribute</b></td>
</tr>
<tr>
<td align="left" height="19" width="50%">pressure (polyphonic
aftertouch)</td>
<td align="left" height="19" width="50%">pressurer (keyi set to
key number)</td>
</tr>
<tr>
<td align="left" height="19" width="50%">control change</td>
<td align="left" height="19" width="50%">control0r, control1r,
control2r,
... control127r (note: values are normalized to the range [0..1])</td>
</tr>
<tr>
<td align="left" height="19" width="50%">program change</td>
<td align="left" height="19" width="50%">programi</td>
</tr>
<tr>
<td align="left" height="19" width="50%">channel pressure
(aftertouch)</td>
<td align="left" height="19" width="50%">pressurer (keyi is -1)</td>
</tr>
<tr>
<td align="left" height="19" width="50%">pitchbend</td>
<td align="left" height="19" width="50%">bendr (normalized to the
range [-1..1]</td>
</tr>
<tr>
<td align="left" height="19" width="50%">key signature</td>
<td align="left" height="19" width="50%">keysigi (number of
sharps, negative
of&nbsp; number of flats) and modea ('majora' for major, 'minora' for
minor)</td>
</tr>
<tr>
<td style="width: 50%; height: 19px; text-align: left;">time
signature</td>
<td align="left" height="19" width="50%">timesig_numr (the
numerator) and
timesig_denr (the denominator)</td>
</tr>
<tr>
<td style="vertical-align: top;">system exclusive<br>
</td>
<td style="vertical-align: top;">sysexs (message encoded as hex
string)<br>
</td>
</tr>
</tbody>
</table>
<br>
</center>
<p>Standard MIDI File metadata is also encoded into allegro attributes
as shown below:<br>
</p>
<center>
<table style="text-align: left; width: 75%;" border="1">
<tbody>
<tr>
<td style="vertical-align: top;" width="30%"><span
style="font-weight: bold;">Metadata
Type</span><br>
</td>
<td style="vertical-align: top;" width="70%"><span
style="font-weight: bold;">Allegro
attribute</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">text (0x01)<br>
</td>
<td style="vertical-align: top;">texts (note that the "s" suffix
indicates a string value)<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">copyright (0x02)<br>
</td>
<td style="vertical-align: top;">copyrights<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">instrument (0x04)<br>
</td>
<td style="vertical-align: top;">instruments<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">lyric (0x05)<br>
</td>
<td style="vertical-align: top;">lyrics<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">marker (0x06)<br>
</td>
<td style="vertical-align: top;">markers<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">cue (0x07)<br>
</td>
<td style="vertical-align: top;">cues<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">misc (0x08)<br>
</td>
<td style="vertical-align: top;">miscs<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">smpte offset (0x54)<br>
</td>
<td style="vertical-align: top;">smpteoffsets (SMPTE offset is
encoded in a string as follows: <span style="font-style: italic;">dd</span>fps:<span
style="font-style: italic;">dd</span>h:<span
style="font-style: italic;">dd</span>m:<span
style="font-style: italic;">dd</span>s:<span
style="font-style: italic;">dd.dd</span>f, where <span
style="font-style: italic;">dd</span> is a two-digit decimal number.
The one exception is that 30fps drop frame times are designated by
"29.97fps:...". Examples: "24fps:00h:00m:00s:00.00f",
"29.97fps:00h:01m:40s:00.01f")<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">MIDI Channel Prefix (0x20)<br>
</td>
<td style="vertical-align: top;">MIDI Channel Prefix is used to
assign a channel to a meta-event. In Allegro, this channel becomes a
key specification, e.g. "K4 -cues:"cue15".<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">sequencer specific (0x7F)<br>
</td>
<td style="vertical-align: top;">sqspecifics (data encoded as a
hex string)</td>
</tr>
<tr>
<td style="vertical-align: top;">sequence name (0x03)<br>
</td>
<td style="vertical-align: top;">
<table style="width: 75%;" border="1">
<tbody>
<tr>
<td style="vertical-align: top;">seqnames (in Allegro
files, sequence
name is written after #track 0, but internally data is stored as if one
had written, e.g. -seqnames:"Jordu")<br>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style="vertical-align: top;">track name (0x03)<br>
</td>
<td style="vertical-align: top;">tracknames (in Allegro files,
track name is written after #track <span style="font-style: italic;">n</span>
where <span style="font-style: italic;">n </span>&gt; 0, but
internally data is stored as if one had written, e.g.
-tracknames:"Bass")</td>
</tr>
</tbody>
</table>
</center>
<p><br>
</p>
<h3>MIDI Track Data</h3>
<p>A few attributes, such as beatr and tempor, key signature
information,
and time signature information apply to all channels. The chani
attribute
can be set to -1 to indicate all channels.
</p>
<p>Tracks from Standard MIDI Files are represented in the internal
Allegro
data structure. By default, all data goes to track zero (0), but a new
track can be designated using the syntax "#track <i>n</i>", where <i>n</i>
is an integer track number. All notes and updates following this track
specification (until the next one) go into the designated track.
From the programming API, track numbers can be encoded using the
channel; for
example, if the Allegro channel is:
<br>
&nbsp;&nbsp;&nbsp; track_number * 100 + midi_channel,
<br>
then channel 1207 (decimal) will indicate track 12, midi channel 7.
To preserve track association, the Allegro memory structures store each
track separately. Per-track metadata is stored with the associated
track with
a channel value of -1.
</p>
<h2>Allegro Syntax</h2>
Because Allegro has no nested expressions or complicated syntax, I will
not present a detailed formal grammar. The previous section outlined
the
semantics of attributes. This section describes the syntax to denote an
attribute. Additional syntax and semantics for tempo and beats is given
in the next section.
<p>Allegro notes and updates are denoted by a line of text containing a
set of attributes. In addition, if a line begins with the characterrs
"#",
the line is not interpreted as a note or update. If the line begins
with
"# " (hash, space) the line is a comment. The characters "#track"
denote
the beginning of&nbsp; a new track. The "new track" syntax is:
<br>
&nbsp;&nbsp;&nbsp; #track <i>track_number</i> "<i>track_name</i>"
<br>
where <i>track_number</i> is a decimal integer and <i>track_name</i>
is any string of characters. Other metacommands beginning with "#" may
be introduced in the future.
</p>
<p>All strings are quoted with double (") quotes. To enclose quotes and
other special characters in strings, use backslash ("\") as the escape
character. You must type two backslashes to enter one backslash in a
string,
e.g. the string "\\" has a length of one.
</p>
<p>Allegro is case-insensitive, that is, upper and lower case letters
are
treated as the same, except that full attribute names, when spelled
out,
are case-sensitive. By convention, attributes are lower case for
uniformity
and simplicity. In the following, an italic <i>n</i> indicates a
decimal
integer, e.g. "7", and an italic <i>r</i> indicates a decimal floating
point number, e.g. "7.34".
</p>
<p>Allegro events always carry a channel number, but some data is not
channel-specific.
These events use channel number -1. Similarly, some updates apply to
every
note on a channel and are therefore not key-specific. These updates use
key number -1. Purely for aesthetic reasons, there is a special syntax
for -1, namely, channel -1 can be indicated "V-" and key -1 can be
indicated
"K-". (In common cases,&nbsp; "K-" can be omitted.)
<br>
&nbsp;
<table border="1" width="100%">
<tbody>
<tr>
<td width="50%">
<center><b><font size="+1">Allegro Field or Attribute</font></b></center>
</td>
<td width="50%">
<center><b><font size="+1">Allegro Syntax</font></b></center>
</td>
</tr>
<tr>
<td width="50%">chan</td>
<td width="50%">V<i>n</i></td>
</tr>
<tr>
<td width="50%">key</td>
<td width="50%">K<i>n</i>, Af<i>n</i>, A<i>n</i>, As<i>n</i>,
..., Gf<i>n</i>,
G<i>n</i>, Gs<i>n</i></td>
</tr>
<tr>
<td width="50%">loud</td>
<td width="50%">L<i>r</i>, Lppp, ..., Lfff</td>
</tr>
<tr>
<td width="50%">pitch</td>
<td width="50%">P<i>r</i>, Af<i>n</i>, A<i>n</i>, As<i>n</i>,
..., Gf<i>n</i>,
G<i>n</i>, Gs<i>n</i></td>
</tr>
<tr>
<td width="50%">dur</td>
<td width="50%">U<i>r</i>, S, I, Q, H, W, etc.</td>
</tr>
<tr>
<td width="50%">time</td>
<td width="50%">T<i>r</i>, TS, ..., TW, etc.</td>
</tr>
<tr>
<td width="50%">(next time is not an Aura attribute)</td>
<td width="50%">N<i>r</i>, NS, ..., NW, etc.</td>
</tr>
<tr>
<td width="50%">(syntax for additional attributes/value pairs)</td>
<td width="50%">-<i>attribute</i>:<i>value</i></td>
</tr>
</tbody>
</table>
</p>
<h3>Notes vs. Updates</h3>
A new note or sound object is created by the appearance of a field with
any of the following initial letters: P, A, B, C, D, E, F, G (pitches),
or U (duration). If neither an explicit pitch or duration appears, then
an update is generated. In terms of Aura streams, an update means that
no "gater" attribute will be generated, and no sound resource will be
allocated.
It is assumed (but not checked) that an update applies to an existing
resource
and merely modifies some of its attributes.
<p>Since a pitch specification indicates a new note, use something like
"-pitchr:60" to update pitch. Consider using "bendr" instead, or
generate
notes anyway and send them to a synthesizer that implements something
like
MIDI&nbsp; "mono" mode.
</p>
<h3>Sticky Attributes</h3>
Most attribute values need not be specified if they do not change from
their lexically previous value. However, a blank line does not mean
"repeat
the last note;" at least one attribute must be present to signify
anything
at all. Only if a note is specified using at least a pitch or duration
will certain default values be used. For example, default pitch is
ignored
if only pitch bend is updated.
<p>To get MIDI-like semantics, the keyi (K) attribute should not be
specified
at all. If you specify pitch using P or A through G, then the key will
be implied by the pitch, and notes will therefore be identified as in
MIDI.
For example, a MIDI note-off message uses key number (not pitch, which
may
depend upon pitch-bend, etc.) to say which note to turn off.
</p>
<p>If the key (K) is specified and less than 128, and no pitch is
specified,
then the pitch will default to the the key number. Thus K60 (with no
P60
or C4 pitch specifications) is equivalent to P60 or C4.
</p>
<p>If keyi (K) is not specified, control changes will have no keyi and
therefore apply to the channel as a whole. This also corresponds to
MIDI.
The one exception to this is that pressure (polyphonic aftertouch) MIDI
messages need a key number. If you specify pitch along with the control
change, a new note will be generated. Therefore, to issue a polyphonic
aftertouch message without a new note, you should use something like
"V5
KG4 -pressurer:50", which says "on channel 5, pressure 50 on key 67 (g
above middle c)."
</p>
<p>To get more general semantics, every note can have an identifier.
This
allows multiple notes with the same pitch or for pitches of notes to
change
without ambiguity. Identifiers are specified by the keyi (K) attribute,
for example "V5 K279 G4" creates a note (g above middle c) and labels
it
with the identifier 279. With this style, all updates should normally
have
a keyi (K) attribute, for example "V5 K279 -pressurer:50" sends&nbsp; a
pressure changes to note 279. If "K" is omitted from a control change
specification,
then the control change applies to the channel, just as with the "MIDI
style" in the previous paragraph. <i>In other words, there is an
implicit
"K-1" attribute on all non-note attribute specifications. </i>Thus,
keyi
is not a "sticky" attribute.
</p>
<p>The initial default time is zero. The default time for the next
event
is computed as follows: Set the default time to the time of the current
event. If a "N"ext attribute is given, the default time is incremented
by the value of the "N"ext attribute. Otherwise, if the current event
is
a note, increment the default time by the duration of the note. This
results
in a new default, which may be overridden by a "T" attribute in the
next
event.
</p>
<h3>Pitch Specification</h3>
Pitches in Allegro are the same as in Adagio. The letters "A" through
"G"
are followed optionally by one or more "S" (sharps) or "F" (flats), and
then by an octave designation (an integer). C4 is middle C. Octaves run
from C to B, so B4 is higher in pitch than C4, as musicians would
expect.
Sharps and flats are added after the octave is computed, so for
example,
Cf5 is the same as B4, even though the octave numbers are different.
<p>Octave numbers may be omitted, in which case the octave is chosen
such
that the pitch will be closest to the lexically previous pitch (in any
voice). If the previous pitch is 6 half-steps (a tritone) away, then
the
current pitch will be higher than the previous pitch. When in doubt,
specify
the octave explicitly.
</p>
<p>Pitch may also be specified as "P" followed by a number. P60 is
middle
C, P61 is a half step higher, equivalent to Cs4, and P60.5 is a quarter
tone sharper than P60.
</p>
<p>Although not recommended, "P" may also be followed by a "non-P"
pitch
specification starting with "A" through "G".
</p>
<h3>Duration Specification</h3>
Durations are the most complicated attributes in Allegro and Adagio.
The
duration letters S, I, Q, H, and W designate Sixteenth, eIghth,
Quarter,
Half, and Whole notes. These letters may be followed by any combination
of "." (dots) and "T" (triplets). A dot multiplies the duration by 1.5.
Two dots multiply the duration by 1.75, etc. A triplet multiplies the
duration
by 2/3. The end of the specification is an optional multiplier (an
integer)
followed by an optional divisor ("/" followed by an integer.)
<p>Durations may be combined using "+", which has lower precedence than
any other duration operators.
</p>
<p>Some examples follow:
</p>
<blockquote>&nbsp;
<table border="1">
<tbody>
<tr>
<td width="30%">
<pre>Q3</pre>
</td>
<td width="70%">3 beats</td>
</tr>
<tr>
<td width="30%">
<pre>H.</pre>
</td>
<td width="70%">3 beats</td>
</tr>
<tr>
<td width="30%">
<pre>HT</pre>
</td>
<td width="70%">4/3 beats (half note triplet)</td>
</tr>
<tr>
<td width="30%">
<pre>IT.</pre>
</td>
<td width="70%">1/4 beats (a dotted sixteenth triplet)</td>
</tr>
<tr>
<td width="30%">
<pre>HTT</pre>
</td>
<td width="70%">8/9 beats</td>
</tr>
<tr>
<td width="30%">
<pre>Q/5</pre>
</td>
<td width="70%">1/5 beats</td>
</tr>
<tr>
<td width="30%">
<pre>W3/23</pre>
</td>
<td width="70%">12/23 beats</td>
</tr>
<tr>
<td width="30%">
<pre>Q..</pre>
</td>
<td width="70%">7/4 beats (doubly dotted quarter)</td>
</tr>
<tr>
<td width="30%">
<pre>Q+I</pre>
</td>
<td width="70%">3/2 beats (quarter tied to eighth)</td>
</tr>
<tr>
<td width="30%">
<pre>IT+Q5</pre>
</td>
<td width="70%">5 and 1/3 beats (eight triplet tied to 5
quarters)</td>
</tr>
</tbody>
</table>
</blockquote>
Durations may also be specified by the letter U followed by a number of
milliseconds. A decimal point is allowed, e.g. <tt>U23.25</tt>.
<h3>Loudness Specification</h3>
Loudness is specified by "L" followed by "ppp", "pp", "p", "mp", "mf",
"f", "ff", "fff", or by a floating point number. The normal&nbsp;
loudness
range is that of MIDI velocity, from 0 (silent) to 127 (maximum). The
interpretation
of dynamic markings and the numerical values is to be determined.
<h3>Time Specification</h3>
Times are specified just like durations, except that a leading "T"
indicates
this is a time. If the "T" is followed by a digit, then the time is
specified
numerically as milliseconds. For example, "TW5" means 5 whole notes or
20 beats, while "T20" or "T20.0" means 20 milliseconds.
<h3>Next Time Specification</h3>
The default time of the next note, sound or update can be specified
just
like durations, except that a leading "N" is given. If "N" is followed
by a digit, then the value is specified numerically as
milliseconds.&nbsp;
For example, "NQ" means the next event should take place a beat after
this
event. This specifies a default which may be overridden by an explicit
time specification in the next event.
<h2>Tempo Maps</h2>
The goal of tempo specification in Allegro is to allow flexibility
without
getting overly complex. There is one and only one tempo map per score.
This is a limitation, but it is certainly possible to have multiple
score
objects when multiple tempo maps are required. Tempo maps can be
specified
by entering beats or by entering tempo changes. Internally, a tempo map
is a sequence of pairs indicating time and beat. Tempo is assumed to be
constant between any two adjacent points in the tempo map. In a stream
of Aura events, tempo map events are translated into two attributes:
beatr
and tempor. The beatr attribute gives the current beat, and the tempor
attribute gives the tempo change. The use of tempor allows the receiver
to respond to tempo changes without waiting for the next beat.
<p>When the tempo map is manipulated, either the time or the beat
position
must change. In Allegro, changes to the tempo map also change event
times
so that their beat positions remain unchanged.
</p>
<p>On the other hand, when beats are specified, the tempo map is
manipulated
but event times are not changed. This effectively changes the beat
positions
of events. This is useful if performance data is captured and then beat
information is added after the fact.
</p>
<p>The entries in the tempo map are in non-decreasing time order and
non-decreasing
in beat order. Any attempt to specify an illegal tempo map in Allegro
generates
an error. This would most likely occur in Allegro as the result of
inserting
a beat at a position that conflicts with other beats.
</p>
<h3>Avoiding Numerical Problems</h3>
Instantaneous changes in beat position (infinite tempo) are not
allowed,
nor are zero tempos allowed. However, attempts to create an infinite or
zero tempo are automatically approximated by shifting beats or times in
the time map by one microsecond or one microbeat. For example, if the
tempo
at some beat position <i>b</i> is set to zero, the next entry in the
time
map is changed to have a beat position <i>b</i> + 0.000001. There is
no
way in Allegro to specify an infinite tempo: if you specify a second
beat
position at at given time, the entry in the time map is simply edited
to
contain the new beat position. One exception to this is at the
beginning
of the score. Beat 0 occurs at time 0, so if you insert, say, beat 5 at
time 0, you imply an infinite tempo. The score object will
automatically
change this to beat 5 at time 0.000001 seconds.
<h3>Specifying Beat Times</h3>
Beat encoding might be used to synchronize external MIDI sequences or
to
generate a MIDI file for use in a sequencer or music notation package
where
beat information is necessary. The following example specifies beat 25
at time 10.542 seconds:
<blockquote>
<pre>-beatr:25.0 T10542</pre>
</blockquote>
Unlike normal attribute/value pairs, which are stored as events in the
score, the beatr attribute generates an entry in the tempo map. It is
an
error to try to insert a beat such that the implied tempo would be
negative.
(Beats in the tempo map must be non-decreasing.)
<p>When a beat is inserted into the time map, events in the score
retain
their times. This can cause very strange behavior if the time is
specified
in beats, because you are saying something like "insert beat 10 at beat
15." This has a well-defined interpretation: beat 15 is mapped to time
<i>t</i>
in seconds. Then, the entry (<i>t</i>, 10) is inserted into the tempo
map.
Now, what used to be at beat 15 (or time <i>t</i>) is now at beat 10.
Normally,
one would only specify beats at absolute times as shown in the example
above.
</p>
<h3>Specifying Tempo</h3>
For text based notation and composition, we usually want to specify
notes
in terms of beats and specify the tempo of different sections of the
score.
The following example specifies tempo changes:
<blockquote>
<pre>TQ50 -tempor:80.0<br>...<br>TQ100 -tempor:100.0<br>...</pre>
</blockquote>
These insert tempo changes to 80 and 100 beats per minute at beats 50
and
100, respectively. Notice the use of "Q" to specify units of beats
instead
of milliseconds. Tempo changes can be specified at any time. Event
times
throughout the score are adjusted according to the new tempo.
<p>Times and durations expressed directly in milliseconds require
special
care in combination with tempo specifications. When tempo is changed, <i>every</i>
score event is remapped according to the new tempo. If a duration is
specified
as 100ms and then later in the score, tempo in that region is doubled,
the actual duration will be 50ms. If the duration had been specified as
a sixteenth note, it would still be a sixteenth note after the tempo
change.
Thus, all times and durations are treated as if they are beats when
tempo
is altered.
</p>
<p>To freely mix time and beat specifications, it is recommended to
specify
a complete time map before any score events.
</p>
<h3>Time Representation</h3>
Internally, score events are associated with timestamps in units of
seconds.
An auxiliary structure contains a sequence of timestamped beat
positions.
For example, the structure might contain ((0, 0), (10, 10), (20, 30)),
which indicates that at time zero, we are at beat zero. At time 10, we
are at beat 10, so the tempo for the first 10 seconds is 60 beats per
minute.
At time 20, we are at beat 30, so the tempo from 10 to 20 is 120 beats
per minute (20 beats in 10 seconds). The structure may also contain a
final
tempo, indicating the mapping from time to beats after the last beat
position
entry. If no final tempo is indicated, tempo and beats are extrapolated
from the last two points in the map. Initially, the map has just one
point,
(0, 0), and tempo100.
<p>There is a danger that the extrapolated tempo may not correctly
predict
the next beat specification. This is not an error, and it just means
that
the tempo over some time interval must be recomputed based on the new
beat
information. The problem, however, is that any events that occur within
that interval should probably be adjusted in time according to the new
tempo. To avoid this problem, it is best to specify timing using tempo
specifications rather than beat locations. In addition, the data
structure
does adjust times according to the beat information. Finally, when
event
data is generated, both beat positions and tempo changes are sent,
avoiding
the need to extrapolate tempo from previous beat positions.
</p>
<h3>Time Manipulation</h3>
An important aspect of this design is to support editing and
manipulation
of data. Operations include:
<ul>
<li>insert a beat position at a time position: this operation
modifies the
data structure by inserting a (time, beat) pair. No times are altered
if
the new beat position is not at the end of the structure. If at the
end,
times are adjusted between the previous last time position and this new
time position.</li>
<li>insert a tempo at a time position: this inserts a (time, beat)
pair and
adjusts the times of everything that follows so that the tempo is
achieved
to the next beat. If the time position corresponds to the last time in
the structure, the tempo is used in place of extrapolation.</li>
<li>maintain a tempo over a region: this inserts a (time, beat) pair
for
the
beginning and ending of the region, and removes all pairs in the
region.
Times after the region are adjusted.</li>
</ul>
<h2>
Internal Representation</h2>
In Serpent, the representation is a class called Seq, containing the
fields
Notes and Map. Notes is a sequence of Events, and Map is a sequence of
time/beat pairs.
<p>An Event has fields time, key, and channel. Subclasses of Event
include Note
and Update. A Note has fields dur, pitch, loud, and attributes
(attributes
is a dictionary of attribute:value pairs). An Update has additional
fields attribute,
and value.
</p>
<p>In C++, the allegro.h header documents (to some extent) the data
structures.
</p>
</body>
</html>