; trig.lisp - generate MIDI events according to some Y condtion

; generated by some equation. possibly good for generating rhythmic

; ideas, assuming you can come up with a good equation and good

; fenceposting thereof

(require :asdf)

(asdf:load-system :smolmidi) ; https://thrig.me/src/smolmidi.git

; there are more things to TWEAK besides these leading def* things

(defconstant +file+ "out.midi")

; how fine or coarse to "fencepost" the equation; this will depend on

; the equation, how many events you want, how much silence is okay from

; overchecking the test condition, etc. a graphing calculator to see

; what the equation is doing with the fenceposts might be handy

(defparameter *step* 0.05)

; how long to carry X on for

(defparameter *max-step* 101)

; how long of a MIDI event to generate (dtime); also used for silence

; accumulation. the MIDI tempo could also be changed, or *step* could be

; used as a real-time value to sleep for, if the output is going to a

; live synth

(defparameter *ticks* 8)

; next up is an equation that gets an X value, and the Y and previous Y

; values are checked for some condition that causes a MIDI event to be

; generated, otherwise silence is extended based on *ticks*

; 2 gives regularity and 5 being somewhat prime will move in and out of

; sync with the 2, or at least that's the theory I'm working with here.

; really should graph these equations...

(defun idea1 (x)

(+ (sin (* 5 x))

(cos (* 2 x))))

; something like raindrops coming off a gutter?

(defun idea2 (x)

(+ (sin (* 7 x))

(cos (* 11 (+ x (sin (/ x 5)))))))

; more fancy would be to vary the pitch according to some condition

; (repeated bars, selection based on what the equation is doing, etc) or

; to also automate or randomize the note velocity, etc

(defun add-note (track pitch offset duration velocity)

(smolmidi:note-on track offset pitch velocity)

(smolmidi:note-off track duration pitch 0))

(defun run-equation (track fn &aux (changes 0))

(loop with x = 0.0 and y = 0.0 and oldy = 0.0 and dtime = 0

while (< x *max-step*) do

(setf y (funcall fn x))

(if (or (and (>= y 0) (< oldy 0))

(and (< y 0) (>= oldy 0)))

(progn (incf changes)

(add-note track 48 dtime *ticks* 100)

(setf dtime 0))

(incf dtime *ticks*))

(incf x *step*)

(setf oldy y))

(values track changes))

(defun make-track (&aux (track (smolmidi:new-track)))

(run-equation track 'idea1)) ; TWEAK

(smolmidi:write-midi-file +file+ (list (make-track)))


Source