21 Etudes, Op. 7: Automatic Jazz

Interaction 21-1. Creating and displaying MIDI messages.

cm> (make-note-on 0 60 90)
155226
cm> (midi-print-message 155226)
#<Note-On 0 60 90>
155226
cm> (make-note-off 9 48 127)
2496639
cm> (midi-print-message 2496639)
#<Note-Off P "Hi-Mid-Tom" 127>
2498175
cm>

Interaction 21-2. Program changes for Jazz Instruments

cm> (make-program-change 0 0)
196608
cm> (midi-print-message 196608)
#<Program-Change 0 "Acoustic-Grand-Piano">
196608
cm> (make-program-change 1 32)
462848
cm> (midi-print-message 462848)
#<Program-Change 1 "Acoustic-Bass">
462848
cm>

Example 21-1. A seq of program changes for the Jazz Combo

(new seq :name 'combo-setup
     :subobjects
     (list (new midimsg :time 0 
                :msg (make-program-change 0 0))
           (new midimsg :time 0 
                :msg (make-program-change 1 32))))

Interaction 21-3. Testing the program changes.

cm> (events (list #&combo-setup
                  (new midi :time 1 :channel 0
                       :keynum 60)
                  (new midi :time 3 :channel 1 
                       :keynum 48))
            "pctest.mid")
"pctest-1.mid"
cm>

Example 21-2. Global control data for the jazz improviser.

(define jazz-scale ; dorian with decorated octave
  '(0 2 3 5 7 9 10 12 14)) 

(define jazz-changes ; key changes
  '(bf3 ef4 bf3 bf ef4 ef bf3 bf f4 ef bf3 bf))

(define jazz-tempo 120)

Example 21-3. Percussion key numbers in the GM drum map.

(define hihat 42) ; Closed Hi Hat
(define snare 40) ; Electric Snare
(define bdrum 35) ; Acoustic Bass Drum
(define ride1 51) ; Ride Cymbal 1
(define ride2 59) ; Ride Cymbal 2

Example 21-4. The High Hat process.

(define (jazz-high-hat tmpo ampl)
  ;; generate a 4/4 measure of high-hat
  (let ((rhy (rhythm 'q tmpo))
        (dur (rhythm 't8 tmpo))
        (amp (amplitude 'mp))
        (pat (new cycle 
               :of `(r ,hihat r ,hihat ))))
    (process repeat 4
             output
             (new midi :time (now) 
                  :keynum (next pat)
                  :channel 9 :duration dur
                  :amplitude (* amp ampl))
             wait rhy)))

Interaction 21-4. Playing eight measures of the high hat.

cm> (events (loop repeat 8 collect (jazz-high-hat 120 1))
            "perc.mid"
            '(0 2 4 6 8 10 12 14))
"perc-1.mid"
cm>

Example 21-5. Jazz drums

(define (jazz-drums tmpo ampl)
  (let ((knums (new random 
                 :of `((r :weight .25) ,snare ,bdrum)))
        (rhys (new cycle :of '(t4 t8)))
        (amps (new random :of '(f (ffff :weight .1)))))
    (process repeat 8
             for k = (next knums)
             for a = (amplitude (next amps))
             for r = (rhythm (next rhys) tmpo)
             output
             (new midi :time (now)
                  :keynum k :channel 9 
                  :duration r 
                  :amplitude (* a ampl))
             wait r)))

Interaction 21-5. Playing eight measures of the drums.

cm> (events (loop repeat 8
              collect
              (list (jazz-high-hat 120 .99)
                    (jazz-drums 120 .99)))                    
            "perc.mid"
            '(0 2 4 6 8 10 12 14))
"perc-2.mid"
cm>

Example 21-6. Random cymbal element.

(define (or12r wt)
  ;; wt is weight of resting relative to playing
  ;; r1 pattern plays ride1 or rests
  ;; r2 pattern plays ride2 or rests
  (let ((r1 (new random
              :of `(,ride1 (r :weight ,wt) )
              :for 1))
        (r2 (new random 
              :of `(,ride2 (r :weight ,wt) )
              :for 1)))
    ;; return random pattern that slightly
    ;; prefers r1 pattern over r2 pattern
    (new random 
      :of `((,r1 :weight 1.5)
            ,r2)
      :for 1)))

Example 21-7. Jazz cymbals.

(define (jazz-cymbals tmpo ampl)
  (let* ((rhy (rhythm 't8 tmpo))
         (amps (new cycle
                 :of '(mf mp fff f mp ffff mf
                       mp fff f mp ffff)))
         (knums (new cycle
                  :of (list ride1 'r (or12r 5)
                            ride1 'r ride1 
                            ride1 (or12r 7) (or12r 7)
                            ride1 (or12r 3) ride1))))
    (process repeat 12
             for k = (next knums)
             for a = (amplitude (next amps))
             output
             (new midi :time (now) 
                  :keynum k
                  :channel 9 
                  :duration rhy
                  :amplitude (* a ampl ))
             wait rhy)))

Interaction 21-6. Listening to the percussion sounds.

cm> (events (loop repeat 8 
              collect
              (list (jazz-high-hat 120 1)
                    (jazz-drums 120 1)
                    (jazz-cymbals 120 1)))
            "perc.mid"
            '(0 2 4 6 8 10 12 14))
"perc-3.mid"
cm>

Example 21-8. The jazz piano process.

(define (jazz-piano scale on tmpo ampl)
  ;; generate a measure of jazz harmony.
  ;; measure contains either 8 or 12 notes.
  (let* ((reps (odds .65 8 12))
         (rhys (if (= reps 8)
                 (new cycle :of '(t4 t8))
                 (new cycle :of 't8)))
         (amps (if (= reps 8)
                 (new random 
                   :of (list (new cycle :of '(mp f)) 
                             (new cycle :of '(mf ff))))
                 (new random
                   :of (list (new cycle :of '(mp p f))
                             (new cycle :of '(mf mp ff))))))
         (knms (new random
                 :of `((,(new heap :of scale
                              :for (new random 
                                     :of '(1 2 3 4))) 
                        :weight ,(new random 
                                   :of '(1.15 1.65)))
                       r))))
    (process repeat reps
             for r = (rhythm (next rhys) tmpo)
             for a = (amplitude (next amps))
             for l = (transpose (next knms true) on)
             each k in l
             output (new midi :time (now)
                         :channel 0 :keynum k
                         :duration r
                         :amplitude (* a ampl))
             wait r)))

Interaction 21-7. Playing four measures of the piano part.

cm> (events (loop repeat 4
                  collect (jazz-piano jazz-scale 'bf3 120 1))
            "piano.mid"
            '(0 2 4 6))
"piano-1.mid"
cm>

Example 21-9. Helper functions for the acoustic bass process.

(define (getset scale ints)
  ;; return the notes in scale
  ;; at the positions in ints.
  (loop for i in ints 
        collect (list-ref scale i)))

(define (rancyc data prob)
  ;; create cyclic pattern to be used
  ;; as element in random pattern with weight prob
  (list (new cycle :of data) :weight prob))

Example 21-10. The acoustic bass process.

(define (jazz-bass scale on tmpo ampl)
  (let ((rhy (rhythm 'te tmpo))
        (tonics (new random 
                  :of (getset scale '(0 2 4 6 7))))
        (colors (new random 
                  :of (getset scale '(1 3 5 6 8))))
        (amps (new cycle 
                :of '(mp p ffff fff p fff
                      mp p ffff fff mp fff)))
        (durs (new cycle :of '(tq t8 t8)))
        ;; beat map
        (bmap 
         (new cycle 
           :of
           (list
            ;; 5 possible patterns for 1-4
            (new random :for 1
                 :of (list (rancyc '(t r r c) 1.0)
                           (rancyc '(t r r r) .25)
                           (rancyc '(t r t c) .22)
                           (rancyc '(t c t c) .065)
                           (rancyc '(t c t r) .014)))
            ;; 5 possible patterns for 5-7
            (new random :for 1
                 :of (list (rancyc '(r r t) 1.0)
                           (rancyc '(r r r) .25)
                           (rancyc '(r c t) .22)
                           (rancyc '(t c t) .038)
                           (rancyc '(t c r) .007)))
            ;; 5 possible patterns for 8-10
            (new random :for 1
                 :of (list (rancyc '(r r c) 1.0)
                           (rancyc '(r t c) .415)
                           (rancyc '(r r r) .25)
                           (rancyc '(c t c) .11)
                           (rancyc '(c t r) .018)))
            ;; two possible values for 11
            (new random :for 1 
                 :of '((r :weight 1)
                       (t :weight .25)))
            ;; two possible values for 12
            (new random :for 1
                 :of '((r :weight 1)
                       (c :weight .25)))))))
    (process repeat 12
             for x = (next bmap)
             for k = (if (equal? x 't)
                       (next tonics)
                       (if (equal? x 'c)
                         (next colors)
                         x))
             for d = (rhythm (next durs) tmpo)
             for a = (amplitude (next amps))
             output
             (new midi :time (now)      ;
                  :keynum (transpose k on)
                  :channel 1
                  :duration d
                  :amplitude (* a ampl))
             wait rhy)))

Interaction 21-8. Listening to eight bars of the acoustic bass.

cm> (events (loop repeat 8
                  collect (jazz-bass jazz-scale 'bf2 120 1))
            "bass.mid" 
            '(0 2 4 6 8 10 12 14))
"bass-1.mid"
cm>

Example 21-11. The main process.

(define (jazz-combo measures changes tempo scale)
  (let ((roots (new cycle :of changes))
        (ampl 1))
    (process for meas below measures
             for root = (next roots)
             if (= 0 (mod meas 12)) 
             set ampl = (between .5 1)
             sprout (jazz-piano scale root tempo ampl)
             sprout (jazz-cymbals tempo ampl)
             sprout (jazz-high-hat tempo ampl)
             sprout (jazz-drums tempo ampl)
             sprout (jazz-bass scale (transpose root -12)
                               tempo ampl)
             wait (rhythm 'w tempo))))

Interaction 21-9. Two different versions of the Jazz Combo.

cm> (events (list #&combo-setup
                  (jazz-combo 48 jazz-changes
                              jazz-tempo jazz-scale))
            "jazz.mid")
"jazz-1.mid"
cm> (events (list #&combo-setup
                  (jazz-combo 48 jazz-changes
                              jazz-tempo jazz-scale))
            "jazz.mid")
"jazz-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 jazz.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.