Music 220b: Winter 2001
Fernando Lopez-Lezcano, instructor
Christopher Burns, teaching assistant
Tamara Smyth, teaching assistant
Week 3: random values in composition
Some discourse on the use of random values as part of an algorithmic composition....
There are a variety of reasons why we might introduce random- or chance-determined elements into our compositions. John Cage used chance techniques as a way of exploring domains outside of his own intentions and taste; Iannis Xenakis uses random values as a way of specifying the innumerable small details of the swarms of sound which characterize many of his compositions. These two composers use randomness to very different aesthetic ends. (Both of these goals may be related to computer music, however: many see the field as an opportunity for the exploration of new compositional ideas, and most experienced composers are looking for some way to deal with "data explosions"!)
In both Cage and Xenakis' case, we may find the compositional act in the constraint of randomness. Even if a composition were to be "totally chance-determined," the composer would have to specify how the random values were produced, and how they were mapped. And in practice, total randomness isn't really that interesting. Imagine a soundfile where every sample is determined randomly. For a perfectly random distribution (which Lisp's (random) function aspires to), that's white noise....
The challenge, then, is to create meaningful or interesting constraints on randomness, and to evolve those constraints through time. For instance....
Changing the range of a randomized parameter over time:
(loop for lower-limit from 0 to 100 by 10 ; increase lower limit to 100 for upper-limit from 210 by -10 ; decrease upper limit to 110 collect (+ lower-limit (random (- upper-limit lower-limit)))) ; "zeroing in" on the 100-110 range
Brownian motion:
(let* ((random-value 0)) (loop repeat 20 collect (incf random-value (- (random 10) 2)))) ; value should "wobble", but rise more often than fall
Each value is calculated starting from the position of the last value. (Xenakis has used this technique on occasion). Note that (incf variable value) is equivalent to (setf variable (+ variable value)). Here's an example in which Brownian motion takes place with changing "velocity":
(let* ((random-value 0)) (loop for lower-limit from -10 to 10 ; transition from mostly decreasing... for upper-limit from 0 ; ...to mostly increasing... collect (incf random-value (+ lower-limit (random (- upper-limit lower-limit))))))
Imagine also an situation in which a value was "reflected" off an absolute upper or lower limit....
Reading at random from a table of values:
(loop repeat 20 collect (nth (random 4) '(0.1 0.2 0.15 7)))
Reading values from a table offers the possibility of using many different statistical or idiosyncratic distributions of elements. For example, if we mapped the list above to durations, we'd get short durations about 75% of the time, with a very long duration for the remainder.
Better still, we can change from one kind of distribution to another:
(let* ((element-list '(10 20 30 40 50))) (loop repeat 25 do (setf random-index (random 5)) (setf current-value (nth random-index element-list)) (setf (nth random-index element-list) random-index) ; changing to a random distribution of the elements 1-5 (format t "~d " current-value)))
Or we can use a Common Music (pattern) to read values out of a table without using them twice:
(let* ((test-pattern (new pattern 1 2 3 4 5 in heap))) (loop repeat 5 collect (next test-pattern)))
John Cage's working methods often included tables of values which would then be selected (and perhaps altered) by a random process. In this type of situation, the nature of the constraint depends upon what you put in the table....
There are endless possibilities; the key is to think about how the random values are mapped to musical parameters, and how those values (and the music they constitute) change through time....