3.2. Steve Reich: Piano Phase
(in-package :cm) (ql:quickload "cm-utils") ;;; STEVE REICH - PIANO PHASE ;;; Töne (defparameter *pattern* '(60 62 67 69 70 62 60 69 67 62 70 69)) ;;; Partitur für den Rhythmusstream der beiden Pianos: Jedes Element ;;; der Partitur entspricht einer Phrase. Eine Phrase wird durch eine ;;; Liste mit zwei Zahlen definiert. Die erste Zahl gibt die Anzahl ;;; der Wiederholungen eines Patterns an, die zweite Zahl gibt den ;;; offset an, um den das Pattern nach der Anzahl der Wiederholungen ;;; verschoben sein soll. Mit anderen Worten sind die Rhythmen so ;;; berechnet, dass nach der Anzahl der Wiederholungen im ;;; Originaltempo die Notenverschiebung erreicht wird, die die zweite ;;; Zahl angibt. (defparameter *score-pno1* '((12 0))) (defparameter *score-pno2* '((12 0) (12 1))) (defparameter *playing* t) ;;;; Verschachtelte Patterns: (defun mache-rhythmus-phrasen-stream (eventstream patternlaenge dauer-einer-ganzen) (new thunk :of (lambda () (let ((ne (next eventstream))) (destructuring-bind (anzahl-perioden verschiebung) ne (next (new cycle :of (* (/ (* anzahl-perioden patternlaenge) (+ verschiebung (* anzahl-perioden patternlaenge))) (* 1/16 dauer-einer-ganzen)) :for (+ verschiebung (* anzahl-perioden patternlaenge))) t)))))) #| (loop with rstr = (mache-rhythmus-phrasen-stream (new cycle :of '((4 0) (4 1))) 3 1) for count below 2 collect (next rstr t)) ;;; -> ((1/16 1/16 1/16 1/16 1/16 1/16 1/16 1/16 1/16 1/16 1/16 1/16) ;;; (3/52 3/52 3/52 3/52 3/52 3/52 3/52 3/52 3/52 3/52 3/52 3/52 3/52)) |# (defun play-pno (score pat tempo channel) (let* ((dauer-einer-ganzen (/ 60 (apply #'* tempo))) (events (new cycle :of score)) (pattern (new cycle :of pat)) (patternlaenge (length pat)) (rhythmen (mache-rhythmus-phrasen-stream events patternlaenge dauer-einer-ganzen))) (process while *playing* for rhythmus = (next rhythmen) for keynum = (next pattern) output (new midi :keynum keynum :duration rhythmus :channel channel) wait rhythmus))) ;;; Aufruf für piano phase: (let ((tempo '(1/4 120))) (setf *playing* t) (sprout (play-pno *score-pno1* *pattern* tempo 0)) (sprout (play-pno *score-pno2* *pattern* tempo 1))) ;;; stoppen: (setf *playing* nil) ;;; -------------------------------------------------- #| ;;; in einer Funktion zusammengefasst: (defun play-pno (score pat tempo channel) (let* ((time-per-whole (/ 60 (apply #'* tempo))) (events (new cycle :of score)) (pattern (new cycle :of pat)) (period (length pat)) (rhythms (new thunk :of (lambda () (let ((ne (next events))) (destructuring-bind (num-periods offset) ne (next (new cycle :of (* (/ (* num-periods period) (+ offset (* num-periods period))) (* 1/16 time-per-whole)) :for (+ offset (* num-periods period))) t))))))) (process while *playing* for rhythm = (next rhythms) output (new midi :keynum (next pattern) :duration rhythm :channel channel) wait rhythm))) ;;; Aufruf für piano phase: (let ((tempo '(1/4 120))) (setf *playing* t) (sprout (play-pno *score-pno1* *pattern* tempo 0)) (sprout (play-pno *score-pno2* *pattern* tempo 1))) ;;; stoppen: (setf *playing* nil) | #