;; Pftjschute of Finnegan ;; ;; An algorithmically created composition using markov chains based ;; on the radical and complex work of James, Joyce, Finnegan's Wake ;; Jen Carlile ;; March 1, 2005 #| For this assignment, I created a piece using soundfiles of the human voice speaking different vowel and consonant sounds. The soundfiles are arranged, layed, and controlled by two markov chains created from the first page of Finnegan's Wake. For the first markov chain, I made a list of the first letter of each word on the page, and then did a 3rd order markov analysis on the list. The second markov chain was created in a similar way, but instead of sorting by the first letter, it is sorted by the number of letters in each word. The first markov chain (based on letters) dictates which vowel/consonant soundfile is selected. The second chain (based on word length) controls amplitude, reverb amount, and spatial position. To widen the frequency band, I added in a sampling-rate multiplier term. The multiplier lies in the range from 0.01 to 1.8, with narrower ranges for different sections of the piece. This piece is algorithmically generated using markov chains created from a passage taken from the first page of Finnegan's Wake by James Joyce. |# (load "cut.cmucl") (load "freeverb.cmucl") (setf *vol* 0.5) (setf *num* 0) (setf *num2* 0) (setf *pos* 45) (setf *num3* 0) (setf *rev* 0.9) ;; the first letter of each word on the first page of Finnegan's Wake (defparameter firstLetter '(r p e a a f s o s t b o b b u b c v o r b t h c a e s t v d a f o t s s h p r f n a o t s t s i o e m t w h p w n h t r b t s o e t t l c g w t w d t m a t t n a f a b m m t t t t p n y t v a h a k b a b o i n y t a f i v w s s w w t n r a p o p m h j o s b b a a r e t t r w t b s r o t a t f b b b d g r g t k m n r o b t n r t t t v h k t h h d t o a o w o i r e i b a l o l d t a c m t g f o t o e a s s n t f o f e s m t t h h h o h p s a u o w t t w i q o h t t t a t u t p p a p i a t k o i t p w o h b l t r u t g s d l l)) ;; the length of each word on the first page of Finegan's Wake (defparameter wordLength '(8 4 3 3 5 4 6 2 5 2 4 2 3 6 2 2 1 9 5 2 13 4 2 5 6 3 8 3 8 6 1 6 2 4 3 5 3 3 10 9 4 5 8 2 4 4 3 7 7 2 6 5 2 12 3 10 3 3 3 10 5 2 3 6 6 10 9 2 7 7 7 5 4 4 7 5 6 3 3 4 3 6 4 5 9 5 5 2 8 14 3 3 6 9 5 3 1 7 9 1 5 3 6 3 3 6 4 4 2 7 4 5 8 5 4 5 10 3 1 4 2 3 4 3 4 2 4 6 2 8 3 4 3 2 3 10 3 2 2 4 8 2 3 8 3 4 99 2 1 4 6 7 2 7 5 2 3 3 5 2 4 4 7 3 9 10 3 5 4 2 3 7 8 2 4 5 6 3 10 2 8 4 5 3 4 3 14 2 7 8 5 2 9 3 4 2 3 4 2 5 2 3 13 3 5 23 2 2 3 5 3 2 3 4 5 7 4 4 4 2 4 4 3 5 5 13 6 5)) ;;create a markov chain by analyzing the first letter of words on the first page (setf letter (markov-analyze firstLetter :order 3)) ;;create a markov chain by analyzing word length (setf length (markov-analyze wordLength :order 2)) ;;the above markov chains are order 1 for the most randomness ;; this function chooses a .wav file to play based on the markov pattern 'letter' ;; it also formats the string so it can be passed as an argument to one-cut ;; ** Thank You! to Nando for his help with this function ** (defun getafilename (letterstream) (let* ((letter (next letterstream)) (number nil)) (cond ((eql letter 'a) (setf number 4)) ((eql letter 'e) (setf number 3)) ((eql letter 'i) (setf number 2)) ((eql letter 'o) (setf number 3)) ((eql letter 's) (setf number 2)) ((eql letter 't) (setf number 2))) (if number (format nil "letters/~a~a.wav" (string-downcase letter) (+ 1 (random number))) (format nil "letters/~a.wav" (string-downcase letter))))) (defun getvolume (numstream) (let* ((curnum (next numstream)) (curvol nil)) (cond ((> curnum *num*) (setf curvol (* *vol* 1.05))) ((< curnum *num*) (setf curvol (* *vol* .98))) ((= curnum *num*) (setf curvol *vol*))) (if (< curvol 0.2) (setf curvol 0.2)) (if (> curvol 0.9) (setf curvol 0.9)) (setf *num* curnum) (setf *vol* curvol) )) (defun getdegree (numstream) (let* ((curnum (next numstream)) (curpos nil)) (setf curpos (+ *pos* (- curnum *num2*))) (setf *num2* curnum) (setf *pos* curpos) )) (defun getrev (numstream) (let* ((curnum (next numstream)) (currev nil)) (setf currev (+ *rev* (* 0.03 (- curnum *num3*)))) (if (< currev 0.0001) (setf currev 0.0001)) (if (> currev 0.99) (setf currev 0.99)) (setf *num3* curnum) (setf *rev* currev) )) (with-sound (:srate 44100 :channels 2 :output "out.wav" :reverb freeverb) (loop repeat 100 for time = 0 then (+ time (* 0.05 (next length))) for sr = (+ (* (random 1.0) (- 1.15 0.85)) 0.85) do (one-cut time (getvolume length) :soundfile (getafilename letter) :degree (getdegree length) :reverb-amount (getrev length) :sample-rate-mult sr)) (loop repeat 100 for time = 10 then (+ time (* 0.02 (next length))) for sr = (+ 0.001 (random 1.8)) do (one-cut time (getvolume length) :soundfile (getafilename letter) :degree (getdegree length) :reverb-amount (getrev length) :sample-rate-mult sr)) (loop repeat 100 for time = 20 then (+ time (* 0.1 (next length))) for sr = (+ (* (random 1.0) (- 1.15 0.85)) 0.85) do (one-cut time (getvolume length) :soundfile (getafilename letter) :degree (getdegree length) :reverb-amount (getrev length) :sample-rate-mult sr)) (loop repeat 100 for time = 50 then (+ time (* 0.015 (next length))) for sr = (+ 0.001 (random 1.1)) do (one-cut time (getvolume length) :soundfile (getafilename letter) :degree (getdegree length) :reverb-amount (getrev length) :sample-rate-mult sr)) (loop repeat 75 for time = 55 then (+ time (* 0.005 (next length))) for sr = (+ (* (random 1.0) (- 1.1 0.9)) 0.9) do (one-cut time (- 1 (getvolume length)) :soundfile (getafilename letter) :degree (getdegree length) :reverb-amount (getrev length) :sample-rate-mult sr)) )