; week-07.lisp: linear automata for music ; apply an arbitrary function to three numbers (defun apply-rule-to-triple (rule triple) (funcall rule triple)) ; different kinds of arbitrary functions you might apply.... (defun average-rule (triple) (/ (+ (nth 0 triple) (nth 1 triple) (nth 2 triple)) 3.0)) (defun modulo-rule (triple) (mod (+ (nth 0 triple) (nth 1 triple) (nth 2 triple)) 1.0)) (defun add-subtract-rule (triple) (- (+ (nth 0 triple) (nth 1 triple)) (nth 2 triple))) ; get three numbers from an arbitrary-length list (defun first-three (input-list counter) (if (>= counter 3) nil (cons (car input-list) (first-three (cdr input-list) (+ counter 1))))) ; produce one generation of a linear automaton (defun la-generation (rule input-list) (if (< (length input-list) 3) input-list (cons (apply-rule-to-triple rule (first-three input-list 0)) (la-generation rule (cdr input-list))))) ; recursively produce many generations of a linear automaton (defun la-generations (rule input-list generations) (if (<= generations 0) nil (let ((next-generation (la-generation rule input-list))) (cons next-generation (la-generations rule next-generation (- generations 1)))))) ; produce a list of random values (defun random-list (list-length lower-bound upper-bound) (if (<= list-length 0) nil (cons (+ (random (- upper-bound lower-bound)) lower-bound) (random-list (- list-length 1) lower-bound upper-bound)))) ; (la-generations #'average-rule (random-list 20 30 100) 10) ; render automaton output as a sequence of MIDI chords (defun la-render (start-time input-list) (if (null input-list) nil (append (make-chord start-time (car input-list)) (la-render (+ start-time 0.5) (cdr input-list))))) ; produce one MIDI chord from a list of numbers between 0.0 and 1.0 (defun make-chord (start-time input-list) (if (null input-list) nil (cons (new midi :time start-time :keynum (round (+ (* (car input-list) 88) 21)) :duration (+ (random 0.4) 0.1) :amplitude (+ (random 0.6) 0.2)) (make-chord start-time (cdr input-list))))) #| test examples (events (la-render 0 (la-generations #'average-rule (random-list 10 0.0 1.0) 30)) "test.mid") (events (la-render 0 (la-generations #'modulo-rule (random-list 10 0.0 1.0) 30)) "test.mid") (events (la-render 0 (la-generations #'add-subtract-rule (random-list 10 0.0 1.0) 30)) "test.mid") |#