A major scale might run A B C# D E F# G# which is fine for humans but maybe not so good for computers. Computers rather favor numbers. Another way to look at this scale is as pitch numbers, or set in a particular octave,
A B C# D E F# G# A 69 71 73 74 76 78 80 81
here with some MIDI pitch numbers more favorable to computers. Yet another way to look at this scale is as a set of intervals. By subtracting the previous pitch from each successive pitch one might come up with the interval list of 2 2 1 2 2 2 1 (the standard pattern,† according to some). Still another way to represent this scale is as a sum of the prior intervals, or 0 2 4 5 7 9 11. Computers are pretty good at adding certain numbers, especially small integers like we have here, so with a notion of an octave (12 semitones), an octave number, a scale degree (an index into the sums list), and maybe a transposition value
$ cat major.lisp (require :asdf) (asdf:load-system :cl-clno) (in-package #:cl-user) (defpackage :eg (:use #:cl #:cl-clno)) (in-package :eg) (let ((no (clno-new '(2 2 1 2 2 2 1) :transpose 9 :octave 5))) (loop for i from 0 below 7 do (format t "~a " (clno-pitch no i)) finally (fresh-line))) $ sbcl --script major.lisp 69 71 73 74 76 78 80
https://thrig.me/src/cl-clno.git
This is a new system that needs a few more functions (e.g. to obtain the pitch numbers for various chords) and more documentation, but it seems to mostly work. It's also a pretty low-level and computer-y interface to some music theory notions.
The math is pretty simple but you have to get it right (especially when selecting negative offsets into the interval sums); the octave number times the octave size (12 by default) gets you to say pitch 60; the optional transposition can change that to 69 or whatever, and then from there an index in an "intervals sum" list gets you the pitch of a particular scale degree, assuming the octave, transposition, and interval set involved. The interval list can be all sorts of different numbers; for example the rotation 2 2 2 1 2 2 1 will get you a Lydian scale, or 1 4 2 1 a particular Pentatonic scale, etc.
One can also use unusual interval sets that do not add up to the typical twelve-tone scale, but I haven't tested that yet, and you may need a customized synthesizer or software to do suitable things with the resulting pitch numbers.
(require :asdf) (asdf:load-system :cl-clno) (in-package #:cl-user) (defpackage :eg (:use #:cl #:cl-clno)) (in-package :eg) (let ((no (clno-new '(2 2 2 1 2 2 1)))) (format t "~&~a~&" (clno-triad no :count 4)) (format t "~&~a~&" (clno-triad no :count 8 :step 1)) (format t "~&~a~&" (clno-sequence no '(-3 1) 6)))
Here we have triad construction, or "triads" in scare quotes as one can change the step size to any interval value, so a step of 1 results in a scale run upwards. The default step is 2, which may mean a 3rd as the intervals start from 0, not 1. The sequence call loops over a list of intervals, so -3 1 is (depending on the scale) down by a 4th and up by a 2nd, which some of you may recognize.
/blog/2023/10/11/harmonic-sequences.gmi
SBCL> (LET ((NO (CLNO-NEW '(2 2 2 1 2 2 1)))) (FORMAT T "~&~a~&" (CLNO-TRIAD NO :COUNT 4)) (FORMAT T "~&~a~&" (CLNO-TRIAD NO :COUNT 8 :STEP 1)) (FORMAT T "~&~a~&" (CLNO-SEQUENCE NO '(-3 1) 6))) (60 64 67 71) (60 62 64 66 67 69 71 72) (60 55 57 52 54 48) NIL SBCL>
Of course the interval set need not match a Major scale or whatever, in which case steps or leaps will move up or down that interval set as need be, and maybe not by 3rds or 4ths or whatever. Leaps in a pentatonic (or more sparse scale) will move up and down the pitch numbers rather quickly, so are more likely to run into range limits.
Chromatic notes are either trivial to calculate (subtract or add one or maybe two from a pitch native to the scale) or perhaps complicated if one wants to divine the harmonic function of an alien note. Better questions for a computer are probably "what is the inverse of this interval set?" (e.g. notes in the chromatic scale that do not belong to E Mixolydian) and "is this pitch native to a given note object?"
tags #composition #lisp
—
† The "standard pattern" can be represented as long long short long long long short drum beats which can then be recursively expanded to some number of levels, so that within each beat there is another standard pattern, and within that…