Demonstration 1 provided the practical component for Chapter 3: “Literal Selection” of my unpublished textbook on composing programs. It illustrates the basic design of a complete composing program. In particular it shows how a composer might implement literal strategies to derive not only the musical details, but also the broader level of musical structure.
From the perspective of my production framework, the process as a whole is a single problem interleaving decisions about phrase attributes with decisions about note attributes. What distinguishes this Demonstration from all others is that its decisions implement the degenerate scenario known as Hobson's choice. Except that this composing program does not have the luxury of trying another stable.
The piece derives entirely from the three rows depicted in Figures 1 (a), 1 (b), and 1 (c). It has three levels of structure: the local level consists of individual notes; the median level consists of 24-note phrases; and the global level consists of the piece as a whole, which spans four entire phrases.
Each phrase in Demonstration 1 constitutes a resultant created by phasing four cycles of the pitch row against three cycles of the period row. Figure 2 illustrates how the opening resultant of the piece is derived. Concurrent with each cycle of periods is a cycle of the nine articulations. Notice that the cycles of pitches and periods come back into alignment at the end of the phrase because one element in each cycle of articulations is always a rest.
Measure | Pitches | Periods |
---|---|---|
1 | High Register Retrograde |
No augmentation Prime form |
7 | Low Register Retrograde - inversion |
Augmentation by 2 Inversion |
25 | Medium Register Inversion |
Augmentation by 3 Retrograde - inversion |
37 | High Register Prime form |
No augmentation Retrograde |
Table 1 gives the layout of Demonstration 1 and details which transformations have been applied to the pitch and period rows in each phrase. Here are the outcomes from a decision-making process which, rather than being delegated to the computer, was undertaken prior to the automated phase of production. But you can see criteria at work which, with greater programming sophistication, could conceivably have been programmed. For example, the series forms (prime, inversion, retrograde, retrograde-inversion) are each employed once for pitches and once for durations; also, pitch and rhythm never employ the same series form in the same phrase. Also, registers cycle through high, low, and medium before recapping with high register in the fourth phrase. Likewise, augmentations cycle through 1×, 2×, and 3× before recapping with 1×.
The complete musical product appears in Figure 3.
The explanations to follow focus on three musical attributes: pitch, timing (approached through the notion of periods between consecutive attacks), and articulation. Their purpose is to tease out the strands of code that affect a particular attribute, and thus to reveal the mechanics of literal selection in play. The explanations are peppered with line numbers identifying where precisely the various declarations, data initializations, loops, branches, calculations, and subroutine calls may be found in the printed listing. Yet these line numbers will distract your focus from attribute-specific strands to the greater mass of code. You are by no means expected to chase down every line of code. Rather, you should follow through with line numbers only when you have a specific question that the narrative is not answering.
The design of DEMO1
reflects a structure of phrases and notes:
DEMO1
proper.
The source code for DEMO1
appears as Listing 1.
PHRASE
, whose source code appears as
Listing 2.
PHRASE
receives support from the library subroutine SEQUEN
.
WNOTE
, whose source code appears as
Listing 3.
WNOTE
also writes this text out to the file named “DEMO1.DAT”.
Lines 7-10 of program DEMO1
implements the layout through four
calls to subroutine PHRASE
.
PHRASE
receives information from Table 1 through seven
explicit arguments:
ITIME
— Phrase start time in sixteenth notes.
IREG
— Register expressed as an offset; 0 indicates 32' C.
IAUG
— Augmentation factor, used to multiply note durations.
INCPCH
— Increment for pitch row: 1 indicates forward; -1 indicates retrograde.
INCPER
— Increment for period row: 1 indicates forward; -1 indicates retrograde.
ISGN
— Direction for pitch row: 1 indicates original; -1 indicates inversion.
RHYFLG
— Flag for period inversion: If false, original period values are used; if true,
period values (1, 2, or 4) are divided into 4.
A final call to subroutine WNOTE
(line 11) acts to close the piece on a quarter-note C5 with normal articulation.
The source code for subroutine PHRASE
appears as Listing 2.
The symbols in PHRASE
are associated with musical attributes through three abbreviations:
PCH
— pitch, expressed as an offset from the first note in the row. Parameter MPCH
(line 2) sets the length of the pitch row to 6. Array VALPCH
holds the pitch row. This array is populated
in line 5, with contents expressed as offsets relative to the starting pitch.
Variable IDXPCH
tracks the current pitch-row position.
PER
— period between consecutive attacks. Parameter MPER
(line 2) sets the length
of the period row to 9. Array VALPER holds the period row. This array is populated in line 6, with values
indicating 1, 2, or 4 sixteenth notes. Variable IDXPER
tracks the current period-row position.
ART
— articulation. Parameter MART
(line 2) sets the length of the articulation row to 9.
Array VALART holds the articulation row. This array is populated in line 7,
with values indicating 0 (rest), 1 (staccato), 2 (normal), 3 (slur).
Variable IDXART
tracks the current articulation-row position.
The library subroutine SEQUEN
1
is modeled on the SEQUENCE feature of G.M. Koenig's Project Two.
It implements the most basic of literal procedures; that is, sampling elements in order from a row.
Calls to SEQUEN
require five arguments:
RESULT
— SEQUEN
selects a new element from a row and returns
the row value in this location.
VALUE
— Supply of values arranged in position order. Duplicate values are permitted.
VALUE
must be an array in the calling program whose dimension in the calling program is NUM
(argument #5 below).
IDX
— Index to pending selection. IDX
must be an integer in the calling
program. Before anything else, SEQUEN
increments IDX
by INC
(argument #4 below).
Whenever IDX
threatens to move
outside the range from 1 to NUM
, SEQUEN
performs wrap-around arithmetic
to restore IDX
into range. SEQUEN
completes by setting RESULT=VALUE(IDX)
.
Initializing IDX
to 1-INC
causes the
first call to SEQUEN
to return the first element of VALUE
.
INC
— Sampling increment. INC
must be an integer in the calling program.
It can be either positive or negative (setting INC
to -1 produces the retrograde) but it should
always be relatively prime to NUM
.
NUM
— Number of row elements (dimension of array VALUE
in the calling program).
The length of each row is given by a parameter starting with the letter M
;
values of the prime row-forms reside in arras beginning with VAL
.
Each row also has an associated index beginning with IDX
.
The transformations used to generate additional material for Demonstration 1 break down as follows:
IREG
(line 29 of PHRASE
).
All transpositions in Demonstration 1 occur at the octave.
ISGN
(line 29) determines whether offsets from array VALPCH
go
upward (ISGN * IPCH
positive) or downward (ISGN * IPCH
negative).
INCPCH
determines whether SEQUEN selects offsets by sampling forward or
backward through array VALPCH
(line 27).
INCPER
(line 17 of PHRASE
) determines whether SEQUEN
selects periods
by sampling forward or backward through array VALPER
.
RHYFLG
(line 19) determines whether or not PHRASE
should invert the relative period IPER
.
IAUG
(line 21) converts the relative period IPER
into
an absolute period.
VALART
(line 15).
Each complete cycle through VALART
causes PHRASE
to rotate each element of VALART
by one position
by initiating a call (line 14) to the library subroutine ROTATE
.
The library subroutine ROTATE
2 accepts an array of arbitrary
dimension and shifts the elements of the array by an arbitrary number of positions. Calls to ROTATE
require
three arguments:
VALUE
— Array of values, arranged in position order. VALUE
in the calling program must be an array of
dimension NUM
(argument #3 below).
NSHIFT
— Number of positions each element is to shift. If NSHIFT
is positive, then the shift
will be rightward/clockwise; if NSHIFT
is negative, then the shift will be leftward/counter-clockwise.
NUM
— Number of row elements (dimension of array VALUE
in the calling program).
The mechanics of subroutine WNOTE
bear close attention because they serve for most the of Demonstrations
in this series. When it calls WNOTE
to append a note to the human-readable listing, DEMO1
provides four
arguments:
ITIME
— Start time in sixteenth notes.
DUR
— Duration in sixteenth notes.
IPCH
— Pitch, expressed as in integer offset from 32'C.
IART
— Articulation: (0) rest, (1) staccato, (2) normal, (3) slur.
The first task of WNOTE
is to place ITIME
in a measure (lines 8-19).
The author finds it most convenient to begin measures on beat 0.
Conversion of numeric degrees to letter names is easily accomplished using the character array LETTER
.
The convention is to express registers in octaves above 32'C (making 32'C C0; middle C is C4; A 440 is A4, and so on).
The character array ARTIC
converts numeric articulations into readable text indications.
SEQUEN
is described in Automated Composition,
Chapter 3,
pp. 3-8 to 3-9.
ROTATE
is presented in Automated Composition,
Chapter 3,
pp. 3-13 to 3-15.
© Charles Ames | Original Text: 1984-11-01 | Page created: 2017-03-12 | Last updated: 2017-03-12 |