(in-package :CM) (cd "/home/t/tmp/") ;; Main purpose of the examples here is to demonstrate Common Music ;; programming means, there are not necessarily important compositions ;; ;-) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Nested patterns and Envelopes ;;; ;; A particular strength of Common Music patterns is that patterns can ;; be arbitrarily nested. ;; knum-pattern is a nested pattern, consisting of a heap of cycles (defun nested-pattern (n) (let ((knum-pattern (new heap :of (list (new cycle :of '(48 49 50 51)) (new cycle :of '(55 54 53 52)) (new cycle :of '(56 57 58 59))))) (dur-pattern (new cycle :of '(0.1 0.3 0.2 0.3)))) (process repeat n for dur = (next dur-pattern) output (new midi :time (now) :duration dur :keynum (next knum-pattern)) wait dur))) (events (nested-pattern 16) "nested-pattern.midi") ;; In this example knum-pattern is again nested (a cycle containing a ;; heap). Additionally, the length of the inner pattern is controlled ;; by the keyword :for. The duration and the amplitude are controlled ;; by envelopes. (defun nested-pattern2 (n) (let ((knum-pattern (new cycle :of (list 48 (new heap :of '(64 65 67 69 71 72) ;; the length of a subpattern can ;; be controlled by a pattern :for (new range :from 1 to 10)))))) (process for i from 1 to n ;; interpl reads a values from an envelope, specified as ;; a list of the form (x1 y1 ... xn yn) for dur = (interpl i (list 1 0.5 n 0.01) :base 0.1) for amp = (interpl i (list 1 0.1 n 1) :base 3) output (new midi :time (now) :duration dur :keynum (next knum-pattern) :amplitude amp) wait dur))) (events (nested-pattern2 200) "nested-pattern2.midi") ;; The next example is a variation of the proceeding example: the duration and the amplitude of the notes is adjusted, depending to the pitch. All notes of the lowest pitch (keynum 48) are louder and of longer duration. (defun conditional (n) (let ((knum-pattern (new cycle :of (list 48 (new heap :of '(64 65 67 69 71 72) ;; the length of a subpattern can ;; be controlled by a pattern :for (new range :from 1 to 10)))))) (process for i from 1 to n ;; interpl reads a values from an envelope, specified as ;; a list of the form (x1 y1 ... xn yn) for dur = (interpl i (list 1 0.5 n 0.01) :base 0.1) for amp = (interpl i (list 1 0.1 n 0.7) :base 3) for keynum = (next knum-pattern) output (new midi :time (now) :duration (if (= keynum 48) (* dur 3) (* dur 0.3)) :keynum keynum :amplitude (if (and (= keynum 48) (< amp 0.5)) (* amp 2) amp)) wait dur))) (events (conditional 200) "conditional.midi") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Spouting Patterns and Recursive Processes ;;; ;; A process definition, as we saw many meanwhile (defun innerProcess (n dur transposition) (let ((keynums (new palindrome :of '(67 65 64 62 60)))) (process repeat n output (new midi :time (now) :duration dur :keynum (+ (next keynums) transposition)) wait dur))) ;; A process definition which calls another process using the sprout ;; process-keyword. The process innerProcess is sprouted whenever ;; outerProcess generates a note. outerProcess generates the arguments ;; for innerProcess as well. (defun outerProcess (n dur) (let ((keynums (new palindrome :of '(60 62 64 65 67)))) (process for i from 1 to n for keynum = (next keynums) output (new midi :time (now) :duration dur :keynum keynum) sprout (innerProcess i (/ dur i) (- 12 i)) wait dur))) (events (outerProcess 11 1) "nestedProcesses.midi") ;; The process sierpinski sprouts itself, i.e. the process calls ;; itself recursively. To avoid an infinite loop the process limits ;; the number of recursive calls to a depth, given as an argument. For ;; each recursive call, the depth is reduced. A subprocess is only ;; sprouted if depth exceeds 1. (defun sierpinski (keynum ints dur amp depth) (process for i in ints for len = (length ints) for k = (+ keynum i) output (new midi :time (now) :duration dur :amplitude amp :keynum k) ;; conditional call (after process keyword sprout) when (> depth 1) ;; recursive call with changed args sprout (sierpinski (+ k 12) ints (/ dur len) amp (1- depth)) wait dur)) (events (sierpinski 21 '(0 7 5) 3 .5 4) "sierpinski.midi") ;; listen to sierpinski with a different depth: (events (sierpinski 21 '(0 7 5) 3 .5 1) "sierpinski.midi") (events (sierpinski 21 '(0 7 5) 3 .5 2) "sierpinski.midi") (events (sierpinski 21 '(0 7 5) 3 .5 8) "sierpinski.midi") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; outputting sierpinski to csound ;;; ;; see last week (defobject i1 (i) (amp freq (pan :initform 0.5)) ;; class i of CM-2.3.4 defines slot 'duration', CM-2.4.0 defines slot 'dur'? (:parameters time duration amp freq pan)) ;; just replace (new midi ...) (defun sierpinski (keynum ints dur amp depth) (process for i in ints for len = (length ints) for k = (+ keynum i) output (new i1 :time (float (now)) ; ensure we don't get ratios :duration (float dur) :amp (float amp) :freq (hertz k) ; transform keynumber to frequency :pan (between 0.0 1.0)) ; random number in given range when (> depth 1) ;; recursive call with changed args sprout (sierpinski (+ k 12) ints (/ dur len) amp (1- depth)) wait dur)) (events (sierpinski 21 '(0 7 5) 3 .5 4) "sierpinski.sco" :header "f1 0 1024 10 1")