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

;;

;; DRAG GRAPHICS EXAMPLE

;;

;; Demonstrates direct manipulation of graphics.

;;

;; Drag two squares around a graphics window

;; using X and Y to control pitch and velocity.

;; Each square controls a different instrument.

;;

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


;; make sure that no audio units are already connected

(au:clear-graph)


;; Setup AudioGraph

; In this example two audio units are used. Their outputs

; are combined using an audio unit mixer, Apple's stereo mixer.

(define marimba (au:make-node "aumu" "dls " "appl"))

(define guitar (au:make-node "aumu" "dls " "appl"))

(define mixer (au:make-node "aumx" "smxr" "appl"))

(au:connect-node mixer 0 *au:output-node* 0)

(au:connect-node marimba 0 mixer 0)

(au:connect-node guitar 0 mixer 1)

(au:update-graph)


;; Set program changes

(au:midi-out (now) marimba *io:midi-pc* 0 12 0)

(au:midi-out (now) guitar *io:midi-pc* 0 25 0)


;; Set up graphics window and register 

;; this process to receive mouse events

(define *canvas* (gfx:make-canvas))

(io:register-mouse-events *canvas*)


;; Setup Some Globals used to store the mouse position

(define *x* 0)

(define *y* 0)


; list containing (instrument path fill stroke)

; The "list" function constructs a list from the elements

; that follow it. In this case there are nested lists.

(define *marimba* 

   (list marimba (gfx:make-rectangle 300 200 50 100)

                 (list 1.0 0.0 0.0 1.0)

                 (list (random) (random) (random) 0.6)))


; list containing (instrument path fill stroke)

(define *guitar*

   (list guitar (gfx:make-oval 100 100 50 100)

         (list 1.0 0.0 0.0 1.0)

                (list (random) (random) (random) 0.6)

                (list 1.0 0.0 0.0 1.0)))

; Create a variable to hold the shape currently being dragged

(define *current* '())


;; Receives all io:mouse-down events

;; Clear (fill) the screen, draw both squares

;; Set *current* to be the shape the

;; mouse is currently inside (or set to null)

(define (io:mouse-down x y)

  (set! *x* x)

  (set! *y* y)

  (gfx:clear-canvas (now) *canvas* '(0.2 0.0 0.0 1.0))

  (gfx:draw-path (now) *canvas*

             (cadr *marimba*) 

             (caddr *marimba*) 

             (cadddr *marimba*)

             1.0

             *gfx:whole-path*)

  (gfx:draw-path (now) *canvas*

             (cadr *guitar*) 

             (caddr *guitar*) 

             (cadddr *guitar*)

             1.0

             *gfx:whole-path*)

  (cond ((gfx:point-in-path? (cadr *marimba*) x y)

         (set! *current* *marimba*))

        ((gfx:point-in-path? (cadr *guitar*) x y)

         (set! *current* *guitar*))

        (else (set! *current* '()))))



;; Receives all io:mouse-up events

;; set *current* to null when mouse button released

(define (io:mouse-up x y)

   (set! *current* '()))



;; Receives all io:mouse-drag events

;; 1) play note on *current* instrument

;; 2) wipe old square (keeping the stroke) 

;; 3) move square 

;; 4) draw square

; The function cadr gets the second element of a list

; caddr gets the third element of a list

; cadddr gets the fourth element of a list, etc...

(define io:mouse-drag

   (lambda (x y)

      (if (not (null? *current*))

          (begin (play-note (+ (now) 1) 

                            (car *current*) 

                            (+ 10 (/ y 4)) (+ 0 (/ x 4)) 5000)

                 (gfx:draw-path (+ (now) 2) *canvas*

                            (cadr *current*) 

                            '(0.2 0.0 0.0 1.0) 

                            '(0.2 0.0 0.0 1.0))

                 (gfx:move-path (+ (now) 3) (cadr *current*) (- x *x*) (- y *y*))

                 (gfx:draw-path (+ (now) 4) *canvas*

                            (cadr *current*) 

                            (caddr *current*) 

                            (cadddr *current*))

                 (set! *x* x)

             (set! *y* y)))))


;; Initialize

(define (start time)

   (gfx:clear-canvas time 

                 *canvas* 

                 '(0.2 0.0 0.0 1.0))

   (gfx:draw-path (+ time 1) *canvas*

              (cadr *marimba*) 

              (caddr *marimba*) 

              (cadddr *marimba*))

   (gfx:draw-path (+ time 1) *canvas*

              (cadr *guitar*) 

              (caddr *guitar*) 

              (cadddr *guitar*)))


;; Start

(start (+ (now) *second*))