Cours pour le Master ATIAM option MMIM (combinatoire des mots et langages formels)
;-------------------------------------------------------------------- 
;TUTORIAL FOR THE LISP CLASSES 'ORACLE' AND 'IMPROVIZER' WITH 'BEATS' 
;Marc Chemillier (after Gerard Assayag) 
;PART I (May 12th 2009, last modified February 16th 2010) 
;-------------------------------------------------------------------- 
;Examples for a quick understanding of the Lisp code of the 'Improvizer' function in mode 'Beats' 
;In the Open Music environment, first evaluate the whole file (Ctrl-H) 
;Then select each expression and evaluate it (Ctrl-E) 
;Look at the result in the Listener window and listen to the sound examples 
;Maj-Alt-Point opens the definition of a function when the cursor is placed at the end of its name 

(load "CL:UserLibrary;Omax 2.0;Omax sources;ImprotekTutorialData.lisp")     ; contains musical data for testing the functions 
(load "CL:UserLibrary;Omax 2.0;Omax sources;ImprotekTutorialCode.lisp")     ; contains new definitions of some functions


;------------ 
;EXAMPLE # 01 
;------------ 
;Basic oracle on letters a, b, c
#| 
(setf o (oracle-online '(a b a c)))        ; = (make-instance 'oracle :text '(a b a c) :lrsMode t)

(inspect o) 
(transition o 2 'a) 
(suppleance o 2) 
(veclrs o) 
(loop for i from 0 to 10 collect (suppleance o i))

The following expressions display the structure of the oracle (transitions, suffix links): 
(loop for x being the hash-key using (hash-value q) of (hashtransition o) do (format t "~a ---> ~a~%" x q)) 
(loop for x being the hash-key using (hash-value q) of (hashsuppl o) do (format t "~a ===> ~a~%" x q)) 
(loop for x being the hash-key using (hash-value q) of (hashsuppl-> o) do (format t "~a ===> ~a~%" x q))

(loop for etat from 1 to (maxetat o) do (format t "~a ===> ~a~%" etat (suppleance o etat)))

(setf o (make-instance 'Pythie :text '(a b a c) :comparateur 'equal :lrsMode t))

Revaluate the previous expressions once again in order to display the structure of o 
|#
;------------ 
;EXAMPLE # 02 
;------------ 
;Musical oracles with events of the class 'Beat' including labels and midi data, using CompareEvent defined for beats
#| 
(setf beat-list2 '( 
((c) ((60 0 500 80 1))) 
((d) ((62 0 500 80 1))) 
((e) ((64 0 500 80 1))) 
((f) ((65 0 500 80 1))) 
((e) ((64 0 500 80 1))) 
((d) ((62 0 500 80 1))) 
((c) ((60 0 500 80 1))) 
))

(setf beats2 (make-beat-list beat-list2)) 
(setf myoracle2 (NewImprovizer))                    
(loop for i from 0 to (1- (length beats2)) do (learn-event myoracle2 (nth i beats2))) 
(inspect myoracle2) 
(loop for x being the hash-key using (hash-value q) of (hashtransition myoracle2) do (format t "~a ---> ~a~%" x (reverse q))) 
(loop for x being the hash-key using (hash-value q) of (hashsuppl myoracle2) do (format t "~a ===> ~a~%" x q))

(loop for i from 1 to (maxetat myoracle2) collect (harmlabel (text myoracle2 i)))

(setf labels2 '((e) (c) (f) (e) (d) (c))) 
(setf newbeats2 (ImprovizeOnHarmGrid myoracle2 (length labels2) labels2)) 
(mapcar 'HarmLabel newbeats2)

(play (beats->chseq newbeats2 500 0))   ;;; val 500 = beat duration in ms

(save-as-midi (beats->chseq newbeats2 500 0)) 

(setf labels2 '((c) (c) (c) (d) (e) (d) (c))) 
(setf newbeats2 (ImprovizeOnHarmGrid myoracle (length labels2) labels2)) 
(play (beats->chseq newbeats2 500 0)) 
|#
;------------ 
;EXAMPLE # 03 
;------------ 
;Different midi data sets for the same label
#| 
(setf beat-list3 '( 
((c) ((60 0 500 80 1))) 
((d) ((62 0 500 80 1))) 
((e) ((64 0 500 80 1))) 
((c) ((72 0 500 80 1))) ; same labels but with different midi data (notes one 8ve higher) 
((d) ((74 0 500 80 1))) 
((e) ((76 0 500 80 1))) 
))

(setf myoracle3 
      (let ((beats3 (make-beat-list beat-list3)) (o3 (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats3)) do (learn-event o3 (nth i beats3))) o3))

(setf labels3 '((c) (d) (e) (d) (e) (c) (d) (e) (d) (e) (c) )) 
(setf newbeats3 (ImprovizeOnHarmGrid myoracle3 (length labels3) labels3)) 
(mapcar 'HarmLabel newbeats3) 
(play (beats->chseq newbeats3 500 0))   ;;; val 500 = beat duration in ms


(play (beats->chseq (ImprovizeOnHarmGrid myoracle3 (length labels3) labels3) 500 0)) 
|#
;------------ 
;EXAMPLE # 04 
;------------ 
;Pattern matching of the labels is done up to a transposition of at most a minor third, 
;thus labels can match beats in the oracle even if they do not appear in the original sequence thanks to transposition
#| 
(setf beat-list4 '( 
((c) ((60 0 500 80 1))) 
((c#) ((61 0 500 80 1))) 
((f) ((65 0 500 80 1))) 
((f#) ((66 0 500 80 1))) 
))

(setf myoracle4 
      (let ((beats4 (make-beat-list beat-list4)) (o4 (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats4)) do (learn-event o4 (nth i beats4))) o4))

(MidiSet (text myoracle4 2)) 
(MidiSet (TransposeClonedBeat (text myoracle4 2) -35))

(setf labels4 '((c) (c#) (c) (g) (g#) (c#) (c) (c) (g#) (g) ))    ; should transpose g and g# on f or f# 
(setf impro4 (ImprovizeOnHarmGrid myoracle4 (length labels4) labels4)) 
(mapcar 'HarmLabel impro4) 
(mapcar 'MidiSet impro4) 
(play (beats->chseq impro4 500 0))

(setf beat-list4 '( 
((c) ((60 0 500 80 1))) 
((c#) ((61 0 500 80 1))) 
((d) ((62 0 500 80 1))) 
((eb) ((63 0 500 80 1))) 
))

(setf labels4 '((c) (c#) (d) (eb) (e) (f) (f#) (a) (bb) (b) (c)))

;Reavalute the construction of myoracle4 above with the new values for beat-list4 and labels4, 
;then play an improvisation generated by this new oracle: 
(play (beats->chseq (ImprovizeOnHarmGrid myoracle4 (length labels4) labels4) 500 0)) 
|#
;------------ 
;EXAMPLE # 05 
;------------ 
;A more complicated example using transposition with real "chord" labels Bm7 and E7 and full midi data 
;Taken from a house tune entitled "Rain" (DJ Kerri Chandler, 1999)

(setf fromrain  '(                           ;beat duration = 484 ms                
((b m7) ((11 0 484 2 14) (35 0 242 97 2) (66 0 484 69 1) (62 0 484 69 1) (61 0 484 69 1) (57 0 484 69 1) (47 242 242 97 2))) 
((e 7)  ((4 0 484 3 14) (34 0 242 97 2) (73 0 484 69 1) (62 0 484 69 1) (61 0 484 69 1) (56 0 484 69 1) (46 242 242 97 2))) 
))

(setf oracle5 
      (let ((beats5 (make-beat-list fromrain)) (o5 (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats5)) do (learn-event o5 (nth i beats5))) o5))

(setf labels5                 ;too many chords so that transposition is required 
'((b m7) (e 7) (bb m7) (eb 7) (a m7) (d 7) (e 7) (e 7) (f# 7) (f# 7) (c# m7) (c# m7) (g# m7) (g# m7) (b m7) (a m7)))

#| 
(progn (setf impro5 nil) 
(pgmout 4 1) (pgmout 33 2) 
(ctrlchg 7 127 1) (ctrlchg 7 127 2) 
(let* ((n (length labels5)) 
       (drumpart (make-list (round (/ n 2)) :initial-element 2beatpoumchi)))
  (setf impro5 (merger (beats->chseq (ImprovizeOnHarmGrid oracle5 n labels5) 484 0)
                       (beats->chseq (make-beat-list drumpart) 484 0)))
  (play impro5)) 
)

(save-as-midi impro5)

(save-as-midi (mf-info->chord-seq (timestretch (chord-seq->mf-info impro5) 2.067)))             ;1.03

|#

(setf 2beatpoumchi 
 '((nolabel nolabel 2) ((36 0 207 121 10) (42 242 207 121 10) (36 484 207 121 10) (40 484 207 121 10) (42 726 207 121 10))))
;------------ 
;EXAMPLE # 06 
;------------ 
;Continuation of EXAMPLE # 05 with an oracle on real midi data, BPM = 124 (beat duration = 60000/BPM = 484 ms) 
;Taken from a harmonic loop by DJ Kerri Chandler in his house tune "Rain", 1999 
;(itself borrowed from the chord changes of "Round Midnight" bars 4, 5, 6, 7) 
;The number of beats in each chord is indicated by a number as the third element 
;The full beat list is in ImprotekTutorialData.lisp 
;Included are variations of the drums pattern, and an audio sample of the original piano loop 'rain-piano.aiff'

;AUDIO EXAMPLE WITH A BETTER SOUND (not QuickTime): 
;- original piano sample alternates with algorithmic substitutions (December 15th 2001)

(setf oracle6 
      (let ((beats6 (make-beat-list rain)) (o6 (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats6)) do (learn-event o6 (nth i beats6))) o6))

(setf labels6 '((b m7 1) (e 7 1) (bb m7 1) (eb 7 1) (g# m7 2) (c# 7 2) (f# maj7 2) (g# 7 2) (b 7 2) (bb 7 2)))

#| 
(progn 
(pgmout 4 1)      ; channel 1 = "4 - Electric Piano 1", for a complete list evaluate the variable *midi-programs* 
(pgmout 33 2)     ; channel 2 = "33 - Electric Fingered Bass" 
(let* ((nbgrids (/ (loop for x in labels6 sum (third x)) 16))
       (drumpart (make-drumpart nbgrids)))
  (play (merger (beats->chseq (ImprovizeOnHarmGrid oracle6 (length labels6) labels6) 484 0)
                (beats->chseq (make-beat-list drumpart) 484 0)))) 
)

;Revaluate the previous expression after evaluating the following label list: 
(setf labels6 
'((c 7 1) (f 7 1) (bb m7 1) (eb 7 1) (g# maj7 1) (g# m7 1) (g maj7 1) (g maj7 1) (f# maj7 1) (eb m7 1) (c 7 2) (f m7 2) (bb 7 2) 
(f 7 2) (bb 7 2) (eb 7 1) (g# 7 1) (c# 7 2) (f# maj7 2) (g# maj7 1) (c 7 1) (f maj7 2) (bb 7 2)) 
)

(setf rhodes (get-aiff))         ; choose the file name: 'rain-piano.aiff'

;WARNING: You need to load the soundfile 'rain-piano.aiff' before playing this example
;The original piano sample is followed by variations on different chord changes: 
(progn (setf impro nil) 
(pgmout 4 1)      ; channel 1 = "4 - Electric Piano 1", for a complete list evaluate the variable *midi-programs* 
(pgmout 33 2)     ; channel 2 = "33 - Electric Fingered Bass" 
(let* ((labels (append (list '(no label 16)) labels6))
       (nbgrids (/ (loop for x in labels sum (third x)) 16))
       (drumpart (make-drumpart nbgrids)))
  (setf impro (merger (beats->chseq (ImprovizeOnHarmGrid oracle6 (length labels) labels) 484 0)
                      (beats->chseq (make-beat-list drumpart) 484 0)))
  (play-sound-now rhodes)
  (play impro)) 
)
(follow the trace by opening a new window)

(Stop-Player *general-player*)    ; if needed... 
(DoPause rhodes)

(save-as-midi impro)  ; visualization of the voicings in a piano-roll

|#

(defun play-sound-now (sound) (let ((dur (get-obj-dur sound))) (doplay sound 0 dur)))

(defun make-drumpart (nbgrids)
  (loop for i from 1 to nbgrids with basic4beat = (list 2beatpoumchi 2beatpoumchi)
        append (append (if (= (random 2) 0) (list 4beatvar1) basic4beat) basic4beat
                       (if (= (random 2) 0) (list 8beatvar2) (append basic4beat basic4beat))))) 
(setf 4beatvar1 
 '((nolabel nolabel 4) ((36 0 242 121 10) (42 242 241 121 10) (40 484 242 121 10) (36 484 242 121 10) (42 726 242 121 10) (36 968 242 121 10) (42 1210 242 121 10) (40 1331 121 121 10) (40 1452 242 121 10) (36 1452 242 121 10) (42 1694 242 121 10) (40 1815 121 121 10)))) 
(setf 8beatvar2 
 '((nolabel nolabel 8) ((36 0 242 121 10) (42 242 241 121 10) (40 484 242 121 10) (36 484 242 121 10) (42 726 242 121 10) (36 968 242 121 10) (40 1129 242 121 10) (42 1210 242 121 10) (40 1452 242 121 10) (36 1452 242 121 10) (42 1694 242 121 10) (40 1775 242 121 10) (36 1936 242 121 10) (40 2097 242 121 10) (42 2178 242 121 10) (36 2420 242 121 10) (40 2581 242 121 10) (42 2662 242 121 10) (36 2904 242 121 10) (40 3065 242 121 10) (42 3146 242 121 10) (40 3388 242 121 10) (36 3388 242 121 10) (42 3630 242 121 10))))
;------------ 
;EXAMPLE # 07 
;------------ 
;BPM = 145 dotted quarter note (beat duration = 414 ms) 
;A boogie-woogie style example played on the organ, the full beat list is in ImprotekTutorialData.lisp 
;Taken from a piano solo by K.Jarrett in "Sun Bear Concerts", "Sapporo" Part II at 5'30, Nov 18th 1976 
;Music notation in M. Chemillier, "Grammaires, automates et musique", in J.P. Briot & F. Pachet 2004 
;Voicings available for all possible chord labels by means of transposition 
;Labels contain a 4th element indicating the position in the bar (1st or 3rd beat)

;AUDIO EXAMPLE WITH A BETTER SOUND (not QuickTime): 
;- solo added manually by Marc Chemillier, April 5th 2000

(setf oracle7 
      (let ((beats7 (make-beat-list sapporo)) (o7 (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats7)) do (learn-event o7 (nth i beats7))) o7))

(setf labels7 '((e 7 8 1) (e 7 8 1) (a 7 8 1) (e 7 8 1) (b 7 8 1) (e 7 8 1)))

#| 
;Plays the basic blues chord changes: 
(progn (setf impro nil) 
(pgmout 17 1)      ; channel 1 = "17 - Percussive Organ" 
(pgmout 52 2)      ; channel 2 = "52 - Choir Aahs", channel 1 duplicated for a more sustained sound 
(pgmout 78 3)      ; channel 3 = "78 - Whistle", channel 1 duplicated for the bass part 
(ctrlchg 7 110 1) (ctrlchg 7 92 2) (ctrlchg 7 127 3) 
(let* ((impro1 (beats->chseq (ImprovizeOnHarmGrid oracle7 (length labels7) labels7) 414 0))
       (impro2 (clone impro1)) (impro3 (clone impro1)))
  (setf (Lchan impro2) (change-element 2 1 (Lchan impro2)) (Lchan impro3) (change-element 3 1 (Lchan impro3))
        (Lmidic impro3) (mapcar #'(lambda (l) (remove-if #'(lambda (x) (> x 6000)) l)) (Lmidic impro3))    ; bass part
        impro (merger (merger impro1 impro2) impro3))
  (play impro) 
))

(Stop-Player *general-player*)

;Revaluate the previous progn expression after evaluating the following label list: 
(setf labels7 '( 
(e 7 8 1) (e 7 4 1) (b 7 2 1) (bb 7 2 3) (a 7 8 1) (e 7 4 1) (e 7 2 1) (c# 7 2 3) (f# 7 4 1) (b 7 4 1) (e 7 8 1) 
(e 7 8 1) (c 7 4 1) (b 7 2 1) (bb 7 2 3) (a 7 8 1) (e 7 4 1) (e 7 2 1) (g 7 2 3) (f# 7 4 1) (f 7 4 1) (e 7 8 1) 
(a 7 4 1) (g# 7 2 1) (g 7 2 3) (c 7 4 1) (b 7 2 1) (bb 7 2 3) (a 7 8 1) (e 7 4 1) (e 7 2 1) (g 7 2 3) (f# 7 4 1) (f 7 4 1) (e 7 8 1) 
(eb 7 4 1) (d 7 2 1) (c# 7 2 3) (c 7 4 1) (b 7 2 1) (bb 7 2 3) (a 7 8 1) (e 7 4 1) (e 7 2 1) (g 7 2 3) (f# 7 4 1) (f 7 4 1) (e 7 8 1) 
))
(follow the trace by opening a new window)
(Stop-Player *general-player*) 
(save-as-midi impro) 
|#

(defun change-element (new old list) (mapcar #'(lambda (x) (substitute new old x)) list))
;------------ 
;EXAMPLE # 08 
;------------ 
;Bernard Lubat's tune "D'ici d'en bas" BPM = 188 (beat duration = 60000/BPM = 319 ms), 128 beats (32 bars) 
;An example involving a real live solo performed by Bernard Lubat at Ircam, May 8th 2004 
;When dealing with live midi data it is necessary to take into account the prolongation of notes accross the beats: 
;In this old version, it is done with the 'beats-check-sustain' function which connects notes 
;from the end of one beat to the beginning of the next as soon as they are on the same pitch 
;Bernard's solo full beat list is in ImprotekTutorialData.lisp 
;Also included are an audio sample of percussion '188.64dicirhytmic.aiff', and a midi bass line

;AUDIO EXAMPLE WITH A BETTER SOUND (not QuickTime): 
;- three choruses flute solo played by Bernard Lubat (May 8th 2004), five choruses trumpet phrases generated by the computer

(setf beats8 (make-beat-list dicidenbas))

#| 
(setf percu (get-aiff))         ; choose the file name: '188.64dicirhytmic.aiff'

;WARNING: You need to load the soundfile '188.64dicirhytmic.aiff' before playing this example
;Plays part of Bernard Lubat's original solo: 
(progn 
(pgmout 75 11)      ; channel 11 = "75 - Pan Flute" 
(play-sound-now percu) 
(play (beats->chseq (beats-check-sustain (subseq (nthcdr (random (- (length beats10) 65)) beats8) 0 64) 
                                         319 30) 319 0))   
)

(Stop-Player *general-player*) 
(DoPause percu)

(save-as-midi (beats->chseq (beats-check-sustain beats8 319 30) 319 0))  ; visualization of the live solo in a piano-roll 
|#

(setf oracle8 
      (let ((o (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats8)) do (learn-event o (nth i beats8))) o))

(setf labels8aa 
'((f m7) (f m7) (f m7) (f m7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7)
  (f m7) (f m7) (f m7) (f m7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7)
  (f m7) (f m7) (f m7) (f m7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7)
  (f m7) (f m7) (f m7) (f m7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c 7) (c 7) (c 7) (c 7))) 
(setf labels8ab 
'((f m7) (f m7) (f m7) (f m7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7) (c m7)
  (f m7) (f m7) (f m7) (f m7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c 7) (c 7) (c 7) (c 7)
  (f m7) (f m7) (f m7) (f m7) (bb 7) (bb 7) (bb 7) (bb 7) (eb) (eb) (eb) (eb) (g#) (g#) (g#) (g#)
  (d 7) (d 7) (d 7) (d 7) (g 7) (g 7) (g 7) (g 7) (c m7) (c m7) (c m7) (c m7) (c 7) (c 7) (c 7) (c 7)))

#| 
(loop for i from 1 to (maxetat oracle8) collect (harmlabel (text oracle8 i)))

;WARNING: You need to load the soundfile '188.64dicirhytmic.aiff' before playing this example
(progn 
(pgmout 75 11)      ; channel 11 = "75 - Pan Flute" 
(pgmout 78 3)       ; channel 3 = "78 - Whistle", a kind of electronic bass... 
(let* ((newbeats (ImprovizeOnHarmGrid oracle8 (length labels8aa) labels8aa))
       (impro (beats->chseq (beats-check-sustain newbeats 319 30) 319 0))
       (mix (merger impro (beats->chseq (make-beat-list (list bassline-aa)) 319 0))))
  (play-sound-now percu)
  (play mix)) 
) 
;WARNING: You need to load the soundfile '188.64dicirhytmic.aiff' before playing this example
(progn 
(pgmout 75 11)      ; channel 11 = "75 - Pan Flute" 
(pgmout 78 3)       ; channel 3 = "78 - Whistle", a kind of electronic bass... 
(let* ((newbeats (ImprovizeOnHarmGrid oracle8 (length labels8ab) labels8ab))
       (impro (beats->chseq (beats-check-sustain newbeats 319 30) 319 0))
       (mix (merger impro (beats->chseq (make-beat-list (list bassline-ab)) 319 0))))
  (play-sound-now percu)
  (play mix)) 
)
(follow the trace by opening a new window)
|#

(setf bassline-aa 
 '((nolabel nolabel 64) 
   ((0 0 2 1 3) (29 447 204 117 3) (36 616 360 93 3) (41 942 97 118 3) (31 1751 184 120 3) (38 1910 305 101 3) (43 2192 98 110 3) (36 2984 234 111 3) (31 3162 346 108 3) (24 3484 120 127 3) (36 4273 231 117 3) (31 4428 336 110 3) (24 4760 96 127 3) (29 5576 204 117 3) (36 5744 306 105 3) (41 6051 90 111 3) (31 6836 178 117 3) (38 6977 321 100 3) (43 7298 104 108 3) (36 8114 202 120 3) (31 8262 354 100 3) (24 8598 99 127 3) (36 9396 194 117 3) (31 9534 332 111 3) (24 9846 122 127 3) (29 10664 204 117 3) (36 10814 332 101 3) (41 11125 96 114 3) (31 11928 188 113 3) (38 12070 322 95 3) (43 12400 96 110 3) (36 13205 198 117 3) (31 13362 342 108 3) (24 13682 122 127 3) (36 14452 212 114 3) (31 14610 329 113 3) (24 14930 114 127 3) (29 15755 210 106 3) (36 15901 288 97 3) (41 16219 92 118 3) (31 17026 179 113 3) (38 17172 309 106 3) (43 17484 90 108 3) (36 18302 197 114 3) (31 18455 322 110 3) (24 18758 94 127 3) (24 19569 178 127 3) (26 19712 382 100 3) (28 20054 322 118 3)) 
)) 
(setf bassline-ab 
 '((nolabel nolabel 64) 
   ((0 0 2 1 3) (29 447 204 117 3) (36 616 332 101 3) (41 927 96 114 3) (31 1730 188 113 3) (38 1872 323 95 3) (43 2202 96 110 3) (36 3008 198 117 3) (31 3164 343 108 3) (24 3484 122 127 3) (36 4254 212 114 3) (31 4412 329 113 3) (24 4732 114 127 3) (29 5558 209 106 3) (36 5703 288 97 3) (41 6021 92 118 3) (31 6828 180 113 3) (38 6974 310 106 3) (43 7286 90 108 3) (36 8104 197 114 3) (31 8258 322 110 3) (24 8560 94 127 3) (24 9371 178 127 3) (26 9514 382 100 3) (28 9856 322 118 3) (29 10176 373 97 3) (29 10620 198 111 3) (32 10786 386 120 3) (32 11236 184 120 3) (34 11405 436 98 3) (34 11906 160 124 3) (38 12069 400 113 3) (38 12556 171 106 3) (39 12722 396 117 3) (39 13205 160 120 3) (43 13334 377 100 3) (43 13810 210 103 3) (44 13966 398 123 3) (44 14432 174 108 3) (48 14588 400 108 3) (48 15055 178 118 3) (50 15252 398 120 3) (50 15722 192 114 3) (42 15877 402 113 3) (42 16358 192 114 3) (43 16508 388 91 3) (43 16944 214 101 3) (47 17132 392 103 3) (47 17586 186 113 3) (48 17779 354 95 3) (48 18230 226 103 3) (43 18416 370 89 3) (43 18879 167 118 3) (36 19042 252 110 3) (36 19342 356 111 3) (38 19660 340 101 3) (40 19962 321 110 3)) 
))
;------------ 
;EXAMPLE # 09 
;------------ 
;"Ziste zeste", BPM = 112, beat duration = 60000/BPM = 536 ms, Bernard's solo recorded in Uzeste, April 4th 2003 
;Funky rhythm with slap bass

;AUDIO EXAMPLE WITH A BETTER SOUND (not QuickTime): 
;- original solo as played by Bernard Lubat on April 4th 2003 
;- older example with substitutions on a Bb7 vamp and a solo generated by a former algorithm (whithout oracle), October 30th 2002

(setf beats9 (make-beat-list zistesolo))

(setf oracle9 
      (let ((o (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats9)) do (learn-event o (nth i beats9))) o))

(setf (max-continuity oracle9) 5)

(setf labels9 
'((bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7)
  (eb 7) (eb 7) (eb 7) (eb 7) (eb 7) (eb 7) (eb 7) (eb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7) (bb 7)
  (f 7) (f 7) (f 7) (f 7) (eb 7) (eb 7) (eb 7) (eb 7) (bb 7) (bb 7) (bb 7) (bb 7) (f 7) (f 7) (f 7) (f 7)))

#| 
;Plays the beginning of Bernard Lubat's solo: 
(progn  (setf impro nil)                  
(pgmout 36 4)       ; "36 - Slap Bass 1" 
(pgmout 4 11)       ; channel 11 = "4" (solo by Bernard Lubat) 
(ctrlchg 7 90 4) (ctrlchg 7 127 11) 
(setf impro (merger (beats->chseq (subseq beats9 0 48) 536 0) 
                    (beats->chseq (make-beat-list (list zistefunk)) 536 0))) 
(play impro) 
)

(Stop-Player *general-player*) 
(save-as-midi impro) 
(inspect beats9)

;Plays solo on the blues chord changes: 
(progn  (setf impro nil)               
(pgmout 36 4)     ; "36 - Slap Bass 1", fixed bass pattern 
(pgmout 4 11)     ; channel 11 = "4" (solo by Bernard Lubat) 
(ctrlchg 7 90 4) (ctrlchg 7 127 11) 
(setf impro (merger (beats->chseq (ImprovizeOnHarmGrid oracle9 (length labels9) labels9) 536 0)
                    (beats->chseq (make-beat-list (list zistefunk)) 536 0))) 
(play impro) 
) 
(follow the trace by opening a new window)
|#
;------------ 
;EXAMPLE # 10 
;------------ 
;Complex chord changes derived from Mingus "Goodbye Porkpie Hat", BPM = 77, beat duration = 60000/BPM = 779 ms 
;Bernard's solo recorded on October 1st 2004 with various chord changes on five choruses 
;Slow blues rock (cf. "Rooftops" by Jerome Sabbagh, "Pogo", 2006)

;AUDIO EXAMPLE WITH A BETTER SOUND (not QuickTime): 
;- flute solo played by Bernard Lubat (October 1st 2004), drums by Lubat and guitare by Fabrice Vieira added in rerecording, 
;mixed by "JPax" Louis at Uzeste (December 7th 2007)

(setf beats10 (make-beat-list goodbye))

(setf oracle10 
      (let ((o (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats10)) do (learn-event o (nth i beats10))) o))

(setf (max-continuity oracle10) 100)

(setf labels10        ;chord changes of Bernard's first chorus 
'((g# 7) (g# 7) (g 7) (g 7) (f# 7) (f 7) (e 7) (e 7) (e 7) (eb 7) (bb 7) (bb 7) (c 7) (f# 7) (f# 7) (f 7)
  (b maj7) (bb m7) (a 7) (a 7) (g# maj7) (d 7) (c# 7) (eb 7) (g# 7) (g# 7) (g# 7) (g# 7) (g 7) (g 7) (f# 7) (f 7)
  (b 7) (eb 7) (d 7) (d 7) (c# 7) (g 7) (f# 7) (f# 7) (d 7) (d 7) (g maj7) (c# 7) (c 7) (c 7) (b 7) (b 7)))

#| 
(inspect oracle10)

;Plays on the chord changes of Bernard Lubat's first chorus: 
(progn (setf impro nil) 
(pgmout 4 1)       ; channel 1 = piano voicings "4 - Electric Piano 1" 
(pgmout 78 2)      ; channel 2 = bass "78 - Whistle"      
(pgmout 75 11)     ; channel 11 = flute "75" (solo by Bernard Lubat) 
(ctrlchg 7 110 1) (ctrlchg 7 127 2) (ctrlchg 7 127 11) 
(let* ((drumpart (loop for i from 1 to (floor (length labels10) 8) collect roof)))     ; roof duration = 8 beats (2 bars)
  (setf impro (merger (beats->chseq (thread-Beats (ImprovizeOnHarmGrid oracle10 (length labels10) labels10)) 779 0)
                      (beats->chseq (make-beat-list drumpart) 779 0)))
  (print labels10) 
  (play impro)) 
)

(Stop-Player *general-player*)

(save-as-midi impro) 
;(str2ctrlNum "Effects3Depth")   ; # 93 = chorus effect (does not work in Open Music)

;Revaluate the previous progn expression after evaluating the following label lists: 
;- the first one corresponds to Bernard's second chorus, 
;- the second one is not is the oracle, and gives much more discontinuity

(setf  labels10        ;chord changes of Bernard's second chorus 
'((eb 7) (eb 7) (d 7) (g# 7) (g 7) (f# 7) (f 7) (f 7) (e 7) (eb 7) (g 7) (g 7) (f# 7) (f# 7) (f# 7) (f 7) 
  (b maj7) (a 7) (c 7) (c 7) (b 7) (bb 7) (a 7) (a 7) (g# maj7) (g# maj7) (d 7) (d 7) (d 7) (c# 7) (b 7) (b 7) 
  (d 7) (d 7) (d 7) (c# 7) (f 7) (f 7) (e 7) (g 7) (f# 7) (d 7) (eb 7) (d 7) (c# 7) (c 7) (b 7) (b 7)))

(setf  labels10        ;chord changes which are not in the oracle 
'((g# 7) (g# 7) (g 7) (g 7) (c 7) (f 7) (e 7) (e 7) (e 7) (eb 7) (bb 7) (bb 7) (c# m7) (f# 7) (f# 7) (f 7) 
  (b maj7) (bb m7) (a 7) (a 7) (g# maj7) (d 7) (c# 7) (a maj7) (g# maj7) (g# maj7) (g# 7) (g# 7) (g 7) (g 7) (f# 7) (f 7) 
  (b 7) (eb 7) (d 7) (d 7) (d m7) (g 7) (f# 7) (f# 7) (d 7) (d 7) (g maj7) (c# 7) (c 7) (c 7) (b 7) (b 7))) 
(follow the trace by opening a new window)

|#
;------------ 
;EXAMPLE # 11 
;------------ 
;Bill Evans original solo on "Israel", February 2nd 1961 (midifile transcription from www.billevans.nl) 
;Walking bass in medium up tempo, BPM = 182, beat duration = 60000/BPM = 328 ms
(setf beats11 (make-beat-list billevans))

(setf oracle11 
      (let ((o (NewImprovizer)))      
        (loop for i from 0 to (1- (length beats11)) do (learn-event o (nth i beats11))) o))

(setf labels11 
'((d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d m7) (d 7) (d 7) (d 7) (d 7) 
  (g m7) (g m7) (g m7) (g m7) (c 7) (c 7) (c 7) (c 7) (f maj7) (f maj7) (f maj7) (f maj7) (bb maj7) (bb maj7) (bb maj7) (bb maj7)
  (e m7) (e m7) (e m7) (e m7) (a 7) (a 7) (a 7) (a 7) (d m7) (d m7) (d m7) (d m7) (a 7) (a 7) (a 7) (a 7)))


#| 
;Plays Bill Evans original five choruses on "Israel": 
(progn  (setf impro nil)                 
(pgmout 4 1) (pgmout 4 2)    ; channel 1 = Bill Evans' right hand, channel 2 = Bill Evans' left hand 
(pgmout 32 4)                ; "32 - Acoustic Bass" 
(ctrlchg 7 127 1) (ctrlchg 7 127 2) (ctrlchg 7 127 3) (ctrlchg 7 127 10) 
(setf impro (merger (beats->chseq (thread-Beats beats11) 328 0)
                    (beats->chseq (make-beat-list (list israelwalking israelwalking israelwalking israelwalking israelwalking)) 328 0))  ) 
(play impro) 
)

(Stop-Player *general-player*)

;Plays stepwise transformations of Bill Evans solo with less and less continuity along four choruses: 
(progn  (setf impro nil)                    
(pgmout 4 1) (pgmout 4 2)    ; channel 1 = Bill Evans' right hand, channel 2 = Bill Evans' left hand 
(pgmout 32 4)                ; "32 - Acoustic Bass" 
(ctrlchg 7 127 1) (ctrlchg 7 127 2) (ctrlchg 7 127 4) (ctrlchg 7 127 10) 
(let* ((beats11a (progn (setf (max-continuity oracle11) 100) (ImprovizeOnHarmGrid oracle11 (length labels11) labels11)))
       (beats11b (progn (setf (max-continuity oracle11) 10) (ImprovizeOnHarmGrid oracle11 (length labels11) labels11)))
       (beats11c (progn (setf (max-continuity oracle11) 5) (ImprovizeOnHarmGrid oracle11 (length labels11) labels11)))
       (beats11d (progn (setf (max-continuity oracle11) 1) (ImprovizeOnHarmGrid oracle11 (length labels11) labels11))))
  (setf impro (merger (beats->chseq (thread-Beats (append beats11a beats11b beats11c beats11d)) 328 0)
                      (beats->chseq (make-beat-list (list israelwalking israelwalking israelwalking israelwalking))
                                    328 0)))
  (play impro)) 
)
(follow the trace by opening a new window)
(save-as-midi impro)

|#