16 Mapping

Example 16-1. Common Music's rescale function.

(define (rescale x old-min old-max new-min new-max)
  ;; scale the size of x by the proportion between ranges
  ;; and then shift into the new coordinate system.
  (let ((old-range (- old-max old-min))
        (new-range (- new-max new-min))
        (old-size (- x old-min)))
    (+ (* (/ new-range old-range)
          old-size)
       new-min)))

Interaction 16-1. Examples of rescale.

cm> (rescale 5 0 10 10 20)
15
cm> (rescale 5 0 10 0 40)
20
cm> (rescale 5 0 10 100 200)
150
cm> (rescale 5 0 10 -200 0)
-100
cm> (rescale 2 0 10 200 100)
180
cm>

Example 16-2. Playing MIDI notes along a sine curve.

(define (play-sine len cycs key1 key2 rhy dur amp)
  (let ((maxx (- len 1))
        (maxr (* 2 pi cycs)))
    (process for x from 0 to maxx 
             ;; rescale i to radians
             for r = (rescale x 0 maxx 0 maxr)
             ;; calc sine value -1 to 1 of r
             for a = (sin r)             
             ;; rescale sin to keynum
             for k = (rescale a -1 1 key1 key2)  
             output
             (new midi :time (now)
                  :keynum k
                  :amplitude amp 
                  :duration dur)
             wait rhy)))

Interaction 16-2. Listening to play-sine.

cm> (events (play-sine 80 4 20 100 .1 .1 .6) 
            "sine.mid")
"sine-1.mid"
cm> (events (list (play-sine 80 4 20 100 .1 .1 .6)  
                  (play-sine 60 5.7 50 80 .1 .1 .6))
            "sine.mid" 
            '(0 2))
"sine-2.mid"
cm>

Example 16-3. Variation of sine wave process.

(define (play-sine2 end cycs rate keymin keymax ampmin ampmax)
  (process for r = (rescale (now) 0 end 0 (* 2 pi cycs))
           for a = (sin r)
           while (< (now) end)
           output (new midi :time (now)
                       :keynum (rescale a -1 1 keymin keymax)
                       ;; invert sine shape for amplitude
                       :amplitude (rescale a -1 1 ampmax ampmin))
           wait rate))

Interaction 16-3. Listening to play-sine2.

cm> (events (play-sine2 10 6 .1 20 70 .1 .9) "sine.mid")
"sine-3.mid"
cm> (events (play-sine2 10 6 .5 20 70 .1 .9) "sine.mid")
"sine-4.mid"
cm>

Interaction 16-4. X and y interpolation pairs.

cm> (loop for x in '(0 .2 .4 .6 .8 1)
          for y = (rescale x 0 1 100 200)
          collect x collect y)
(0 100 0.2 120.0 0.4 140.0 0.6 160.0 0.8 180.0 1 200)
cm> (loop for x in '(0 .25 .5 .75 1)
          for y = (rescale x 0 1 440 220)
          collect x collect y)
(0 440 0.25 385.0 0.5 330.0 0.75 275.0 1 220)
cm>

Interaction 16-5. x and y interpolation pairs.

cm> (loop for x in '(0 .2 .4 .6 .8 1)
          for y = (between 40 80)
          collect x collect y)
(0 50 20 83 40 59 60 66 80 51 100 66)
cm>

Interaction 16-6. interp and interpl

cm> (interp .5 0 0 1 100)
50
cm> (interpl .5 '(0 0 1 100))
50
cm>

Interaction 16-7. Passing keyword arguments to the interpl function.

cm> (interpl 0.5 '(0 0 1 1) :scale 100)
50.0
cm> (interpl 0.5 '(0 0 1 1) :offset 100)
100.5
cm> (interpl 0.5 '(0 0 1 1) :scale 100 :offset 100)
150
cm>

Example 16-4. Interpolating amplitude values from event number.

(define (play-interp len rate key1 key2 mintem maxtem minamp maxamp)
  (let* ((end (- len 1))
         (mid (+ (* .2 len) (random (* .6 len)))))
    (process for x from 0 to end
             for a = (interp x 0 minamp mid maxamp end minamp)
             for c = (interp x 0 mintem mid maxtem end mintem)
             output (new midi :time (now)
                         :keynum (+ key1 (random key2))
                         :amplitude a
                         :duration (* rate 1.5 c))
             wait (* rate c))))

Interaction 16-8. Listening to play-interpl

cm> (events (loop for k in (keynum '(c6 f5 bf4 ef4 af3 df3))
                  for s from 0 by .5
                  collect (play-interp 40 .2 k (+ k 7) 
                                       1 .6 .4 .8))
            "interp.mid")
"interp-1.mid"
cm>

Example 16-5. Common envelope shapes.

(define ramp-up '(0 0 1 1))
(define ramp-down '(1 0 0 1))
(define tri-env '(0 0 .5 1 1 0))
(define mid-env '(0 0 .25 1 .75 1 1 0))
(define exp-down '(0 1 .25 1/4 .5 1/16 .75 1/32 1 0))
(define exp-up '(0 0 .25 1/32 .5 1/16 .75 1/4 1 1))

Example 16-6. Applying normalized shapes to a process.

(define (shaper len env rate ampscale ampoff keyscale keyoff)
  (let ((last (- len 1)))
    (process for i below len
             for x = (/ i last)
             for a = (interpl x env :scale ampscale
                              :offset ampoff)
             for k = (interpl x env :scale keyscale
                              :offset keyoff)
             output (new midi :time (now)
                         :duration rate
                         :keynum k
                         :amplitude a)
             wait rate)))

Interaction 16-9. Calling shaper with different envelopes.

cm> (events (shaper 20 tri-env .15 .7 .05 16 48)
            "shaper.mid")
"shaper-1.mid"
cm> (events (shaper 20 exp-down .15 .5 .2 20 30)
            "shaper.mid")
"shaper-2.mid"
cm>

Example 16-7. Exponential curve for falling ball.

(define (ballfall drops end curve key amp)
  (let* ((all (explsegs drops end curve))
         (max (first all))
         (low (hertz key)))
    (process for d in all
             for e = (random (expt 2.0 (/ d max)))
             for k = (keynum (* low e) :hz)
             for a = (rescale d 0 max .1 amp)
             output (new midi time (now) 
                         :duration d 
                         :keynum k
                         :amplitude a)
             wait d)))

Interaction 16-10. Exponential curve for tempo and key number.

cm> (events (ballfall 40 10 1/256 60 .8) "ball.mid")
"ball-1.mid"
cm> (events (ballfall 100 15 1/150 40 .8) "ball.mid")
"ball-2.mid"
cm>

Example 16-8. Self-similar segments of a line.

(define (sschop value segments levels)
  (if (< levels 1) 
    '()
    (let* ((nextval (/ value segments))
           (nextlev (- levels 1))
           (chopped (loop repeat segments
                          append (sschop nextval segments nextlev))))
      (list* value chopped))))

Interaction 16-11. Calling sschop.

cm> (sschop 440 2 0)
()
cm> (sschop 440 2 3)
(440 220 110 110 220 110 110)
cm> (sschop 36 3 3)
(36 12 4 4 4 12 4 4 4 12 4 4 4)
cm>

Example 16-9. Sierpinski's Melody

(define (sierpinski tone melody levels dur amp )
  (let ((len (length melody)))
    (process for i in melody
             for k = (transpose tone i)
             ;; play current tone in melody
             output (new midi :time (now) :duration dur 
                         :amplitude amp :keynum k
                         :channel 0)
             when (> levels 1)
             ;; sprout melody on tone at next level
             sprout (sierpinski (transpose k 12)
                                melody
                                (- levels 1)
                                (/ dur len) 
                                amp)
             wait dur)))

Interaction 16-12. Listening to sierpinski.

cm> (events (sierpinski 'a0 '(0 7 5 ) 4 3 .5) "sier.mid")
"sier-1.mid"
cm> (events (sierpinski 'a0 '(0 -1 2 13) 5 24 .5) "sier.mid")
"sier-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 mapping.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.