;;; ;;; 01/27/2004 ;;; Common Music Patterns ;;; ;;; 2/13/2004 version references sound files stored in ;;;/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds ;; create a pattern of type "cycle", use note duration names (q -> quarter note) (setf r (new cycle :of '(q q e s s e))) ;;; use the pattern ;;; (next r) --> returns the next element of the pattern ;;; (rhythm (next r)) --> translates the name to a time value in seconds in the current tempo ;;; for more details on rhythm see: ;;; http://www-ccrma.stanford.edu/software/cm/doc/dict/rhythm-fn.html (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r))) do (format t "~s " time) ;; the "mix" clm instrument mixes in a soundfile at a point in time ;; :output-frame is in samples so we must convert from time in ;; seconds to samples, see: ;; http://www-ccrma.stanford.edu/software/snd/snd/clm.html#mix (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*))))) ;;; the second argument to rhythm is an optional tempo factor ;;; (the default is 60 bpm, 60 beats per minute) ;;; here we set up a counter that increments tempo by 5bpm on each iteration of the loop (with-sound(:srate 44100) (loop repeat 50 for tempo from 60 by 5 for time = 0 then (+ time (rhythm (next r) tempo)) do (format t "~s " time) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*))))) ;;; here we define a tempo envelope (the local variable tempo) ;;; and interpolate over it with time, so that we get a smootly ;;; changing tempo (that can change in arbitrary ways) (with-sound(:srate 44100) (loop repeat 50 ;; the tempo "envelope", x values are in seconds, y values are in bpm with tempo = '(0 60 3 60 6 120 10 120) ;; on each iteration we add to time for time = 0 then (+ time ;; the rhythmic value of the next element (rhythm (next r) ;; interpreted with respect to the current ;; tempo as interpolated in the envelope (interpl time tempo))) do (format t "~s " time) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*))))) ;;; more complex rhythmic patterns (with an embedded subpattern) ;;; note the use of backquote "`" and comma "," to add a pattern ;;; element to the list of elements (setf r (new cycle :of `(q q e s s ,(new random :of '(e s. s.. e e) :for 2)) :for 8)) (setf r (new heap :of `(q q e s s ,(new random :of '(e s. s.. e e) :for 2)) :for 8)) ;;; so let's use the new pattern (the last one is a "heap", random selection ;;; with replacement). We use a fixed tempo of 120 bpm. (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) do (format t "~s " time) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*))))) ;;; having to use "mix" with all the parameters is a pain, we can encapsulate it ;;; inside a function and define a explicit "pirexlid" instrument, which is ;;; easier to read and has less parameters (with time being expressed in seconds). (defun pirexlid (time) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*)))) ;;; so the same call as before looks cleaner (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) do (format t "~s " time) (pirexlid time))) ;;; we define another "instrument" (defun potlid (time) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/small-lid-1.snd" :output-frame (floor (* time *srate*)))) ;;; and redefine our rhythm pattern (setf r (new heap :of `(q q e s s ,(new random :of '(e s. s. e e) :for 2)) :for 8)) ;;; and we get two performers to use the same rhythmic pattern, but ;;; not at the same time. (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) do (format t "~s " time) (pirexlid time)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) do (format t "~s " time) (potlid time)) )) ;;; one of the performers is now playing at a different tempo (80 bpm instead of ;;; 120 bpm), so both are out of sinc and one of them finishes first... (with-sound(:srate 44100) (loop repeat 20 for time = 0 then (+ time (rhythm (next r) 80)) do (format t "~s " time) (pirexlid time)) (loop repeat 20 for time = 0 then (+ time (rhythm (next r) 120)) do (format t "~s " time) (potlid time)) )) ;;; of course we can limit our loop by time instead of by number of notes, ;;; let's use the "while" feature of the loop macro. This will mercifully ;;; only last for 10 seconds. One of the performers is using the same ;;; rhythmic pattern but is playing it at half speed... (60 bpm instead ;;; of 120 bpm) (with-sound(:srate 44100) (loop for time = 0 then (+ time (rhythm (next r) 60)) while (< time 10) do (format t "~s " time) (pirexlid time)) (loop for time = 0 then (+ time (rhythm (next r) 120)) while (< time 10) do (format t "~s " time) (potlid time)) )) ;;; ok, let's redefine the instruments adding one more parameter. Our percussionist ;;; can do better than before and produce different amplitudes... (defun potlid (time amp) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/small-lid-1.snd" :output-frame (floor (* time *srate*)) :amplitude amp)) (defun pirexlid (time amp) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*)) :amplitude amp)) (setf r (new heap :of `(q q h h e s s t s ,(new random :of '(s s s) :for 2)) :for 8)) ;;; create a pattern for amplitudes (setf a (new heap :of `(ppp ppp ppp f mp p fff))) ;;; we use the "amplitude" function to translate between amplitude names ;;; and numbers (that mix can understand). (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp)) )) ;;; one more instrument added to the mix... (defun trivet (time amp) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/1.snd" :output-frame (floor (* time *srate*)) :amplitude amp)) ;;; let's add a whole note there so that the texture is not so thick... (setf r (new heap :of `(q w h h e s s t s ,(new random :of '(s s s) :for 2)) :for 8)) ;;; and now we have three players banging on three different "percussion ;;; instruments", all of them using the same basic rhythm pattern, but not ;;; synchronized at all. (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (trivet time amp)) )) ;;; let's redefine the trivet instrument, instead of using the "mix" clm ;;; function we now use the "one-cut" instrument. This can add vibrato, ;;; sampling rate control and amplitude envelope control to a soundfile. ;;; (and a lot of other things as well). More interesting than just plain ;;; sample playback. ;;; the "one-cut" instrument is part of the "cut.ins" file at: ;;; http://www-ccrma.stanford.edu/courses/220b/lectures/2/examples/cut.ins ;;; you need to download it to your working directory, and compile and load ;;; it before you can use the following definition. (defun trivet (time amp rate) (one-cut time amp :soundfile "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/1.snd" ;; we do not add an amplitude envelope, just leave amp as it is :amp-func '(0 1 1 1) ;; we do pass a sampling rate multiplier :sample-rate-mult rate)) ;;; and add a pattern for controlling sampling rate conversion ;;; "1.0" is not rate conversion at all, ie: play at the original pitch (setf rt (new random :of '(1 1.1 0.9 1.2 0.1))) ;;; so now the trivet player has a "tunable" trivet, that is, a trivet that ;;; he can change in size between notes! Or better, a set of tuned trivets ;;; that have frequency ratios (to the original master trivet) of 1.1, 0.9, 1.2 ;;; and 0.1 - the last one is the "bass trivet" :-) (with-sound(:srate 44100 :statistics t) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate)) )) ;;; obviously the potlid and pirexlid instruments could be changed to use one-cut as well..... ;;; 01/29/2004 (setf r (new heap :of `(q q h h e s s t s ,(new random :of '(s s s) :for 2)) :for 8)) (setf a (new heap :of `(ppp ppp ppp f mp p fff))) (setf rt (new random :of '(1 1.1 0.9 1.2 0.1))) (defun potlid (time amp) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/small-lid-1.snd" :output-frame (floor (* time *srate*)) :amplitude amp)) (defun pirexlid (time amp) (mix "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" :output-frame (floor (* time *srate*)) :amplitude amp)) (defun trivet (time amp rate) (one-cut time amp :soundfile "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/1.snd" ;; we do not add an amplitude envelope, just leave amp as it is :amp-func '(0 1 1 1) ;; we do pass a sampling rate multiplier :sample-rate-mult rate)) (with-sound(:srate 44100 :statistics t) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate)) )) ;;; Duration: 88.7651, Last begin time: 17.9375 ;;; Compute time: 28.486, Compute ratio: 0.32 ;;; OutA max amp: 0.948 (near 11.377 secs) ;;;"/zap/test.snd" ;;; now we use with-mix to isolate all three percussionists ;;; we can change the score for one of them and the others ;;; are just mixed in... ;;; http://www-ccrma.stanford.edu/software/snd/snd/clm.html#with-mix (with-sound(:srate 44100 :statistics t) (with-mix() "perc1" 0 (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp))) (with-mix() "perc2" 0 (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp))) (with-mix() "perc3" 0 (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate))) ) ;;; first time through... ;;; Duration: 87.3276, Last begin time: 17.6250 ;;; Compute time: 28.305, Compute ratio: 0.32 ;;; OutA max amp: 0.732 (near 11.188 secs) ;;;"/zap/test.snd" ;;; second time... ;;; Duration: 87.3276, Last begin time: 0.0000 ;;; Compute time: 0.397, Compute ratio: 0.00 ;;; OutA max amp: 0.732 (near 11.188 secs) ;;;"/zap/test.snd" ;;; let's change something in the second percussionist: ;;; 60 notes instead of 50 (with-sound(:srate 44100 :statistics t) (let* ((*random-state* #S(RANDOM-STATE :SEED 214464539643913 :FIXSEED #(65427681 367335485 250634044 75027447 224158754 510482997 248826895 178541235 39577401 527928579 470234764 290257996 51428656 131576166 207674176 390823226 215523727 199814170 122060315 381945238 243794854 443469863 133521199 257170632 256805179 265642477 198974496 80963503 189170188 206604054 237227377 353393716 229783914 382284057 359650929 399018617 176020288 536256588 17902852 478918536 48178404 204065716 56771807 488407272 422693426 433834005 374329143 136243570 413154235 498987801 104220607 491584442 432050878 520273799 321642460 25 1)))) (with-mix() "perc1" 0 (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp))) (with-mix() "perc2" 0 (loop repeat 60 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp))) (with-mix() "perc3" 0 (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate))) )) ;;; first: save the state of the random number generator (format t "~s~%" *random-state*) ;;; second: save the state somewhere #S(RANDOM-STATE :SEED 53394439818049 :FIXSEED #(322232860 96107050 250634044 75027447 224158754 510482997 248826895 178541235 39577401 527928579 470234764 290257996 51428656 131576166 207674176 390823226 215523727 199814170 122060315 381945238 243794854 443469863 133521199 257170632 256805179 265642477 198974496 80963503 189170188 206604054 237227377 353393716 229783914 96047189 434678376 86306459 149632373 248212571 196444087 518495937 39236071 137429568 347029803 2965016 17398680 104637269 228281457 351767297 76097493 84177204 486165845 198508384 338649829 116924086 41942180 1 32)) ;;; use the saved state: ;;; --> somehow set *random-state* to the saved state ;;; --> avoid global (special) variables that hold common music patterns (with-sound(:srate 44100 :statistics t) (let* ((*random-state* #S(RANDOM-STATE :SEED 214464539643913 :FIXSEED #(65427681 367335485 250634044 75027447 224158754 510482997 248826895 178541235 39577401 527928579 470234764 290257996 51428656 131576166 207674176 390823226 215523727 199814170 122060315 381945238 243794854 443469863 133521199 257170632 256805179 265642477 198974496 80963503 189170188 206604054 237227377 353393716 229783914 382284057 359650929 399018617 176020288 536256588 17902852 478918536 48178404 204065716 56771807 488407272 422693426 433834005 374329143 136243570 413154235 498987801 104220607 491584442 432050878 520273799 321642460 25 1))) (r (new heap :of `(q q h h e s s t s ,(new random :of '(s s s) :for 2)) :for 8)) (a (new heap :of `(ppp ppp ppp f mp p fff)))) (loop repeat 10 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp)))) ;;; Duration: 87.3276, Last begin time: 0.0000 ;;; Compute time: 1.867, Compute ratio: 0.02 ;;; OutA max amp: 0.794 (near 15.627 secs) ;;;"/zap/test.snd" ;;; Let's change all instruments to use one-cut (defun potlid (time amp rate) (one-cut time amp :soundfile "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/small-lid-1.snd" ;; we do not add an amplitude envelope, just leave amp as it is :amp-func '(0 1 1 1) ;; we do pass a sampling rate multiplier :sample-rate-mult rate)) (defun pirexlid (time amp rate) (one-cut time amp :soundfile "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/lid-1.snd" ;; we do not add an amplitude envelope, just leave amp as it is :amp-func '(0 1 1 1) ;; we do pass a sampling rate multiplier :sample-rate-mult rate)) (defun trivet (time amp rate) (one-cut time amp :soundfile "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/1.snd" ;; we do not add an amplitude envelope, just leave amp as it is :amp-func '(0 1 1 1) ;; we do pass a sampling rate multiplier :sample-rate-mult rate)) (with-sound(:srate 44100 :statistics t) (let* ((r (new heap :of `(q q h h e s s t s ,(new random :of '(s s s) :for 2)) :for 8)) (a (new heap :of `(ppp ppp ppp f mp p fff))) (rt (new random :of '(1 1.1 0.9 1.2 0.1)))) (with-mix() "perc1" 0 (let* ((rates (new heap :of '(1 1.001 0.99 1.003 0.98)))) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp (next rates))))) (with-mix() "perc2" 0 (let* ((flex (new random :of '(((0 1 1 1))((0 1 0.2 0.5 1 0.7))((0 1 0.3 0.9 1 1.3)))))) (loop repeat 50 for cut-sample-rate = (next flex) for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp 1.0)))) (with-mix() "perc3" 0 (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate))) )) ;;; change rhythms... (with-sound(:srate 44100 :statistics t) (let* ((r (new heap :of `(q h. h h s s t t ,(new random :of '(s s s) :for 2)) :for 8)) (a (new heap :of `(pppp pppp ppp f mp p fff))) (rt (new random :of '(1 1.1 0.9 1.2 0.1)))) (with-mix() "perc1" 0 (let* ((rates (new heap :of '(1 1.001 0.99 1.003 0.98)))) (loop repeat 51 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp (next rates))))) (with-mix() "perc2" 0 (let* ((flex (new random :of '(((0 1 1 1))((0 1 0.2 0.5 1 0.7))((0 1 0.3 0.9 1 1.3)))))) (loop repeat 51 for cut-sample-rate = (next flex) for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp 1.0)))) (with-mix() "perc3" 0 (loop repeat 51 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate))) )) ;;; END OF WORKING EXAMPLES......... (setf rbass (new cycle :of '(w w h) :for 5)) (setf abass (new heap :of '(ppp ppp ppp fff))) (defun dish (time amp rate) (one-cut time amp :soundfile "/usr/ccrma/web/html/courses/220b/lectures/5/examples/sounds/large-5.snd" :amp-func '(0 1 1 1) :sample-rate-mult 0.5)) (with-sound(:srate 44100) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (pirexlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) do (format t "~s " time) (potlid time amp)) (loop repeat 50 for time = 0 then (+ time (rhythm (next r) 120)) for amp = (amplitude (next a)) for rate = (next rt) do (format t "~s " time) (trivet time amp rate)) ))