(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)
| #