Demonstration 9 provided the second of two practical components for Chapter 11: “Musical Design II: — Grammars” of my unpublished textbook on composing programs. Like Demonstration 8, Demonstration 9 employs the method of generative grammars and also illustrates the principle of top-down design. This time, the productions divide regions of musical space into nested sub-regions.
The archetype for Demonstration 9 is described by extents along three axes.
The productions for Demonstration 9 progressively refine this description by dividing sections into sub-sections and then recursively treating each sub-section as a section in its own right. Figure 1 illustrates this process for measures 1-51 of Demonstration 9. Of the two kinds of production,
There are four binary modes and three ternary ones; each specific mode is distinguished by the proportions between subsection durations.
In order to project the grammatical structure clearly, no subsection exploits any registral or chromatic resource not already inherent in the section which produced it. To emphasize similarities between the two outer (a) subsections in ternary divisions, ternary productions pass identical resources to outer subsections. To emphasize differences between (a) and (b) subsections in both binary and ternary divisions, productions pass complementary resources to (a) and (b) subsections.
Each act of division deals with registers by dividing the section's extent into two overlapping subranges: a lower range covering the bottom two-thirds of the section extent and an upper range covering the top two thirds of the section extent. Which subrange goes to the (a) subsection is determined by a coin toss, the remaining subrange goes to the (b) subsection.
With regard to chromatic resources, each act of division derives two distinct (though overlapping) subsets from the set of chromatic degrees characterizing the section.
The transcribed product appears in Figure 2 (a) and Figure 2 (b).
|
|
|
| Figure 2 (a): Figure 2: Transcription of Demonstration 9, page 1. | Figure 2 (b): Figure 2: Transcription of Demonstration 9, page 2. |
The following explanations seek to illustrate recursive grammars in play. The explanations are peppered with line numbers, but you are 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.
Program DEMO9 proper appears as Figure 3 (a); the BLOCK DATA
routine used to initialize COMMON memory variables appears as Listing 2.
|
|
|
Figure 3 (a): Program DEMO9.
|
Listing 2: BLOCK DATA routine for DEMO9.
|
Since Demonstration 9 elaborates only one statement of its archetype, the main composing loop in
program DEMO9 proper implements recursive processing. Variable names will be familiar
from Demonstration 8's subroutine COMPOS:
LEVEL tracks the level of recursion, iterating from the top down and back. IDX
tracks horizontal progress, iterating from left to right in the time dimension.
Each iteration of DEMO9's main loop (lines 23-49) begins by incrementing IDX (line 25),
then testing if IDX has reached the limit stored in array element CNTLEV(LEVEL).
The value of IDX is saved (“pushed”) into array element IDXLEV(LEVEL) before LEVEL advances;
IDX is retrieved (“popped”) from IDXLEV(LEVEL) after LEVEL retreats.
For the present purpose, IDX identifies a subsection either of the piece as a whole (the archetype) or of a
section at the previous recursive level. Sectional attributes are stored in multidimensional arrays indexed both by IDX
and by LEVEL:
DURLEV(IDX,LEVEL) holds the duration of subsection IDX.
RLWLEV(IDX,LEVEL) and RHGLEV(IDX,LEVEL) hold lower and upper boundaries, respectively,
for a value which will ultimately define the lowest pitch in a twelve-semitone gamut.
NUMLEV(LEVEL) indicates how many degrees of the chromatic scale are to be exploited at the current level.
The specific degrees exploited in subsection IDX reside in array elements DEGSCD(1,IDX,LEVEL)
through DEGSCD(NUMLEV(LEVEL),IDX,LEVEL).
Lines 20-26 of program DEMO09 express the archetype by setting CNTLEV(1,1)
to 1, DURLEV(1,1) to the duration of the composition, RLWLEV(1,1) and RHGLEV(1,1) to
values reflecting the range of the clarinet, NUMLEV(1) to 12, and DEGSCD(1,1,1) through DEGSCD(12,1,1)
to the twelve degrees of the chromatic scale.
For LEVEL=2 through LEVEL=6, line 38 of DEMO09 articulates consecutive sections with a rest
whose duration resides in array element RSTLEV(LEVEL). Since the values of array RSTLEV are static, they
are populated in line 13 of the BLOCK DATA routine.
Remember that I termed Demonstration 9 an “architectural” grammar because notes are generated only at the
bottommost level of recursion. Note-generating requests are implemented as calls to subroutine WNOTE (lines
47-48).
Productions for Demonstration 9 divide sections into subsections.
Implementing these productions boils down to populating values into DURLEV, RLWLEV,
RHGLEV, NUMLEV, and DEGSCD
for LEVEL+1 given values previously populated into these same arrays for LEVEL.
The code module responsible for this is subroutine DEDUCE, which appears in Listing 3 (a) and
Listing 3 (b).
|
|
|
Listing 3 (a): Subroutine DEDUCE, lines 1-71.
|
Listing 3 (b): Subroutine DEDUCE, lines 72-138.
|
The first step in dividing a section into subsections is to choose a mode of division.
DEDUCE implements this choice in lines 15-29, which places the selected mode in the variable IDIV.
There four binary modes and three ternary modes.
The number of sections for mode IDIV is given by array element CNTDIV(IDIV) while the duration of subsection
IDX is given by array element FACDIV(IDX,IDIV). Since the contents of CNTDIV and
FACDIV are static, both arrays are initialized in the BLOCK DATA routine.
Subsection durations are expressed relative to parent section durations; that is why the values of FACDIV sum to
unity for each mode of division.
The BLOCK DATA routine initializes all elements of array WGTDIV to unity,
but this array is not static. Here is the mechanism which prevents any one mode of division from being chosen more than once along
any vertical path one might trace down through the structure. Array element WGTDIV(IDIV) holds the relative likelihood of
selecting mode IDIV. For LEVEL=1, each element of WGTDIV has its initialized value of unity.
Thus all modes have equal likelihood of selection. Should the choice for IDIV at LEVEL=L
be I, then I is populated into array element
DIVLEV(L) while WGTDIV(I) is
cleared to zero (line 44 of program DEMO09). This prevents mode I
from being reselected at any lower level. When the composing process retreats back to LEVEL=L,
array element WGTDIV(I) resets to unity (line 54 of DEMO09).
Line 21 of subroutine DEDUCE dereferences the subsection count from array element
CNTDIV(IDIV) into variable LCNT. The mechanism for selecting durations of subsections varies with LCNT
as follows:
DEDUCE selects the variable MORE to indicate the longer subsection while selecting the variable
LESS to indicate the shorter subsection.
Understand that my library function IRND called in line 32 generates random numbers ranging from 1 up to the
indicated argument.
Thus DEDUCE selects either MORE=1 and LESS=2 or MORE=2 and LESS=1
with equal likelihood. Lines 34-35 dereference relative proportions from FACDIV(1,IDIV) and FACDIV(2,IDIV),
scale these proportions to the section duration, then distribute the results to subsections.
FACDIV(1,IDIV), FACDIV(2,IDIV), and FACDIV(3,IDIV)
holds the relative proportions which lines 40-42 scale to the section duration, then distribute to subsections.
Lines 47-71 of subroutine DEDUCE compute subsection ranges as two-thirds of the section extent, positioned
either at the bottom or at the top. The library subroutine SUCCES(P) implements a Bernoulli trial with output
values 0 (probability P) or 1 (probability 1-P). Having the probability set to 1/2 in line 48 means that which range (lower or upper)
goes with which subsection is decided by a coin toss.
Lines 76-136 of subroutine DEDUCE allocates chromatic degrees to subsections. This process most
heavily favors those degrees which have been least exploited elsewhere in the piece.
The first step uses the library subroutine DSORT to
marshal the current section's chromatic set into a preference order.
DSORT expects an integer array for argument 1, a real array for argument 2, and a
simple integer for argument 3. The integer array contains the values which will be sorted into descending order based
on preference values stored in the real array. Argument 3 indicates how many values to sort.
Remember that FORTRAN passes subroutine arguments by address rather than by value, so that what DSORT does
to reorder the integer array remains valid in the calling routine.
Array element CUMDEG(I) holds the total duration (in sixteenth notes) of all sections
in which degree I has been eliminated up to the current point in the composing process.
Line 82 sorts the current section's chromatic set into a preference order; however, using CUMDEG values
directly for this purpose means that if two degrees share the same CUMDEG value, then the sorting algorithm
will favor the degree with the lower chromatic number. To eliminate such favoritism, each CUMDEG value
receives an increment generated randomly between zero and unity. Lines 77-81 store these adjusted sums in array FUZDEG.
The expression call DSORT(DEGSCD(1,IDX,LEVEL),FUZDEG,NUM) translates into English as follows: sort NUM successive integers
starting with the address of DEGSCD(1,IDX,LEVEL) into descending order based on the preference values stored in array FUZDEG.
We know DSORT will receive the right content by understanding that FORTRAN stores the content of the multidimensional DEGSCD
array as a contiguous block of MDEG×MCNT×MLEV integers, arranged in the following sequence:
DEGSCD(1,1,1)
|
DEGSCD(2,1,1)
|
… |
DEGSCD(MDEG,1,1)
|
|||
DEGSCD(1,2,1)
|
DEGSCD(2,2,1)
|
… |
DEGSCD(MDEG,2,1)
|
|||
| ⋮ | ⋮ | ⋮ | ⋮ | |||
DEGSCD(1,MCNT,1)
|
DEGSCD(2,MCNT,1)
|
… |
DEGSCD(MDEG,MCNT,1)
|
|||
| ⋮ | ⋮ | ⋮ | ⋮ | |||
DEGSCD(1,MCNT,MLEV)
|
DEGSCD(2,MCNT,MLEV)
|
… |
DEGSCD(MDEG,MCNT,MLEV)
|
How subroutine DEDUCE populates chromatic degrees into array DEGSCD for LEVEL+1
depend both upon the recursive level and the mode of division.
Whenever a degree is excluded from a subsection, the corresponding CUMDEG element increases by the subsection's duration.
LEVEL=1 through LEVEL=5, all degrees in the schedule except for the last four are passed
to all subsections. The remaining four degrees are dereferenced into variables IDEG1, IDEG2,
IDEG3, and IDEG4 in reverse1 order of preference.
DEDUCE passes IDEG1 and IDEG2 to the longer subsection while passing
IDEG3 and IDEG4 to the shorter subsection.
DEDUCE passes IDEG1 and IDEG2 to the outer (a) subsections while passing IDEG3 and IDEG4
to the inner (b) subsection. Notice that the combined durations of (a) subsections is consistently at least as
large as the duration of the (b) subsection.
CUMDEG values for IDEG1, IDEG2, IDEG3, and IDEG4
by the durations of the subsections where these degrees were not placed.
DEDUCE dereferences them into variables IDEG1 and IDEG2, in
direct order of preference.
IDEG1 passes down to the longer subsection, while IDEG2 passes down to the shorter subsection.
Lines 126-127 increase the CUMDEG values for IDEG1 and IDEG2 as appropriate.
IDEG1 passes down to the inner (a) subsection, while IDEG2 passes down to the outer (b)
subsection.
Lines 132-134 increase the CUMDEG values for IDEG1 and IDEG2 as appropriate.
As a result of this process, local chromatic distributions are very much non-uniform. However if you sum together the durations for each chromatic degree over the composition as a whole, the sums should be pretty much even.
| © Charles Ames | Original Text: 1984-11-01 | Page created: 2017-03-12 | Last updated: 2017-03-12 |