Music 680, Fall 2005: Special Topics in Music Theory - Algorithmic Composition
Lecture 13: December 5, 2005 - Cage II: later works
artistic process across media
printmaking
I Ching determination of mark types, locations, activities
(examples from www.crownpoint.com)
film
"without regard for illumination" as a byproduct of Europera theatrical lighting experiences
composition
the number pieces: separation of structure and content
(and Europeras as intensifying that separation through borrowed content)
poetry
mesostics and the "writing through" process
"Cage and the Computer"
the computer as an agent of existing processes rather than as an avenue to new techniques
and the possibility of doing projects on an even larger scale than previously
the labor-saving device making time available for new laborious projects
"The Making of Cage's One11"
"Really, the whole piece is a performance for the camera... within the lighting situation." (p. 291)
number pieces in CM
(define (make-proportions number-of-sections)
(if (<= number-of-sections 1)
(list 0)
(cons (random 1.0)
(make-proportions (- number-of-sections 1)))))
(define (sort-proportions proportion-list)
(if (sorted? proportion-list)
proportion-list
(sort-proportions (sort-iteration proportion-list))))
(define (sorted? proportion-list)
(equal? proportion-list (sort-iteration proportion-list)))
(define (sort-iteration proportion-list)
(if (< (length proportion-list) 2)
proportion-list
(if (> (car proportion-list)
(cadr proportion-list))
(cons (cadr proportion-list)
(sort-iteration (cons (car proportion-list)
(cddr proportion-list))))
(cons (car proportion-list)
(sort-iteration (cdr proportion-list))))))
(define (scale-proportions proportion-list start total-duration)
(if proportion-list
(cons (+ (* (car proportion-list) total-duration) start)
(scale-proportions (cdr proportion-list) start total-duration))
(list (+ start total-duration))))
(define (number-voice lowest-pitch highest-pitch time-brackets)
(if (>= (length time-brackets) 2)
(let* ((bracket-start (car time-brackets))
(bracket-end (cadr time-brackets))
(event-start (+ bracket-start
(random (- bracket-end bracket-start))))
(event-duration (random (- bracket-end event-start))))
(cons (new midi
:time event-start
:keynum (+ (random (- highest-pitch lowest-pitch))
lowest-pitch)
:amplitude (random 1.0)
:duration event-duration)
(number-voice lowest-pitch highest-pitch (cdr time-brackets))))))
(define (make-number-voice lowest-pitch highest-pitch events start duration)
(number-voice lowest-pitch
highest-pitch
(scale-proportions
(sort-proportions
(make-proportions events)) start duration)))
; (events (make-number-voice 70 100 15 0 50) "test.mid")
(define (make-number-piece voice-registers events-per-voice start duration)
(if voice-registers
(append (make-number-voice (caar voice-registers)
(cadar voice-registers)
events-per-voice
start
duration)
(make-number-piece (cdr voice-registers) events-per-voice start duration))))
; (events (make-number-piece '((40 70) (50 80) (60 90) (70 100) (80 110)) 15 0 50) "test.mid")
cellular automata in CM
#| ca.scm: code for basic cellular automata
ca are defined as square two-dimensional structures (a list of lists)
both rows and columns are always the same length
rows and columns are indexed from zero to one less than the dimension length
|#
; basic cellular automaton functions
; top-level function for creating a square ca
(define (make-ca size)
(if (> size 0)
(make-ca-helper size size)))
; helper function for creating a square ca - called by (make-ca)
(define (make-ca-helper rows column-size)
(if (> rows 0)
(cons (make-list column-size)
(make-ca-helper (- rows 1) column-size))))
; top-level function for randomly populating a ca with values
(define (populate-ca ca)
(if ca
(cons (populate-dimension (car ca))
(populate-ca (cdr ca)))))
; helper function for randomly populating a ca with values
(define (populate-dimension ca-dimension)
(if ca-dimension
(cons (random-element)
(populate-dimension (cdr ca-dimension)))))
; (random-element): randomly returns 0 or 1 with equal probability
(define (random-element)
(if (> (random 1.0) 0.5)
1 0))
; (get-ca-value): return the value of a particular cell
(define (get-ca-value ca index1 index2)
(list-ref (list-ref ca index1) index2))
; (sum-row): sum the value of a cell and its adjacencies
; accounting for the fact that leftmost/rightmost cells have only one adjacency
; operates on a single row rather than a two-dimensional ca
(define (sum-row ca-row index)
(cond ((= index 0) ; if leftmost element
(+ (list-ref ca-row 0) (list-ref ca-row 1)))
((= index (- (length ca-row) 1)) ; if rightmost element
(+ (list-ref ca-row (- index 1)) (list-ref ca-row index)))
((or (< index 0) (>= index (length ca-row))) ; if out of bounds
0)
(t (+ (list-ref ca-row (- index 1)) ; basic case
(list-ref ca-row index)
(list-ref ca-row (+ index 1))))))
; (sum-neighbors): sum the value of a cell's adjacencies
; operates across two dimensions
; and does not include the value of the indexed cell itself
(define (sum-neighbors ca index1 index2)
(cond ((= index1 0)
(- (+ (sum-row (list-ref ca 0) index2)
(sum-row (list-ref ca 1) index2))
(list-ref (list-ref ca index1) index2)))
((= index1 (- (length ca) 1))
(- (+ (sum-row (list-ref ca (- index1 1)) index2)
(sum-row (list-ref ca index1) index2))
(list-ref (list-ref ca index1) index2)))
((or (< index1 0) (>= index1 (length ca)))
0)
(t (- (+ (sum-row (list-ref ca (- index1 1)) index2)
(sum-row (list-ref ca index1) index2)
(sum-row (list-ref ca (+ index1 1)) index2))
(list-ref (list-ref ca index1) index2)))))
; (step-ca): update the ca to reflect an evolutionary cycle
; active cells with fewer than two or greater than three neighbors are emptied
; empty cells with three neighbors activate
(define (step-ca ca)
(if ca
(step-ca-helper ca (adjacency-count ca 0))))
; (step-helper): helper function for (step-ca)
; traverse existing generation of ca together with sums of adjacencies
; to produce next generation of ca
(define (step-ca-helper ca adjacencies)
(if (and ca adjacencies)
(cons (step-row (car ca) (car adjacencies))
(step-ca-helper (cdr ca) (cdr adjacencies)))))
; (step-row): calculate evolutionary cycle on a single row
(define (step-row ca-row adjacency-row)
(cond ((or (null? ca-row) (null? adjacency-row)) ; if row is empty return nil
nil)
((and (= (car ca-row) 1) ; if cell is active
(or (< (car adjacency-row) 2) ; but adjacencies are out of range
(> (car adjacency-row) 3)))
(cons 0 (step-row (cdr ca-row) (cdr adjacency-row)))) ; return 0
((= (car ca-row) 1) ; otherwise if cell is active it remains active
(cons 1 (step-row (cdr ca-row) (cdr adjacency-row))))
((and (= (car ca-row) 0) ; if cell is ampty
(= (car adjacency-row) 3)) ; and adjacencies are 3
(cons 1 (step-row (cdr ca-row) (cdr adjacency-row)))) ; activate cell
(t (cons 0 (step-row (cdr ca-row) (cdr adjacency-row)))))) ; still empty
; (adjacency-count): calculate adjacencies for the complete ca
(define (adjacency-count ca index)
(if (< index (length ca))
(cons (adjacency-count-row ca index 0)
(adjacency-count ca (+ index 1)))))
; (adjacency-count-row): calculate adjacencies row by row
(define (adjacency-count-row ca index1 index2)
(if (< index2 (length ca))
(cons (sum-neighbors ca index1 index2)
(adjacency-count-row ca index1 (+ index2 1)))))
; music functions
(define (generate-pitches dimension-length)
(if (> dimension-length 0)
(cons (+ (random 70) 30)
(generate-pitches (- dimension-length 1)))))
(define (generate-rhythms dimension-length)
(if (> dimension-length 0)
(cons (+ (random 1.1) 0.1)
(generate-rhythms (- dimension-length 1)))))
(define (generate-dynamics dimension-length)
(if (> dimension-length 0)
(cons (+ (random 0.8) 0.2)
(generate-dynamics (- dimension-length 1)))))
(define (make-ca-chord ca-row pitches start length dynamic)
(cond ((or (null? pitches) (null? ca-row))
nil)
((= (car ca-row) 0)
(make-ca-chord (cdr ca-row) (cdr pitches) start length dynamic))
(t (cons (new midi
:time start
:duration length
:amplitude dynamic
:keynum (car pitches))
(make-ca-chord (cdr ca-row) (cdr pitches) start length dynamic)))))
(define (make-ca-phrase ca pitches durations dynamics start)
(if (and ca pitches durations dynamics)
(append (make-ca-chord (car ca) pitches start (car durations) (car dynamics))
(make-ca-phrase (cdr ca) pitches (cdr durations) (cdr dynamics)
(+ start (car durations))))))
; (ca-music) top-level function
; sonifies the generations of a ca using fixed set of pitches, rhythms, dynamics
; pitches of fixed chord are switched on and off according to cell contents
; rhythms and durations repeated with each iteration
(define (ca-music dimension-length iterations start)
(ca-music-helper (populate-ca (make-ca dimension-length))
iterations
(generate-pitches dimension-length)
(generate-rhythms dimension-length)
(generate-dynamics dimension-length)
start))
; (events (ca-music 5 10 0) "test.mid")
(define (sum-list input-list)
(if input-list
(+ (car input-list)
(sum-list (cdr input-list)))
0))
(define (ca-music-helper ca iterations pitches durations dynamics start)
(if (> iterations 0)
(append (make-ca-phrase ca pitches durations dynamics start)
(ca-music-helper (step-ca ca)
(- iterations 1)
pitches durations dynamics
(+ start (sum-list durations))))))
; (ca-music-2): same as (ca-music) but with a new chord for each iteration
; also creates a little rhythmic space between each iteration
(define (ca-music-2 dimension-length iterations start)
(ca-music-helper-2 (populate-ca (make-ca dimension-length))
iterations
(generate-rhythms dimension-length)
(generate-dynamics dimension-length)
start))
(define (ca-music-helper-2 ca iterations durations dynamics start)
(if (> iterations 0)
(append (make-ca-phrase ca (generate-pitches (length ca)) durations dynamics start)
(ca-music-helper-2 (step-ca ca)
(- iterations 1)
durations
dynamics
(+ start (* (sum-list durations) 1.1))))))
; (events (ca-music-2 7 15 0) "test.mid")