;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; CALLBACK LOOPS
;;
;; The callback function schedules a
;; a function for execution at a precise moment
;; in the future.
;;
;; The ability to precisly schedule the execution
;; of scheme functions is a critical technique in
;; Impromptu programming.
;;
;; Callback functions take the following form
;; (callback time-to-execute function argA argB ...)
;;
;; The callback function's first argument is a
;; time in the future to execute the function.
;; The second argument is a function or more commonly
;; the symbol name of a function to be called
;; back. The remaining arguments are the arguments
;; of the function being called back.
;;
;; Pass a function if you do not want re-definitions
;; of the function to effect the scheduled callback.
;; Use a symbol if you do want re-definitions of the
;; funtion to effect the scheduled callback.
;;
;; To stop a recursive callback from continuously
;; looping re-define the function without including
;; the callback so the next time the function is
;; called it will not loop again.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; callback the print function in two seconds from now,
; pass the "Hello World" string as an argument
; to the print function.
(callback (+ (now) (* 2 *second*)) 'print "Hello World")
; setup a quasi recursive callback loop
; whereby a function continuously reschedules
; a callback to itself.
; This function will print a string to the log
; view every second.
(define my-function
(lambda (string)
(print string)
(callback (+ (now) *second*) 'my-function string)))
; call my-function to start the recursive loop
(my-function "Hello Impromptu")
; stop the loop by redefining the function without a callback
(define my-function (lambda (string) (print "stopped")))
; A less complicated way to redefine the symbol is simply
(define my-function)
; A simple musical example using callback.
; Set up the audio unit graph.
(au:clear-graph)
(define drums (au:make-node "aumu" "dls " "appl"))
(au:connect-node drums 0 *au:output-node* 0)
(au:update-graph)
; global value to control loop callback
(define *loop-go* #t)
; The dls instrument has drums on midi channel 9
; so we need to add the channel as an extra argument
; to the play-note function.
;
; In order to keep the timing accurate, pass the variable
; time within the function rather than using (now) again
; and again. Otherwise a small inaccuracy would creep in
; because of the time it takes to evaluate the now function each time.
(define loop
(lambda (time)
(play-note time drums 36 80 11025 9)
(play-note (+ time (/ *second* 4)) drums 38 80 11025 9)
(if *loop-go*
(callback (+ time (/ *second* 2)) 'loop (+ time (/ *second* 2))))))
; stop drums
(define stop
(lambda ()
(set! *loop-go* #f)))
; start drums
(define start
(lambda ()
(set! *loop-go* #t)
(loop (now))))
(stop)
(start)