Music framework in Common Lisp
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
src instruments, envelopes Mar 28, 2018
.gitignore added nyan cat as example Mar 22, 2018
music.asd instruments, envelopes Mar 28, 2018


Just a framework for musical expression in Common Lisp with a focus on music theory!

Totally building it from scratch, there's lots to do and a lot is missing/broken.

It currently uses SBCL timers for queuing real time midi events, so it's SBCL dependant.

See examples/nyan.lisp for an example of a song.


You can designate pitch classes with symbols:

'c 'c♯ 'f♭ 'g♯♯♯

And actual notes with octaves as well:

'c5 'a♭♭7

You can designate intervals with symbols:

'p5 'maj7 2dim2 (doubly diminished second)

You can designate harmonies like this:

'ii 'IVdom9 'vmin42♯5

You can make a harmony like this:

(harmony 'I7/V)
;; => (D F♯ A C)

(harmony 'IVmaj43)
;; => (C E F A)

You can get a scale like this:

(scale (key 'g-phrygian))
;; => (G A♭ B♭ C D E♭ F)

You can designate scale degrees with either numbers, names or solfège syllables:

'(do re 3 4 dominant submediant)

You can realize scale degrees and pitch class like this:

(realize '(do re 3 4 dominant submediant))
;; => (C4 E4 G4 F4 B4 A4 B4 G2)

You can also nest them:

(realize '(do re mi (fa sol la) ti do))
;;; => (C4 D4 E4 (F4 G4 A4) B4 C5)

And indicate octave displacements and rests like this:

(realize '(mi fa > mi fa > mi r < < < < re r))
;; => (E4 F4 E5 F5 E6 R D2 R)

You can realize harmonic progressions in a simple way like this:

(realize (harmony '(I IV64 V43 I6)))
;; => ((C4 E4 G4) (C4 F4 A4) (D4 F4 G4 B4) (E4 G4 C5))

You can get the interval between notes like this:

(difference (note 'g5) (note 'f6))
;; => MIN7

You can get the note or pitch class an interval above or below another like this:

(above (note 'a♭4) (interval 'p8))
;; => A♭5
(below (pitch-class 'd) (interval 'aug2))
;; => C♭

You can add intervals like this:

(sum (interval 'maj6) (interval 'maj3)
;; => AUG8

Why not stack 100 perfect fifths together and see what you get?

   :with i = (interval 'p1)
   :repeat 100
   :do (setf i (sum i (interval 'p5)))
   :finally (return i))
;; => 14AUG401

You can get relative or parallel keys like this:

(parallel (key 'f-major) 'minor)
;; => F-MINOR

(relative (key 'f♯-minor) 'mixolydian)

You can make a sequence like this:

(seq '(> sol la < ri mi re me re do do re))

You can make a chord like this:

(chord '(do mi sol te))

You can designate rhythms using divisions of beats like this:

;; "one and two and three and four
(2 2 2 2 2 2 1 2 2 2 2 2 2 1) ;; twinkle twinkle

;; "one-ee uh ee-and three four"
(4 2 2 4 2 1 1) ;; mario theme opening rhythm

And you can give rhythm to a sequence like this:

(seq '(> sol la < ri mi re me re do do re)
     '(2 2 4 2 4 4 4 2 2 2))

You can play things with live midi using portmidi like this:

(play (seq '(> sol la < ri mi re me re do do re)
	       '(2 2 4 2 4 4 4 2 2 2)))

Which implicitely wraps the expression in event first:

(event (seq '(> sol la < ri mi re me re do do re)
	        '(2 2 4 2 4 4 4 2 2 2)))
;; => (G4@0s-1/4s A4@1/4s-1/2s D♯4@1/2s-5/8s E4@5/8s-7/8s D4@7/8s-1s E♭4@1s-9/8s D4@9/8s-5/4s C4@5/4s-3/2s C4@3/2s-7/4s D4@7/4s-2s)

Which turns the expression into a list of timed events.