; 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