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

;;

;; An example which:

;; a) outputs quad

;; b) uses extended code AU formats

;;

;; You can use the extended AU formats

;; to get more flexibility over your signal processing

;; but primarily because the extended format is block

;; processed and is considerably more efficient than the

;; standard (non-block) code AU processing format.

;;

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


;; IF YOU DON'T HAVE QUAD CHANGE the 4's to 2's

(define code1 (au:make-node "aumu" "code" "MOSO" 4)) ;; here

(define code2 (au:make-node "aumf" "code" "MOSO" 4)) ;; and here

(au:connect-node code1 0 code2 0)

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

(au:update-graph)

(au:print-graph)


;; pulse using extended "aumf" block format in quad

;; samples is an audio buffer which you need to fill

;; frames is the number of frames to fill in the buffer

(definec pulse-quad

   (let ((frequency 100.0) ;; freq

         (period (/ *samplerate* frequency)) ;; pitch

         (pulse-width 5.0)) ;; spectrum

      (lambda (samples:float** frames:i64 time:double channels:double data:double*)

         (dotimes (k (dtoi64 channels))

            (let ((dat (aref samples k)))               

               (dotimes (i frames)

                  (let ((t (modulo (+ time (i64tod i)) period)))

                     (if (< t (* (random) pulse-width))

                         (aset! dat i 0.125) ;(aref dat i))

                         (aset! dat i 0.0))))))

         ;; extended format returns number of frames processed

         frames)))



(au:code:set! code2 "pulse-quad")



;; make-oscil in case you don't have it yet

(definec make-oscil

   (lambda (phase)      

      (lambda (amp freq)

         (let ((inc (* 3.141592 (* 2.0 (/ freq *samplerate*)))))

            (set! phase (+ phase inc))

            (* amp (sin phase))))))



;; define a square-wave builder (needs make-oscil)

(definec make-square

   (lambda ()   

      (let ((osc (make-oscil 0.0))

            (n 50.0))

         (lambda (amp:double freq:double)

            (* amp (tanh (* n (osc 1.0 freq))))))))



;; uses extended "aumu" block format

;; square-wave player uses make-square

;;

;; samples is an audio buffer which you need to fill

;; frames is number of audio frames for each channel in samples

;;

;; the status in extended format is either

;; 1 = note playing

;; 2 = note released

;; 3 = note fast released.

;; 

;; the return value (i64) in extended is the 

;; number of samples into the buffer when you stopped

;; the note - if your in mode 2 or 3.  If you are in mode

;; 1 then the return value is ignored by the AU.

;;

;; If you don't want to stop the note yet and you are

;; in mode 2 or 3 return -1 until you are ready

;; to release the note.

(definec square-wave-quad

   (lambda ()

      (let ((chans 4)

            (sqrs (make-array chans [double,double,double]*)))

         (dotimes (i chans)

            (aset! sqrs i (make-square)))

         (lambda (samples:float** frames:i64 status:i64 freq:double amp:double 

                                  time:double channels:double data:double*)

            (dotimes (j chans)

               (let ((dat (aref samples j))

                     (func (aref sqrs j)))

                  (dotimes (k frames)

                     (aset! dat k (dtof (* amp (func 0.7 freq)))))))

            0))))


(au:code:set! code1 "square-wave-quad")


(au:open-view code1)


;; finally modify pulse to use incoming signal

;; compiling this will give you silence until

;; you start running the loop below

;;

;; also use param one to control the pulse period

(definec pulse-quad

   (let ((frequency 3000.0) ;; freq

         (period (/ *samplerate* frequency)) ;; pitch

         (pulse-width 3.0)) ;; spectrum

      (lambda (samples:float** frames:i64 time:double channels:double data:double*)

         (dotimes (k (dtoi64 channels))

            (let ((dat (aref samples k)))               

               (dotimes (i frames)

                  (let ((t (modulo (+ time (i64tod i)) 

                                   (* (aref data 0) period))))

                     (if (< t (* 1.0 pulse-width))

                         (aset! dat i (* .125 (aref dat i)))

                         (aset! dat i 0.0))))))

         frames)))


(au:open-view code2)


;; and now play quad sqare waves through pulse

(define loop

   (lambda (beat) 

      (setp code2 0 (cosr 0.5 0.5 1/12))

      (play code1 (random 40 80) 120 1/16)

      (callback (*metro* (+ beat (* 1/2 1/8))) 'loop (+ beat 1/8))))


(loop (*metro* 'get-beat 4))


(define loop2

   (lambda (beat) 

      (play code1 (random 24 36) 30 8)

      (callback (*metro* (+ beat (* 1/2 8))) 'loop2 (+ beat 8))))


(loop2 (*metro* 'get-beat 4))