;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; MUSIC PROGRAM GENERATOR
;;
;; This example demonstrates a very basic shell
;; for generating 'programs' that write music.
;; Think of the 'program' as a tree with *functions*
;; representing branch points and *terminals*
;; as leaf nodes.
;;
;; Note that nothing has been done to make these
;; results in anyway musical. Let your mind wander :)
;;
;; Try adding more *terminals* and *functions*
;;
;; Not much is needed to extend this into a
;; very basic Genetic Programming system.
;; (a) Create a 'generation' of random programs
;; (b) Create a crossover function
;; (c) Create a fitness function to 'judge' melody fitness
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(au:clear-graph)
; Setup AudioGraph
(define *piano* (au:make-node "aumu" "dls " "appl"))
(au:connect-node *piano* 0 *au:output-node* 0)
(au:update-graph)
;; select random pitch from pitch class
;; bounded by lower and upper (inclusive lower exclusive upper)
;;
;; arg 1: lower bound (inclusive)
;; arg 2: upper bound (exclusive)
;; arg 3: pitch class
;;
;; returns -1 if no valid pitch was found
;;
(define random-pc
(lambda (lower upper pc)
(if (null? pc)
-1
(let loop ((val (random lower upper)) (count 0))
(if (> count 50)
-1
(if (memv (fmod val 12) pc)
val
(loop (random lower upper) (+ count 1))))))))
; assign some terminals
; terminals are leaf nodes
(define *terminals* '(int-12
c-major
octave
index
(random 3)
(random-pc 60 72 '(0 2 4 5 7 9 11))
))
; assign some functions (functions will be passed 2 arguments)
(define *functions* '(+ -))
; some terminals are symbols that need to be
; turned into something. else return t
(define (terminal t)
(cond ((equal? t 'c-major)
(random '(0 2 4 5 7 9 11)))
((equal? t 'int-12)
(random 12))
((equal? t 'octave)
(random '(12 24)))
(else t)))
; build a function randomly choosing between
; *functions* and *terminals* along the way
(define (build-program)
(list (random *functions*)
(if (= 0 (random 3))
(build-program)
(terminal (random *terminals*)))
(if (= 0 (random 3))
(build-program)
(terminal (random *terminals*)))))
; build a melody from a program
(define (build-melody program)
(do ((melody '() (cons (abs (eval program))
melody))
(index 0 (+ index 1)))
((= index 15) (reverse melody))))
; play note sequence
(define (play-sequence time inst plst)
(map (lambda (p d r)
(play-note time inst p d r)
(set! time (+ time r)))
plst
(make-list (length plst) 80)
(make-list (length plst) (* *second* 0.15))))
; 1) generate program
; 2) generate melody by running program
; 3) print program & melody
; 4) play melody and return program
(define (run)
(let* ((program (build-program))
(pitches (build-melody program)))
(print 'program-> program)
(print 'melody-> pitches)
(play-sequence (now) *piano* pitches)
program))
; START
(run)