Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


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.


Music framework in Common Lisp






No releases published


No packages published