;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; A SELF REPRODCUING MELODY
;;
;; A melody that pretends to be a DNA strand.
;; The melody acts like a gene sequence
;; with each note acting as a codon.
;; Stretching the metaphors a little bit but
;; there is some fun self referencing here
;; whereby a melody is it's own transformation.
;;
;; c: increment index into melody
;; d: decrement index into melody
;; e: randomly move melody index
;; f: reverse melody
;; g: swap pitch at index with random pitch
;; a: delete note at current index
;; c2: add random note at current index
;;
;; Try messing with the melody and the codons
;;
;; Note that there are couple of useful list functions
;; defined in this example that you might like to
;; keep for future use.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LIST HELPER FUNCTIONS
;;delete from list at index
(define delete-at-index
(lambda (k lst)
(cond ((or (null? lst)
(< k 0))
lst)
((= k 0)
(cdr lst))
((>= k (length lst))
lst)
(else (set-cdr! (cl:nthcdr (- k 1) lst)
(cl:nthcdr (+ k 1) lst))
lst))))
; insert into list at index
(define insert-at-index
(lambda (k lst obj)
(cond ((or (null? lst)
(< k 0))
lst)
((= k 0)
(cons obj lst))
((> k (length lst))
lst)
(else (set-cdr! (cl:nthcdr (- k 1) lst)
(cons obj (cl:nthcdr k lst)))
lst))))
; change list item at index
(define change-at-index
(lambda (k lst obj)
(cond ((or (null? lst)
(< k 0))
lst)
((>= k (length lst))
lst)
(else (set-car! (cl:nthcdr k lst) obj)
lst))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Setup Audio Graph
(au:clear-graph)
(define *guitar* (au:make-node "aumu" "dls " "appl"))
(define *koto* (au:make-node "aumu" "dls " "appl"))
(define *mixer* (au:make-node "aumx" "smxr" "appl"))
(define *reverb* (au:make-node "aufx" "mrev" "appl"))
(au:connect-node *reverb* 0 *au:output-node* 0)
(au:connect-node *mixer* 0 *reverb* 0)
(au:connect-node *guitar* 0 *mixer* 0)
(au:connect-node *koto* 0 *mixer* 1)
(au:update-graph)
(au:set-param (now) *reverb* 0 0 0 0.5)
(au:midi-out (now) *guitar* *io:midi-pc* 0 24 0)
(au:midi-out (now) *koto* *io:midi-pc* 0 108 0)
; Setup some global vars
(define *go* #t)
(define *pitch-map* '((c . 72)
(d . 74)
(e . 76)
(f . 77)
(g . 79)
(a . 81)
(c2 . 84)))
(define *rhythm-map* '(0.25 0.25 0.25 0.25 0.5 0.5 2.0))
(define *accomp-map* '(60 64 67 60 64 67 60 64 62 65 69 62 65 69 62 65))
; Define codons
(define-macro (c)
'(set! index (+ index 1)))
(define-macro (d)
'(set! index (- index 1)))
(define-macro (e)
'(set! index (random (length melody))))
(define-macro (f)
'(set! melody (reverse melody)))
(define-macro (g)
'(set! melody (change-at-index index melody (random '(a c2 c d e f g)))))
(define-macro (a)
'(set! melody (delete-at-index index melody)))
(define-macro (c2)
'(set! melody (insert-at-index index melody (random '(a c2 c d e f g)))))
; A simple pedal point
(define (pedal time)
(play-note time *guitar* 36 120 (* 8 *second*))
(play-note time *guitar* 48 120 (* 8 *second*))
(let ((newtime (+ time (* (* 4 *second*) (random 5)))))
(if *go* (callback (- newtime 20000) 'pedal newtime))))
; A simple arpeggio
(define (arp time)
(map (lambda (p)
(play-note time *guitar* p (random 35 85) (* *second* 0.75))
(set! time (+ time 11025)))
*accomp-map*)
(if *go* (callback (- time 20000) 'arp time)))
; Apply codons
(define (morph melody)
(let ((index (random (length melody))))
(map (lambda (x) ((eval x))) melody)
melody))
; Loop melody (morphing between each loop)
(define (player time melody)
(print melody)
(map (lambda (p)
(play-note time *koto* (cdr (assq p *pitch-map*)) (random 30 90) *second*)
(set! time (+ time (* *second* (random *rhythm-map*)))))
melody)
(if (and *go*
(not (null? melody))
(callback (- time 20000) 'player time (morph melody)))))
(define (stop)
(set! *go* #f))
(define (start time)
(set! *go* #t)
(arp time)
(pedal time)
(player time '(c c c d e e d e f g c2 c2 c2 g a g a f e d c)))
(stop)
(start (now))