;; Matt Wright ;; Music 220B Assignment #2: "Modulation Song" controlled by Cellular Automata ;; Thanks to Rego for suggesting stereo (defun ms-stereo (iterations bar-length on-on on-off) (with-sound (:channels 2 :decay-time 4.0) (let ((left-cells (make-cells bar-length)) (right-cells (make-cells bar-length)) (bar-pitch 20)) (loop repeat iterations for bar-time from 0 by (* on-on bar-length) do (setq bar-pitch (+ bar-pitch 1 (random 3))) (format t "left:") (print-cells left-cells) (format t "right:") (print-cells right-cells) (fm-violin bar-time (* 0.5 bar-length on-on) (hertz bar-pitch) 0.4 :amp-env '(0 0 1 1 10 0.5 100 0)) (play-cells left-cells bar-length bar-pitch bar-time on-on on-off 0) (play-cells right-cells bar-length bar-pitch bar-time on-on on-off 90) (setf left-cells (step-cells left-cells)) (setf right-cells (step-cells right-cells)) )))) (defun play-cells (cells bar-length bar-pitch bar-time on-on on-off degree) (loop for cell across cells for time from bar-time by on-on for note-in-bar from 1 by 1 for proportion from 0 by (/ 1 bar-length) do (if (= cell 1) (fm-violin time on-off (* (hertz bar-pitch) note-in-bar) 0.2 :fm1-index (+ 1 (* 1 proportion)) :degree degree )))) ;; Original mono version: (defun ms-mono (iterations bar on-on on-off) (with-sound (:decay-time 1.0) (let* ((cells (make-cells bar)) (bar-length (length cells)) (bar-pitch 20)) (loop repeat iterations for bar-time from 0 by (* on-on bar-length) do (setq bar-pitch (+ bar-pitch 1 (random 3))) (print-cells cells) (fm-violin bar-time (* 0.5 bar-length on-on) (hertz bar-pitch) 0.4 :amp-env '(0 0 1 1 10 0.5 100 0)) (loop for cell across cells for time from bar-time by on-on for note-in-bar from 1 by 1 for proportion from 0 by (/ 1 bar-length) do (if (= cell 1) (fm-violin time on-off (* (hertz bar-pitch) note-in-bar) 0.2 :fm1-index (+ 1 (* 1 proportion))))) (setf cells (step-cells cells)))))) ;; Cellular automata stuff from fabric.lisp: (defun make-cells (arg) (let* ((size (if (listp arg) (length arg) arg))) (make-array size :initial-contents (if (listp arg) arg (loop repeat size collect (if (< (random 1.0) 0.5) 0 1)))))) ;;; Create the next generation of cells (defun step-cells (cells) ;; cells is a one dimensional array, elements contain either ;; a zero (the cell is dead) or one (the cell is alive) (let* ((size (length cells)) (next (make-array size :initial-element 0))) (loop for i from 0 below size do (let* ((neighbors (list (aref cells i) (aref cells (mod (+ i 1) size)) (aref cells (mod (+ i 2) size))))) ;; set the guy in the middle to be born, hang on or die ;; this implements the rule set of this automata (setf (aref next (mod (+ i 1) size)) (cond ((equal neighbors '(0 0 0)) 0) ((equal neighbors '(0 0 1)) 1) ((equal neighbors '(0 1 0)) 1) ((equal neighbors '(0 1 1)) 0) ((equal neighbors '(1 0 0)) 1) ((equal neighbors '(1 0 1)) 1) ((equal neighbors '(1 1 0)) 0) ((equal neighbors '(1 1 1)) 0) ;; we should never get here... (t nil))))) ;; return the next generation next)) ;;; return number of critters that are alive on the current generation ;;; can be used to control parameters... (defun population (cells) (loop for cell across cells sum cell)) (defun print-cells (cells) (loop for cell across cells do (format t "~a" (if (= cell 1) "*" " "))) (format t "~%")) #| ; Here are some settings I like: (ms-stereo 15 7 0.1 0.09) (ms-stereo 15 7 0.05 0.2) (ms-stereo 4 20 0.2 0.2) |#