;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;

;; USES OSX's BUILT IN SPEECH SYNTH ENGINE

;;

;; This program generates algorithmic poetry

;; based on a simple selection of words.

;;

;; Be aware that the timing of OSX voice synth 

;; operations are not guarateed to be accurate.

;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; Create instances oif the voice synthesizer

(define voice1 (au:get-speech-channel))

(define voice2 (au:get-speech-channel))

(define voice3 (au:get-speech-channel))

(define voice4 (au:get-speech-channel)) 

(define voice5 (au:get-speech-channel)) 

(define voice6 (au:get-speech-channel)) 

(define voice7 (au:get-speech-channel)) 


;; Set the balance between voices

(au:set-speech-vol (now) voice1 0.3)

(au:set-speech-vol (now) voice2 0.3)

(au:set-speech-vol (now) voice3 0.3)

(au:set-speech-vol (now) voice4 0.3)

(au:set-speech-vol (now) voice5 0.5)

(au:set-speech-vol (now) voice6 0.2)

(au:set-speech-vol (now) voice7 1.0)


(define *go* #t)


;; marker

; Events can have a marker number attached to them

; to allow us to mute/ignore them even after they have been

; scheduled. (See below).

(define marker 100)


; Repeat the words at the specified intervals 

; using and callback. Repeat until *go* is false.

; Notes are cons'ed with a marker so they can be

; muted later if required.

(define vloop

   (lambda (time voice text inc)

      (au:speak (cons time marker) voice text)

      (if *go* (callback (+ time 1000) 'vloop (+ time inc) voice text inc))))


; Start each of several word loops playing against each other.

; Set a callback for the ending a couple of minutes in the future.

(define start

   (lambda (time)

      (set! *go* #t)

      (vloop time voice1 "bike" *second*)

      (vloop (+ time (* *second* 4.5)) voice2 "car" *second*)

      (vloop (+ time (* *second* 8.75)) voice3 "boat" *second*)

      (vloop (+ time (* *second* 12)) voice4 "ship" (/ *second* 2))

      (vloop (+ time (* *second* 24)) voice5 "helicopter" (* *second* (/ 4 3)))

      (callback (+ time *minute*)

                (lambda ()

                   (set! *go* #f)

                   (au:speak (cons (+ (now) (* 2.5 *second*)) marker)

                          voice7 "Planes, trains, and automobiles")))))

; Begin the piece

; if you have muted, remember to unmute.

(start (now))


;; Mute

; Blocking all events with this marker number means

; they will be ignored (not played).

(sys:set-block marker)


;; Unmute

; Removing the block means the events will no longer be ignored.

(sys:remove-block marker)