1 Introduction

Once upon a time, there were many music composition software
packages, mostly written in Common LISP. To name a few I know,
Common Music, Symbolic Composer (not related to the Symbolics Lisp
Machine). Common Music is still available in source code but I
doubt if anyone is still able to setup that. Symbolic Composer just
vaporized decades ago, which some archived programs scattered over
the Internet. The package is also a 32bit Intel program so newer
macOS versions would not support it and it is license protected
anyway. Yet another is Patchwork, a more graphic oriented composing
program, and I’d be surprise if it is able to survive from bit

The one I actually uses is Opusmodus, similar in the spirit of
Symbolic Composer. Opusmodus has release 3.0 based on LispWorks on
Dec 2022 which has Apple M1 support, and the Windows port is on the

2 Modulate Modulation

Before introducing all the fancy terms about algorithm
composition, let’s first see a brief example that generates melody
from modulation of sin wave.

  |(setq pitch
  |      (filter-repeat 1 (quarter-tone-closest
  |                        (vector-to-pitch
  |                         '(g3 g5)
5 |                         (add-sine-waves
  |                            12 120 9 4.2 :phase 7
  |                            :modulation (gen-sine 120 1 0.4 :phase 60))
  |                         :quantize 1/2))))

Figure 2.1 Visualized

Then add some classic euclidean rhythm. Since this is a
randomized process, a :seed argument
is provided to produce consistent result.

  |(setq rythm
  |      (euclidean-rhythm (gen-repeat 18 8) 1/2 8 1/16 :seed 9941))

Figure 2.2 The generated

3 Polyphony? No problem

Sometimes it is just desirable to have some polyphonic part playing. This
time, we could add some variation by changing velocity a bit. The
basic idea is still sine wave modulation.

   |(setq rythm
   |      (quantize
   |       (add-sine-waves 17 120 9 0.3
   |                       :phase 44
 5 |                       :modulation (gen-sine 120 3 0.4 :phase 60))
   |       '(1 2 3 4) :type :ratio))
   |(setq pitch
   |      (chord-inner-remove
   |       '(5 1)
10 |       (harmonic-progression
   |      (filter-repeat 2 (mapcar #'floor
   |              (add-sine-waves 12 120 9 1
   |                              :phase 9
   |                              :modulation
15 |                              (gen-sine 120 1 0.3 :phase 3))))
   |      '(c major))
   |       :seed 564))
   |(setq score (make-omn :pitch pitch :length rythm
20 |                      :velocity '(f mf p mp)))

Figure 3.1 Generated
polyphony chords.

4 General composition structure

4.1 Multi-track length alignment

To start composing music it is important to first decide how
many sections one would like to have. Which that settled one can
use get-span to acquire the length
information, then use length-span to
fill other materials like percussion generated by gen-euclidean-omn into the desirable length.



Instead of specify a very long count number to gen-euclidean-omn, which would cause a long time
to compute, length-span takes much
less time to since it just repeats materials.

4.2 Snap to the scale

Now we have some method to generate wave forms and quantize them
to twelve tones. But just playing these pitches won’t make you feel
right. The thing is, you have to decide an interesting scale and
map the generated notes to it.

To do that, we have tonality-map.

   |(setq pitch
   |      (quarter-tone-closest
   |       (vector-to-pitch
   |        '(g3 g5)
 5 |        (add-sine-waves
   |         12 120 9 4.2 :phase 7
   |         :modulation (gen-sine 120 1 0.4 :phase 60))
   |        :quantize 1/2))))
10 |(filter-repeat 3 (tonality-map '(c4e4a4f4e5) pitch))

Figure 4.2.1 Generated score

5 Quick music theory

5.1 Major keys

Major keys are of the '(0 2 4 5 7 9 11
interval. The key
signatures are hard to remember, but one trick is for sharp keys
the name is one half step higher than last sharp; for flat keys the
name is the second to last flat. The reason why it works is
demonstrated below. The name is just from the first note in each

Figure 5.1.1 A list of major keys

This is produced by OMN generated by this lisp loop:

  |(loop for i from 0 to 11
  |  collect (append '(q)
  |                  (integer-to-pitch (x+b '(0 2 4 5 7 9 11 12) i))))

Read More