20 Patterns and Composition

Example 20-1. Pattern creation using the new macro.

(new cycle :of '(a b c))

(new heap :keynums '(c4 b d5 ef3) :for 20
     :name 'gesture1)

(new heap
     :of (list (new cycle :of 'q :for 3)
               (new palindrome :of '(e. s e))
               (new random :of '(h w h.) :for 1)))

Interaction 20-1. Creating and reading patterns.

cm> (define p (new cycle :of '(a b c)))

cm> (next p)
cm> (next p)
cm> (next p)
cm> (next p #t)
(a b c)
cm> (next p 7)
(a b c a b c a)
cm> (next p #t)
(b c)

Example 20-2. Alberti figures implemented as patterns.

(new cycle :notes '(c3 e g e) :name 'm1)

(new cycle :notes '(d3 f g f) :name 'm2)

Example 20-3. Alberti figures used in a short Alberti bass line.

(new cycle :name 'bass-line
     :of (list #&m1 #&m1 #&m2 #&m2
               #&m1 #&m2 'c3))

Example 20-4. Frequency and rhythm joined together.

(new cycle
  :of (list (new join :name 'j1
                 :of (list #&m1
                           (new cycle :of '(te ts te ts))))
            (new join :name 'j2 :of (list #&m2 's))
            #&j2 #&j1 #&j2 '(c3 h)))

Example 20-5. Three dimensional motives with random variation.

(new cycle 
  :of (list (new join 
              :of (list (new cycle :of '(ef5 e4 r))
                        (new cycle :of '(s s q) )
            (new join
              :of (list (new heap :of '(g4 fs4 fn5 b5))
                        (new cycle 
                          :of (list (new heap :of '(e q e))
            (new join 
              :of (list (new cycle :of '(af5 f5 a4 cs4 c5))
                        (new heap :of '(e s q) :for 5)
                        (new cycle :of '(pp p mp mf f))))))

Example 20-6. Cycles of random permutation.

(new cycle
  :of (list (new heap :notes '(c3 cs d ef))
            (new heap :notes '(e3 f fs g))
            (new heap :notes '(gs3 a as b))))

Example 20-7. Randomly permuted cycles.

(new heap
  :of (list (new cycle :notes '(c3 cs d ef))
            (new cycle :notes '(e3 f fs g))
            (new cycle :notes '(gs3 a as b))))

Example 20-8. Randomized Alberti figures.

(new cycle
  :of (list (new heap :notes '(c3 cs d ef) :for 1)
            (new heap :notes '(e3 f fs g) :for 1 :name 'm)
            (new heap :notes '(gs3 a as b) :for 1)

Interaction 20-2. Referencing the last value a pattern produced.

cm> (define p (new cycle :of '(a b c)))

cm> (pattern-value p)
cm> (next p)
cm> (pattern-value p)

Example 20-9. Using pval to delay the evaluation of an expression.

(new cycle
  :of (list (new heap :notes '(c3 cs d ef) :for 1)
            (new heap :notes '(e3 f fs g) :for 1 :name 'm)
            (new heap :notes '(gs3 a as b) :for 1)
            (pval (pattern-value #&m))))

Example 20-10. Using a copier to repeat pattern periods.

(new copier 
  (new cycle
    :of (list (new heap :notes '(c3 cs d ef) :for 1)
              (new heap :notes '(e3 f fs g) :for 1 :name 'm)
              (new heap :notes '(gs3 a as b) :for 1)
              (pval (pattern-value #&m))))
  :for (new heap :of '(2 3 5)))

Example 20-11. Subpatterns with zero period length are skipped over.

(new cycle :of `(c4
                 ,(new cycle :of 'ef4
                       :for (new cycle :of '(1 2)))
                 ,(new cycle :of 'b4
                       :for (new cycle :of '(3 2 0)))

Example 20-12. Process from Chapter 14 converted to use a pattern.

(define (piano1 trope amp chan)
  (let* ((cycl (new cycle :keynums trope
                    :repeat (length trope)))
         (rate (rhythm->seconds pp-pulse pp-tempo)))
    (process for k = (next cycl)
             until (eod? k)
             output (new midi :time (now)
                         :keynum k
                         :duration (* rate 1.5)
                         :amplitude amp
                         :channel chan)
             wait rate)))

Example 20-13. Using pattern states to control a process.

(define (play-pat reps rate dur amp )
  (let ((pat (new heap 
               :notes '(c4 d ef f g af bf c5)
               :for (new random :of '(8 12 16))
               :repeat reps))
        (x 0)
        (r #t ))
    (process for k = (next pat)
             until (eod? k)
             for p = (pattern-period-length pat)
             if r set x = 0
             (new midi :time (now)
                  :keynum k 
                  :amplitude (interp x 0 .4 (- p 1) amp)
                  :duration dur)
             wait rate
             set r = (eop? pat)
             set x = (+ x 1))))

Interaction 20-3. Listening to a pattern.

cm> (events (play-pat 10 .1 .3 .8) "pat-10.mid")

Example 20-14. Sharing pattern values between processes.

(define (two-hands end tempo)
  (let ((the-note #f))  ; shared pattern value
     ;; master process creates the bass-line and sets
     ;; the shared variable.
     (let ((bass (new random
                   :keynums '(e1 f g a b c2 d)))
           (rhys (new random :of '( h.. h e))))
       (process while (< (now) end)
                for k = (next bass)
                for r = (rhythm (next rhys) tempo)
                set the-note = k
                output (new midi :time (now)
                            :keynum k :duration r
                            :amplitude .8)
                wait r))
     ;; slave procees adds random harmony two
     ;; octaves above the-note
     (let ((rhys (new random :of '((q :max 3) (e :max 2)
                                   (s :max 1) 
                                   (t :weight .5 :max 1))))
           (harm (new heap :of '((0 3 7 8) (1 5 8 10)
                                 (0 3 7 10) (1 5 8 12)
                                 (1 3 7 10) (3 5 8 12)
                                 (1 5 7 10)))))
       (process while (< (now) end)
                for c = (transpose (next harm) 
                                   (+ the-note 24))
                for r = (rhythm (next rhys) tempo)
                each k in c
                output (new midi :time (now)
                            :keynum k :duration (* r 2)
                            :amplitude .4)
                wait r)))))

Example 20-15. A palindrome with subpattern.

(new palindrome
  :notes `(, (new heap :notes '(c4 b3 bf a af g) :for 1)
             d4 ef f gf)
  :elide (new random :of '(:first #f)))

Example 20-16. The rotation pattern.

(new rotation
  :notes `(, (new range :by -2 :initially (keynum 'c6))
             b3 f4 g5 ef6)
  :rotations (new cycle :of '((0 1 1) (0 1 2))))

Example 20-17. Random 12-tone generator.

(define (ranrow end)
  (let ((rows (new transposer
                :of (new cycle :of '(0 1 6 -5 10 11 5 16 15 21 26 20))
                :on (new random :keynums '(c4 cs3 b3 fs4 fs3))))
        (rhys (new random 
                :of `((t :min 4) (s :min 2) 
                      (q :weight 3)
                      (te :min 3) (tq :min 3) 
                      ,(new cycle :of '(e. s))
                      (e :weight 2))))
        (amps (new random :of '((mf :weight 7)
                                (mp :weight 3)
    (process while (< (now #t) end)
             for k = (next rows)
             for r = (rhythm (next rhys) 70)
             for a = (amplitude (next amps))
             output (new midi :time (now)
                         :keynum k :amplitude a
                         :duration r)
             wait r )))

Example 20-18. A second order Markov rhythm pattern.

(new markov
  :of '((e s -> s)
        (q s -> e.)
        (q. s -> s)
        (h s -> e.)
        (e e -> s e e. q q. q.. h)
        (* e -> e)
        (* s -> e e. q q. q.. h)
        (* h -> e e. q q. q.. h)
        (* q.. -> s)
        (* q. -> e s)
        (* q -> e e. q q. q.. h)
        (* e. -> s))
  :for 20
  :past '(q q))

Example 20-19. A quasi-markov graph

(new cycle
  :of `(,(new graph 
           :of `((c4 :id 1 :to ,(new random :of '(2 5)))
                 (d4 :id 2 :to ,(new random :of '(1 3)))
                 (ef4 :id 3 :to ,(new random :of '(2 4)))
                 (f4 :id 4 :to ,(new random :of '(3 5)))
                 (,(new heap :of '(g4 fs4 b4 c5))
                  :id 5 
                  :to ,(new cycle :of '(1 2 3 4)))))

Example 20-20. Implementing a pattern with the funcall pattern.

(define (noreps low hi n)
  (define (thunk )
    (loop repeat n
          for x = (between low hi x) 
          collect x))
  (new funcall :of #'thunk))

Interaction 20-4. Defining a noreps pattern.

cm> (define p (noreps 60 72 5))

cm> (next p t)
(63 61 64 62 70)
cm> (next p t)
(66 61 67 69 61)

Example 20-21. Repetition and randomness.

(define (wander tmpo)
  (let ((bass (new copier :of (noreps 41 60 5)
                   :for (new random :of '(1 3 5))
                   :repeat 10))
        (amps (new heap :of '(.6 .4 .4 .4 .4))))
    (process for k = (next bass)
             for a = (next amps)
             until (eod? k)
             (new midi :time (now)
                  :keynum k
                  :duration (if (> a .5) 5 3)
                  :amplitude a)
             wait (rhythm 1/20 tmpo))))

Interaction 20-5. Listening to wander.

cm> (events (wander 48) "pat-17.mid")

Example 20-22. Retrograding and inverting patterns.

(define (revpat pat)
  ;; return the reverse of pat
  (define (thunk )
    (let ((vals (next pat true)))
      (reverse vals)))
  (new funcall :of #'thunk))

(define (invpat pat)
  ;; return the inversion of pat,
  ;; which must contain keynums or notes.
  (define (thunk )
    (let ((vals (next pat true)))
      (invert vals)))
  (new funcall :of #'thunk))

(define (mirror pat)
  ;; return a period of pat followed
  ;; by its strict retrograde
  (define (thunk )
    (let ((vals (next pat true)))
      (append vals (reverse vals))))
  (new funcall :of #'thunk))

Interaction 20-6. Palindrome of random values.

cm> (define p (mirror (noreps 0 12 6)))

cm> (next p t)
(0 2 7 0 2 7 7 2 0 7 2 0)
cm> (next p t)
(4 3 5 10 0 4 4 0 10 5 3 4)

Example 20-23. Random rows with retrograde and inversion.

(define (ranrow2 end offset tmpo chan)
  ;; get a row, any row.
  (let* ((arow (shuffle
                (loop for i below 12
                      collect i)) )
         (main (new cycle :of arow)) ; prime form
         (rows (new transposer
                 ;;  heap of p, i, r and ri forms.
                 :of (new heap
                       :of (list main
                                 (invpat main)
                                 (revpat main)
                                 (revpat (invpat main))))
                 :on (new cycle
                       :keynums (transpose arow offset))))
         (rhys (mirror
                (new random 
                  :of (list
                       (new cycle :of 't :for 4)
                       (new cycle :of 's :for 2)
                       '(q :weight 3)
                       (new cycle :of 'te :for 3)
                       (new cycle of 'tq :for 3) 
                       (new cycle :of '(e. s))
                       '(e :weight 2)))))
         (amps (new random :of '((mf :weight 7)
                                 (mp :weight 3)
    (process while (< (now #t) end)
             for k = (next rows)
             for r = (rhythm (next rhys) tmpo)
             for a = (amplitude (next amps))
             output (new midi :time (now)
                         :keynum k
                         :amplitude a
                         :duration r
                         :channel chan)
             wait r )))

Interaction 20-7. Random 12-tone music.

cm> (events (loop for i below 4
                  (ranrow2 32
                          (transpose 'c3 (* i 12))
            (loop for i from 0 by 8 to 16
                  collect i))

Interaction 20-8. Three generations from a context-free pattern.

cm> (define p
      (new rewrite :of '((a :to (b a))
                         (b :to (a a b)))
           :initially '(a b)))

cm> (next p 19)
(a b b a a a b a a b b a b a b a a a b)

Example 20-24. Rewrite melody.

(define (stepper end rate from)
  (let ((pat (new range :initially (keynum from) 
                  :stepping (new rewrite
                              :of '((+2 :to (+2 -2 +2))
                                    (-2 :to (-2 -2 +2)))))))
    (process while (< (now) end)
             output (new midi :time (now)
                         :keynum (next pat)
                         :duration rate)
             wait rate)))

Interaction 20-9. Listening to four voice stepper.

cm> (events (list (stepper 20 (rhythm 's 100) 'c5)
                  (stepper 20 (rhythm 'te 100) 'f4)
                  (stepper 20 (rhythm 'e 100) 'bf3)
                  (stepper 20 (rhythm 'tq 100) 'ef3))

Example 20-25. Harmonies from a context sensitive rewrite.

(define (lsystem-harmonies len rhy dur)
  (let ((lsys (new rewrite :of '(((0 4 7) :id f)
                                 ((0 3 7) :id g)
                                 (+1 :id +)
                                 (-1 :id -))
                   :initially '(f + f - g - f)
                   :rules '((f -> f f - g - - g - f)
                            (g -> g f + f))))
        (term false)
        (knum 60))
    (process repeat len
             (set! term false)
             (loop until term
                   for x = (next lsys)
                   (if (list? x)
                     (set! term x)
                     (set! knum (fit (+ knum x) 48 72))))
             each c in (transpose term knum)
             output (new midi :time (now)
                         :keynum c
                         :duration dur
                         :amplitude .7)
             wait rhy)))

Interaction 20-10. Listening to context-sensitive rewrite.

cm> (events (lsystem-harmonies 200 .2 .35)

Example 20-26. Probability as a function of time.

(define (cage offset)
  (let* ((w 0)                      ; weight of CAGE
         (d (pval w))               ; delay eval of w
         (p (new random
              :of `((g3 :weight ,d) ; delay weight of G
                    (a3 :weight ,d) ; delay weight of A
                    (c4 :weight ,d) ; delay weight of C
                    (e4 :weight ,d) ; delay weight of E
                    (g4 :weight ,d) ; delay weight of G
                    (r :max 1 :weight .25)) ; add rests
              :for 1))
         (q (new random 
              :of (list 1/16 1/8
                        (new cycle :of 1/32 :for 2 )))))
    (process repeat 100
             for n = (next p)
             for r = (rhythm (next q) 65)
             for i from 0
             ;; interpolate new weight value for CAGE notes.
             set w = (interp i 0 .5 90 4)
             output (new midi :time (now)
                         :duration r 
                         :keynum (transpose n offset))
             wait r)))

Interaction 20-11. Listening to the Cage algorithm.

cm> (events (loop for o in '(-12 0 12 24)
                  collect (cage o))
            (loop for r in '(0 h w w.)
                  collect (rhythm r 65)))

Chapter Source Code

The source code to all of the examples and interactions in this chapter can be found in the file patterns.cm located in the same directory as the HTML file for this chapter. The source file can be edited in a text editor or evaluated inside the Common Music application.