18 Randomness and Chance Composition

Example 18-1. Mapping distributions onto frequency space.

(define (play-ran type len rate key1 key2)
  (process repeat len
           for r = (ran :type type)
           for k = (rescale r 0.0 1.0 key1 key2)
           output (new midi :time (now)
                       :keynum k
                       :duration (* rate 1.5)
                       :amplitude .5 )
           wait rate))

;;; channel tuning on first 9 channels

(define ct9 (list true 0 8)) 

(define (mean-ran type n a b)
  (/ (loop repeat n
           sum (ran :type type :a a :b b))
     n))

Interaction 18-1. Playing continuous uniform distribution.

cm> (events (play-ran :uniform 100 .1 20 100)
            "uniform.mid"
            :channel-tuning ct9)
"uniform-1.mid"
cm>

Interaction 18-2. Playing the low pass distribution.

cm> (events (play-ran :low 50 .1 20 100) "low.mid"
            :channel-tuning ct9)
"low-1.mid"
cm>

Interaction 18-3. Playing the high pass distribution.

cm> (events (play-ran :high 50 .1 20 100) "high.mid"
            :channel-tuning ct9)
"high-1.mid"
cm>

Interaction 18-4. Playing the mean distribution.

cm> (events (play-ran :triangular 50 .1 20 100) 
            "tri.mid" :channel-tuning ct9)
"tri-1.mid"
cm>

Example 18-2. An exponential distribution.

(define (play-exp len rate key1 key2 a)
  (process repeat len
           for r = (ran :type :exponential :a a)
           for k = (rescale r 0.0 6.908 key1 key2)
           when (< k 128)
           output (new midi :time (now)
                       :keynum k
                       :duration (* rate 1.5)
                       :amplitude .5 )
           and wait rate))

Interaction 18-5. Playing the exponential distribution for a=1.

cm> (events (play-exp 50 .1 20 100 1) "exp.mid"
            :channel-tuning ct9)
"exp-1.mid"
cm>

Example 18-3. A Gaussian distribution.

(define (play-gauss len rate key1 key2)
  (process repeat len
           for r = (ran :type :gaussian)
           for k = (rescale r 0.0 3 key1 key2)
           when (<= 0 k 127)
           output (new midi :time (now)
                       :keynum k
                       :duration (* rate 1.5)
                       :amplitude .5 )
           and wait rate))

Interaction 18-6. Playing a Gaussian distribution.

cm> (events (play-gauss 50 .1 20 100) "gauss.mid"
            :channel-tuning ct9)
"gauss-1.mid"
cm>

Example 18-4. The beta distribution.

(define (play-beta len rate a b key1 key2)
  (process repeat len
           for r = (ran :type :beta :a a :b b)
           for k = (rescale r 0.0 1.0 key1 key2)
           output (new midi :time (now)
                       :keynum k
                       :duration (* rate 1.5)
                       :amplitude .5 )
           wait rate))

Interaction 18-7. Playing the beta distribution for a=b=.4.

cm> (events (play-beta 50 .1 .4 .4 20 90) "beta.mid"
            :channel-tuning ct9)
"beta-1.mid"
cm>

Example 18-5. Sampling without replacement.

(define (sampling reps rate notes )
  (let ((len (length notes)))
    (process for i below reps
             for j = (mod i len)
             when (= j 0) ; need to reshuffle?
             set notes = (shuffle notes)
             output (new midi :time (now)
                         :keynum (list-ref notes j)
                         :duration (* rate 1.5)
                         :amplitude (interp j 0 .4 (- len 1) .8))
             wait rate)))

Interaction 18-8. Calling shuffle.

cm> (events (sampling 80 .1 '(c d ef f g a bf c5))
            "shuffle.mid")
"shuffle-1.mid"
cm>

Example 18-6. Avoiding direct repetition in discrete distributions.

(define (reps len lb ub skip?)
  (process repeat len
           for l = (if skip? k false)
           for k = (between lb ub l)
           output (new midi time (now)
                       :keynum k :duration .2)
           wait .125))

Interaction 18-9. Random selection with and without direct repetition.

cm> (events (reps 30 60 63 false) "reps.mid")
"reps-1.mid"
cm> (events (reps 30 60 63 true) "reps.mid")
"reps-2.mid"
cm>

Example 18-7. The tapping process.

(define (tapping reps pct rate key amp)
  (let ((half (/ reps 2)))
    (process for i below reps
             for v = (if (< i half) 0 pct)
             output (new midi :time (now)
                         :duration (vary .1 v )
                         :keynum key
                         :amplitude (vary amp v :below))
             wait (vary rate v))))

Interaction 18-10. Comparing 10% variance with 50% variance.

cm> (events (tapping 50 .1 .2 72 .6) "tap.mid")
"tap-1.mid"
cm> (events (tapping 50 .5 .2 72 .6) "tap.mid")
"tap-2.mid"
cm>

Example 18-8. The rain process.

(define (rain len rate env key1 key2 amp)
  (process for i below len
           for e = (interpl (/ i len) env)
           for v = (vary rate e :above)
           ;; rescale e to control shape of beta distribution
           ;; when e=0 z=.4, and when e=1 z=1.
           for z = (rescale e 0 1 1 .4)
           for b = (ran :type :beta :a z :b z)
           output (new midi :time (+ (now) v)
                       :duration v
                       :keynum (between key1 key2)
                       :amplitude (rescale b 0 1 .1 amp))
           wait rate))
(define rain-env '(0 1 .4 0 .6 0 1 1))

Interaction 18-11. Listening to rain.

cm> (events (list (rain 80 .5 rain-env 70 90 .8)
                  (rain 40 1 rain-env 40 60 .8)
                  (rain 20 2 rain-env 20 40 .9))
            "rain.mid")
"rain-1.mid"
cm>

Example 18-9. Adding a random variance to envelope values.

(define (shaper len rate env key1 key2)
  (process for i below len
           for e = (interpl (/ i len) env )
           for k = (rescale e 0 1 key1 key2)
           for r = (between -5 5) 
           output (new midi :time (now)
                       :keynum (+ k r)
                       :duration rate)
           wait (* rate (pick .5 .25 1))))

(define shape-env
  '(0 0 .2 1 .4 .25 .6 .5 .8 0 1 .5))

Interaction 18-12. Listening to two variations of the same envelope.

cm> (events (list (shaper 40 1 shape-env 70 90)
                  (shaper 40 1 shape-env 60 80)
                  (shaper 20 2 shape-env 60 48))
            "shape.mid")
"shape-1.mid"
cm> (events (list (shaper 40 1 shape-env 70 90)
                  (shaper 40 1 shape-env 60 80)
                  (shaper 20 2 shape-env 60 48))
            "shape.mid")
"shape-2.mid"
cm>

Example 18-10. Tendency masking.

(define low-mask '(0 .4 .75 .4 1 0))
(define top-mask '(0  1 .25 .6 1 .6))

(define (masker len rate lower upper key1 key2) 
  (let ((last (- len 1)))
    (process for i to last
             for e = (tendency (/ i last) lower upper)
             for k = (rescale e 0 1 key1 key2)
             output (new midi :time (now)
                         :duration rate
                         :keynum k)
             wait rate)))

Interaction 18-13. Listening to masker.

cm> (events (masker 80 .1 low-mask top-mask 20 110)
            "masker.mid")
"masker-1.mid"
cm>

Example 18-11. Implementing probability tables.

(define (make-ptable data)
  (let ((total (loop for d in data sum (second d)))
        (sum 0))
    ;; total holds sum of weights in data
    (loop for d in data 
          for v = (first d)      ; outcome to return
          for w = (second d)     ; relative weight
          do (set! sum (+ sum w))
          ;; collect outcome and normalized probability
          collect (list v (/ sum total)))))

(define (pran table)
  ;; return outcome in table according
  ;; to its weighted probability
  (let ((x (random 1.0)))
    ;; x is uniform number < 1.
    (loop for d in table
          for p = (second d)
          when (< x p )   ; x in this segment.
          return (first d))))

Example 18-12. Weighted random selection of notes and rhythms.

(define note-tabl
  (make-ptable '((c 3) (d 1) (ef 2) (f 1) (g 3) 
                 (af 1) (bf 1) (c5 3) )))

(define rhy-tabl
  (make-ptable '((s 3) (e 2) (q 1)  (h 1/4))))

(define (play-pran reps notes rhys tempo)
  (process repeat reps for k = (keynum (pran notes))
           for r = (rhythm (pran rhys) tempo)
           output (new
                    midi :time (now) :keynum k 
                    :duration (* r 1.5))
           wait r))

Interaction 18-14. Listening to Pran

cm> (events (play-pran 50 note-tabl rhy-tabl 100) "ptab.mid")
"ptab-1.mid"
cm>

Example 18-13. Random walks applied to keynum and amplitude.

(define (stagger len low high step)
  (let ((k (/ (- high low) 2))
        (a (between .1 .9)))
    (process repeat len
             for r = (pick 1/8 1/4) 
             set k = (drunk k step :low low :high .9 :mode :jump)
             output (new midi :time (now)
                         :duration (* r 1.5)
                         :keynum k :amplitude a)
             wait r)))

Interaction 18-15. Listening to the stagger process.

cm> (events (stagger 50 40 80 3) "drunk.mid")
"drunk-1.mid"
cm> (events (stagger 50 20 90 7) "drunk.mid")
"drunk-2.mid"
cm>

Example 18-14. Using randomness in scaling and tuning.

(define (arpeggiate-exprhy keynums time rate midpoint-frac
                           amplow amphi legato bass-legato
                           bass-cutoff last-legato)
  (let* ((segs (length keynums))
         (last (1- segs))
         (midpoint (floor (* segs midpoint-frac)))
         ;; deltas below midpoint follow one curve, above another.
         (deltas (append (explsegs midpoint (* midpoint-frac time) 
                                   rate)
                         (explsegs (- segs midpoint)
                                   (* (- 1 midpoint-frac) time)
                                   (/ 1 rate)))))
    (process for i from 0
             for k in keynums
             for d in deltas
             for r = (if (< k bass-cutoff)
                       bass-legato
                       (if (= i last)
                         (* last-legato d)
                         (* legato d)))
             for a = (between 0.45 0.5)
             then (drunk a 0.1 :low amplow :high amphi )
             output (new midi :time (now)
                         :keynum k 
                         :amplitude a
                         :duration r)
             wait d)))

Example 18-15. Arpeggiated harmonic distortions.

(define (distort-harmonics fund distort)
  (loop for h from 1 below (floor (/ 25.0 distort)) 
        if (odds (* 0.9 distort))
        collect (keynum (* fund (expt h distort))
                        :hertz)))

(define (arpa-harmonic note dur gap)
  (process with fund = (hertz note)
           for distort from 0.7 below 1.05 by 0.05
           for notes = (distort-harmonics fund distort)
           sprout (arpeggiate-exprhy notes
                                     (* (vary dur 0.1) distort)
                                     (between 4.0 0.25)
                                     (between 0.3 0.6)
                                     0.3  ; amplow
                                     0.8  ; amphi
                                     (* dur distort 0.7) ; bass-legato 
                                     2.0   ; legato 
                                     59    ; bass cutoff
                                     1.0)  ; last-legato 
           wait (vary gap 0.4)))

Interaction 18-16. Arpeggiated harmonic distortions.

cm> (events (arpa-harmonic 'g1 7.0 5.0) "arp.mid" 
            :channel-tuning ct9)
"arp-1.mid"
cm> (events (arpa-harmonic 'g1 6.0 5.0) "arp.mid"
            :channel-tuning ct9)
"arp-2.mid"
cm>

Chapter Source Code

The source code to all of the examples and interactions in this chapter can be found in the file chance.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.