Audacity Support Forum /
Audacity and Nyquist /
Nyquist Reference Manual /
Nyquist Examples and Tutorials
Cellular Automata & Nyquist /
Cellular Automata Example /
View example: cell-aut.lsp
Sound example: cell-aut-demo.ogg
;; cell_aut.lsp -- cellular automata for sound generation
;; originally by Ann Lewis
;; revised by Roger B. Dannenberg
;; March 2004
;; compute-update-rule -- compute the output given a rule and 3 inputs
;;
(defun compute-update-rule (rule a b c)
;; this is the most interesting part of the whole program
;; the rule has 8 bits. Use a, b, c to index the rule bits
;; and determine the result. To do this, we want a bit in
;; the right position, e.g. if a=0,b=1,c=1, then the index
;; is 011 = 3, and we want a bit pattern with "1" in position 3:
;; 00001000. Note that this is 2^3 = a*2^4 + b*2^2 + c*2^1. So
;; we can test a, b, and c and multiply by 16, 4, and 2 to get
;; the right bit pattern. Then we can "and" it with rule to
;; get either zero or a non-zero as the result.
(let ((abc 1))
(cond (a (setf abc 16)))
(cond (b (setf abc (* abc 4))))
(cond (c (setf abc (* abc 2))))
(setf rule (logand rule abc))
(> rule 0)))
;; the main cellular automata implementation
(defun cell-aut (sound-object-list duration update-rule iter)
(let (prev current array-len score (now 0.0) tmp)
; create and initialize current and prev bit lists
(setf array-len (length sound-object-list))
(setf prev (make-array array-len))
(setf current (make-array array-len))
(setf prev (make-array array-len))
(setf (aref prev (/ array-len 2)) t)
; create the score by computing iter generations of the automata
(dotimes (i iter)
(dotimes (j array-len)
(princ (if (aref prev j) " X" " 0"))
; push a note on the list for each "true" in the prev array
(if (aref prev j)
(push (list now duration (nth j sound-object-list)) score)))
(terpri)
; compute current from prev using update-rule
; first do endpoints, wrap-around style
(setf (aref current 0)
(compute-update-rule update-rule
(aref prev (- array-len 1)) (aref prev 0) (aref prev 1)))
(setf (aref current (- array-len 1))
(compute-update-rule update-rule
(aref prev (- array-len 2)) (aref prev (- array-len 1))
(aref prev 0)))
; then loop through everything else
; want to cycle from 1 to array-len-2
(dotimes (j (- array-len 2))
(setf (aref current (+ j 1))
(compute-update-rule update-rule
(aref prev j) (aref prev (+ j 1)) (aref prev (+ j 2))))
)
; set prev to current
(setf tmp prev)
(setf prev current)
(setf current tmp)
; increment the time
(setf now (+ now duration)))
;; the score is now in reverse order, so fix it
(setf score (reverse score))
;; now we have a score, render it to sound and return it:
(timed-seq score))
)
(defun cell-aut-major-scale ()
;; for testing, this creates an 8-note scale
;; requires (load "pianosyn") to get the piano library
(let (scale offsets)
(setf offsets '(0 2 4 5 7 9 11 12))
(dolist (p offsets)
(push (list 'piano-note-2 (+ A3 p) 100) scale))
(reverse scale)))
(defun cell-aut-demo ()
(play (scale 0.5 (cell-aut (cell-aut-major-scale) 0.2 30 80))))
Cellular Automata & Nyquist /
Cellular Automata Example /
View example: cell-aut.lsp
Audacity Support Forum /
Audacity and Nyquist /
Nyquist Reference Manual /
Nyquist Examples and Tutorials