Algorithmic Composition: A Gentle Introduction to Music Composition Using Common LISP and Common Music
Skip other details (including permanent urls, DOI, citation information) :This work is protected by copyright and may be linked to without seeking permission. Permission must be received for subsequent distribution in print or electronically. Please contact : [email protected] for more information.
For more information, read Michigan Publishing's access and usage policy.
Chapter 11: Arrays
11.1 Introduction to Arrays
An array is a data type that stores information in indexed locations. Arrays may store data in multiple dimensions. Table 11.11.1 graphically represents a one-dimensional array named *MY-MIDI-NOTES*.
Table 11.1.1:*MY-MIDI-NOTES*:
Index 0 | Index 1 | Index 2 | Index 3 |
60 | 62 | 67 | 69 |
The *MY-MIDI-NOTES* array has 4 locations identified as Index 0, Index 1, Index 2, and Index 3. The value of the data stored at Index 0 is 60, the value of the data stored at Index 1 is 62, etc.
Table 11.1.2 graphically represents a two-dimensional array named *MY-MIDI-NOTES-WITH-RHYTHMS*:
Example 11.1.2:*MY-MIDI-NOTES-WITH-RHYTHMS*
Column 0 | Column 1 | Column 2 | Column 3 | |
Row 0 | 60 | 62 | 67 | 69 |
Row 1 | 's | 'e | 's | 's. |
Row 2 | 's. | 's. | 'e | 'e. |
The *MY-MIDI-NOTES-WITH-RHYTHMS* array has 4 columns identified as Column 0 through Column 3. The array also has 3 rows identified as Row 0 through Row 2. Data in two-dimensional arrays are indexed by row and column. For example, the value of the data at row 0, column 2 is 67.
Recall from Chapter 4 that Common Music uses the following symbols to represent relative rhythms:
The symbols representing relative rhythms in the array *MY-MIDI-NOTES-WITH-RHYTHMS* are quoted so that the symbols evaluate to themselves.
The MY-MIDI-NOTES-WITH-RHYTHMS array associates MIDI key numbers with particular rhythms because of the organization of data in the array. There is an association between MIDI note number 60 and the rhythm of a sixteenth (s) and dotted sixteenth (s.) note because the data occupies Column 0.
11.2 Constructing Arrays
The Common LISP function MAKE-ARRAY is used to construct arrays.
Note the use of the colon for an optional keyword. The optional keyword :initial-contents followed by a value may be used to initialize an array, that is, assign all of its locations the same value. The optional keyword :initial-contents followed by value(s) may be used to assign the locations of the array when the array is created.
In Example 11.2.1, we create a one-dimensional array with 4 locations at the Common LISP ? prompt.
In Example 11.2.2, we create a one-dimensional array with 4 locations and each location is initialized to 0.
In Example 11.2.3, we create a one-dimensional array with 4 locations where the locations are assigned initial values of 60, 62, 67 and 69.
In Example 11.2.4, we assign the global variable *MY-MIDI-NOTES* to be a one-dimensional array with elements 60, 62, 67, and 69.
A two-dimensional array may be created by using a quoted list as the size of the array. In Example 11.2.6, we create a two-dimensional array that has three rows and four columns.
We extend example 11.2.5 in Example 11.2.6 by creating a two-dimensional array with three rows and four columns where each location of the array is initialized to 0.
Just as with one-dimensional arrays, two-dimensional arrays may be assigned their initial contents when they are created.
Example 11.2.7
The *MY-MIDI-NOTES-WITH-RHYTHMS* represented Table 11.1.2 array can be assigned using SETF as shown in Example 11.2.9.
Example 11.2.8
The array may also be assigned to a variable using LET as shown in Example 11.2.9.
Example 11.2.9
11.3 Referencing Values in an Array
The Common LISP function AREF is used to reference the values stored in an array.
Recall in Example 11.2.4 when we assigned the variable *MY-MIDI-NOTES* to a one-dimensional array with elements 60, 62, 67, and 69. Example 11.3.1 demonstrates how we can query the value of the second location of the array named *MY-MIDI-NOTES*.
Recall that in Example 11.2.8 we assigned the variable *MY-MIDI-NOTES-WITH-RHYTHMS* to be a two dimensional array of midi-note numbers and symbolic rhythms.AREF may be used with two-dimensional arrays. In Example 11.3.2, we query the value stored in the *MY-MIDI-NOTES-WITH-RHYTHMS* array row 2, column 3.
11.4 Using Arrays in Common Music
Arrays are quite useful in algorithmic composition as they give a new way to organize and access musical data. For example, let's create the MY-MIDI-NOTES-WITH-RHYTHMS array and randomly access the data stored in the array using Common Music. For each randomly-selected note, we randomly select a rhythm from the rhythms stored in the same column as the selected note. For example, if MIDI note number 60 is selected, randomly select either a sixteenth or dotted sixteenth note. Example 11.4.1 shows the Common Music implementation of this algorithm.
A generator named array is created that contains midi-notes. The generator is initialized to have ten note events occurring on MIDI channel 0. Each note event will have an amplitude of .5 and a duration of .2 seconds. Within the generator, we enter the Common Music vars declaration that creates and assigns the array my-midi-notes-with-rhythms. It is necessary to use vars because we want to assign the array contents once when the generator is mixed. After vars, we enter a LET that assigns values to the variables ROW and COLUMN. A LET is necessary because we want the values of ROW and COLUMN to change for each note and rhythm slot assignment.(RANDOM 2) returns either a 0 or 1. By adding 1 to the result, ROW is assigned a value of 1 or 2. Row values of 1 or 2 allow us to access the rhythmic data stored in the array.(RANDOM 4) returns an integer between 0 and 3 that allows us to access the note data stored in the array. Within the body of the LET, we assign the note and rhythm slots. The note slot is assigned using AREF to reference ROW 0 and the COLUMN previously assigned. The rhythm slot is assigned using AREF to reference the randomly-selected row for the same column as the selected note data. The Common Music function rhythm is used to convert a symbolic rhythm to absolute time based on the value of *standard-tempo*.
Example 11.4.2 defines a Common LISP function that implements a linear probability distribution that may be used to reference array locations. The user-defined function CHOOSE-LARGER is created with one argument corresponding to the size of an one-dimensional array. We enter a LET that randomly assigns the variables X and Y based on the size of the array. The values of X and Y are compared and the larger of the two randomly-generated values is returned. Since this function is biased toward larger numbers, repeated calls to CHOOSE-LARGER result in a preference for larger numbers over smaller numbers.
Example 11.4.2: choose-larger.lisp
In Example 11.4.3, the more-arrays generator contains midi-notes and is initialized with a start time of 0 and an end time of 10 seconds. Each midi-note is initialized a duration of .23 and outputs data on MIDI channel 0.vars assigns the ARRAY-NOTE, ARRAY-RHYTHM, and ARRAY-AMPLITUDE one-dimensional arrays. The rhythm slot is assigned by calling CHOOSE-LARGER which implements a linear-distribution in the selection of the array index to array-rhythm. The amplitude slot is assigned in a manner similar to the rhythm slot. A LET randomly assigns the variable OCTAVE a value of either 0 or 1. Within the body of the LET, CHOOSE-LARGER is called again to determine the index of ARRAY-NOTE. The value stored in the selected location is summed with either 0 (* 11 OCTAVE when OCTAVE equals 0) or 11 (* 11 OCTAVE when OCTAVE equals 1) resulting in random assignment of the octave within a two-octave range.
Example 11.4.3: more-arrays.lisp
11.5 Suggested Listening
Emma Speaks by Mary Simoni and Jason Marchant explores the application of Augmented Transition Networks to the development of form in choreography and multimedia. A dance was captured on video and edited such that the video post processing introduced another layer of choreography. Music was composed for the edited video using Common Music (refer to example on accompanying compact disk). [Simoni & Marchant, 1998]