# A fractal sequencer toy

2022-05-20 music math composition

Here's a fractal chord sequencer you can play right in your browser.

Transposition/coset:

## How to play

The play/pause ( / ) and reset ( ) buttons are reasonably self-explanatory. Pause takes effect at the end of the current bar, so it won't be instantaneous when you press the button.

Just below those buttons are boxes for the sequence substitution rule.
You can choose the chords that will define the sequence with the
up/down/left/right buttons, but note that the sequencer does *not*
just play these chords in a loop. It does a fractal substitution (described
below) to generate an effectively infinite sequence of chords from the ones
you enter.

Note names C, C#, D, Eb, and so on refer to the roots of chords, and the other symbols describe chord qualities as follows. The basic shape, such as rectangle or diamond, describes the core quality of the chord. When there is more than one symbol for a given chord, differentiated by dots and subscript numbers, the different symbols sound the same but have different effects when they interact with other chords in the fractal substitution algorithm.

- - major
- - minor
- - dominant seventh
- - sus2 (suspended second)
- - diminished
- - augmented
- - major ninth
- - minor ninth
- - major eleventh
- - minor eleventh
- - major add9 (=add2)
- - minor add9 (=add2)

You can change a few other settings. "Stages" is the number of chords in the
substitution rule, adjustable from 2 to 12. "Tempo" is the speed at which
the sequencer runs, in beats per minute. The default is 130, which is
reasonable for most grooves, but some of the grooves sound better a little
slower or faster, so you should experiment. The "groove" selection controls
not only the drum track, but also the rhythm for playing the chord notes
and some details of how it selects the voicing (specific notes) to make up
each chord. Finally, "transposition/coset" sets a root note and chord
symbol that will be applied to *all* the chords in the sequence,
outside the recursive substitution.

As you change settings, the query string in your browser's location bar should be updated with each change. So you can bookmark the URL and return to the same settings, share your unique sequence creation on social media, and so on.

This has been tested only in my old Firefox installation. That means it should probably be compatible with everything else, but I'll be interested to hear reports on how well it works in other browsers.

## How it works: recursive substitution

This sequencer toy is my latest experiment in recursively-generated fractal chord progressions. You may want to read my earlier article on those, and the notes on my more recent piece Aconcagua. Those were focused on specific pieces of music written using fractal chord progressions; this time around, I've turned the concept into an interactive piece of sequencing software.

Suppose you have a chord progression like the doo-wop progression, I-vi-IV-V. If you play it in the key of C, you get the four chords C-Am-F-G. But you could play it in some other key. The same progression in A would be A-F#m-D-E. In F, it would be F-Dm-Bb-C; and so on.

So suppose we take the I-vi-IV-V progression, C-Am-F-G, and play it four times, first in C, then in A, then in F, then in G. The progression itself (C-A-F-G) tells us in what key to play the whole progression.

C-Am-F-G-A-F#m-D-E-F-Dm-Bb-C-G-Em-C-D

That's 16 chords; and we can add another level by playing that entire 16-chord progression four times, first starting on C, then transposed to start on A, then starting on F... this recursive substitution can be carried to as many levels as desired, increasing in length by a factor of four for each level, sequence of chords as long as desired with the same structure at both long and short time scales.

In my piece Dharmapala I added an additional wrinkle: whenever substituting into a minor chord, I swapped the major and minor chords. In that piece I was using the vi-IV-I-V progression ("sensitive female"), so playing it in C would be Am-F-C-G; but when substituting into the chord Am, instead of just transposing it to give F#m-D-A-E, I swapped major and minor to give F#-Dm-Am-Em. I found that applying that swap throughout the fractal substitution made the music more interesting.

Without the major-minor swap, C-Am-F-G as I said would give these chords in the second level of substitution:

C-Am-F-G-A-F#m-D-E-F-Dm-Bb-C-G-Em-C-D

With the major-minor swap, the same C-Am-F-G generating rule gives these (difference bolded):

C-Am-F-G-**Am-F#-Dm-Em**-F-Dm-Bb-C-G-Em-C-D

In this interactive sequencer, I'm applying a similar though more complicated idea: chord qualities are extended into 36 different symbols, each of which transforms the other chord qualities in a different way.

## A little group theory

The sequencer first plays through the generating rule (sequence of chords) as written. Then it plays it with a second level of substitution - so, first chord in the rule combined with each chord in the rule, then the second chord in the rule combined with each chord, and so on. Then it proceeds to three levels of recursive substitution, four levels, and so on.

If the chords are just basic major chords, denoted by the symbol , then the roots are added up as musical
transpositions and the chords remain just basic major chords. But using the
other symbols makes the chord qualities change in ways that get more
complicated as more symbols stack up. For example, is a minor chord *like in Dharmapala*:
it exchanges the major chord symbol with itself.

- ·=
- ·=
- ·=
- ·=

You could program the sequencer to use the generating rule AFCG, or follow that link, and get basically the same sequence of chords that was used in Dharmapala. Each minor chord denoted by exchanges major and minor chords when it comes up in the substitution process.

Note that I said a minor chord *denoted by *. Other minor chords are possible. If
you instead used the symbol for the
minor chord in the sequence, then it would combine with itself to give - another minor chord - as well as combining
with to give a minor chord. So in the
second level of substitution, there would be more minor chords. And in the
third and later levels, other chord symbols would start appearing as a
result of using , such as (minor with added second).

To get some idea of how the chord symbols transform each other to make
the music more complicated, follow this link to try the generating rule
CAFG.
That's the doo-wop progression again, with my best attempt at a twist groove
straight out of 1959. For the first dozen bars or so it's just something
light and happy that Chubby Checker might play. But then it gets, well,
*twisted* by the consequences of the major chord symbols and , which
change others into suspended and diminished chords. Eventually the doo-wop
harmony is almost unrecognizable.

At each step the sequencer shows its chord symbol calculation next to the
reset and play/pause buttons, so you can get some idea of what it's doing.
You can also set a chord symbol with the "transposition/coset" option, which
will be applied uniformly to *all* the chords in the sequence. For
instance, if you set this to a minor chord and all the chords in the
generating rule to , then you would end
up with a sequence of only minor chords.

The chord symbol calculation is based on a branch of mathematics called
*group theory*, which is the abstract study of symmetry. The chord
symbols are elements of a group, and they combine with each other according
to an operation that has the basic group properties of having associativity,
an identity, and inverses. I've carefully selected which group to use, and
how to map group elements into chord qualities, to produce what I think will
be musically useful behaviour.

I don't encourage readers to try too hard to
understand the details of the math because they are not very relevant to
actually playing the sequencer. It is probably better to just experiment
until the results sound good. But if you insist on knowing the exact
definition of the rule for how chord symbols transform each other, here it
is. First of all, the roots of chords (as notes of the 12-note scale)
simply add. The note C is zero semitones; other
notes are however many semitones from C; and the
scale wraps around at the end of the octave. So, for instance, C·E=E, and D·G=A. I am writing a
centre-dot · for the operation that combines two notes. Group theorists may
note that roots of chords are isomorphic to C_{12}.

The symbols for chord qualities are visually complicated, but each of the 36 symbols can be described by an integer from 0 to 17 (shown in the subscript) and a bit 1 or 0 which indicates whether that symbol has a dot in the middle. For example, is described by (0,0) and is described by (7,1). In that representation, the rule for combining chord qualities is summarized as follows.

- (a,0)·(b,0) = (a+b mod 18,0)
- (a,0)·(b,1) = (a+b mod 18,1)
- (a,1)·(b,0) = (a-b mod 18,1)
- (a,1)·(b,1) = (a-b+9 mod 18,0)

For example, ·= and ·=. You may note that is the identity - combine it with any other symbol and you get the other symbol - while is self-inverse, with ·=, and happens to be the only self-inverse symbol.

These rules make the chord symbols isomorphic to the dicyclic
group of order 36, or Dic_{9}, a group chosen to be non-abelian,
about the right size, and have many subgroups of about the right
size. Considering both the root notes and the quality symbols together, the
group describing entire chords is the direct product
C_{12}×Dic_{9}, with 432 elements.

## Subgroups

As mentioned above, the chord quality symbols and affect each other as follows.

- ·=
- ·=
- ·=
- ·=

If you combine any number of copies of these two symbols, the result is always one of the two. So, if you wrote your generating rule with only these two symbols, you could be sure that the calculation would never have any other result. Such a sequence would only ever contain major and minor chords, not anything weird like elevenths. Moreover, although this is harder to state precisely, you could reasonably expect that a sequence generated from a reasonably long rule that contained only and , after several levels of substitution, would contain major and minor chords in roughly equal proportions.

In mathematical terms we can say that these two elements of the group
form a *subgroup*: a subset {, } which is closed under the group operation.
Combining elements of the subgroup always gives elements of the subgroup.
Subgroups are musically useful because we can use them to control what kinds
of chords the sequencer will generate.

Suppose you want to get both major and minor chords, but mostly major. Then you might build your sequence using the chord symbols {, , , }, which form a larger subgroup of three major chords and one minor. The sequence will remain within the subgroup and if it ends up uniformly distributed, it will contain mostly major but also some minor chords.

Here is a list of all the subgroups of the chord quality symbols
(subgroups of Dic_{9} in the sequencer's notation).

- {}
- {, }
- {, , }
- {, , , }
- {, , , }
- {, , , }
- {, , , }
- {, , , }
- {, , , }
- {, , , }
- {, , , }
- {, , , }
- {, , , , , }
- {, , , , , , , , }
- {, , , , , , , , , , , }
- {, , , , , , , , , , , }
- {, , , , , , , , , , , }
- {, , , , , , , , , , , , , , , , , }
- The entire group of 36 symbols is also technically a subgroup of itself.

## Grooves and voicing

The "grooves" are not really the point of this toy, and the UI doesn't let you do much with them except select one. But it's probably worth talking a bit about how they work.

First, there's the matter of *voicing* - choosing exactly which
notes to play to make up the chosen chord. The recursive substitution
selects a chord for each bar of music, which specifies between three and six
"notes" in the sense of *pitch classes* - offsets in terms of however
many semitones from the start of the octave without specifying which octave.
For example, the C major chord consists of pitch classes 0, 4, and 7 (notes
named C, E, and G).

This sequencer uses an internal notion of six voices, so from the pitch classes, it needs to choose six specific pitches that are in particular octaves; confusingly, in music specific pitches are also traditionally called "notes" even though they are different from pitch classes. In my code I use the term "voicing" to refer to the collection of six specific pitches, which I represent using MIDI note numbers.

In Dharmapala I used a constraint solver written in Prolog to choose the voicings for the chords to meet my musical goals, running offline with a fair bit of human supervision. I didn't want to implement something like that in Javascript and try to make it run in real time, so I used a much simpler branch and bound algorithm here. It still does some clever things. The voicing for each bar is chosen to have the following properties:

- Exactly six distinct MIDI note numbers in the range 30 to 78;
- Every pitch class from the chord is included in the voicing at least once;
- Only pitch classes from the chord are included in the voicing;
- The current bar's voicing is as close as possible to the previous bar's voicing; and
- The current bar's voicing is as close as possible to a constant target voicing that is defined by the groove.

Distance between voicings is defined by sorting them and then taking the
L_{1} metric (sum of absolute differences), so that for instance the
distance between (1,2,3) and (1,3,7) is 5. Each groove specifies, as well
as the constant target voicing, the relative weights to be applied to the
distance from the previous bar and the distance from the target. The branch
and bound algorithm runs to find the voicing that minimizes the weighted
distance while obeying the other constraints, with ties broken
arbitrarily.

The point of the "constant target voicing" is to allow different grooves to aim for different pitch ranges and open or closed harmony styles. For instance, the voicing target for the "Discotheque" groove is (30,31,32,66,69,72), which encourages the three lowest voices to be as low as possible, while the other three will be higher and fairly close to each other. The rhythmic patterns for this groove play the bottom three voices as bass notes and the top three as blips of chords. The "Node Rums" groove, on the other hand, uses a voicing target of (40,45,50,59,64); its chords will be nearer the middle of the pitch range, and will tend toward more open harmony. Despite being the same chords in the sense of containing the same pitch classes, chords in these two grooves will sound different from each other.

Given a voicing, the sequencer chooses a pattern for the bar. Each groove contains several patterns specifying samples to play at specific beats in the bar, including both unpitched drum samples and pitched samples that are parameterized by notes from the voicing. A single pattern might say "play notes 1, 2, and 3 from the voicing using this sample set on beats 1 and 3; play notes 4, 5, and 6 from the voicing using that sample set on beats 2 and 4; and play the kick drum sample on beats 1, 2, 3, and 4." Each groove also contains a list of rules specifying when to play the different patterns, with conditions like "on the final bar of the substitution rule," "with such-and-such probability," and "on bar numbers congruent to zero modulo k." The end result is that the rhythms can be fairly complex despite being generated by simple logic.

Planning out the grooves and finding appropriate samples for them was fun, but also a lot of work, which is why I ended up only defining six choices. I think they nonetheless do a reasonable job of covering a range of musical styles. Building a similar Web-based toy with more focus on user control of the groove might be interesting, but wasn't my main interest here; I was more interested in building a way for visitors to explore fractal chord sequences and the group-theory stuff.

Every time I write about a way of generating sequences, whether it's
fractal chords, hypercube
walks, or something else, I get the question of whether I'm going to
build and sell a module to do it. This one is probably a better candidate
for that than some of the others, but still not a *great* candidate.
I discuss this kind of issue, and other ideas for future products, a lot in
my weekly Twitch stream. I
think the fractal sequencer would need to have a lot of front-panel
controls, and it would need to be a digital module, with a lot of effort
going into programming the firmware; both those things mean it would be
expensive. I would need to be sure that I could sell a significant number
of them at at least a thousand dollars each (quite possibly more) and even
if there are a lot of people who will enjoy poking at the fractal sequencer
in a Web browser for a few minutes *for free*, there are fewer who
would really spend the money for a permanent hardware device just to do
it. Nonetheless, I'll be interested to see whether this Web page version
attracts attention and interest. There's certainly more that can be done
with the fractal substitution and group-based chord transformation concepts.

◀ PREV All about normalling || Do you really want that scope? NEXT ▶

## Comments

**Matthew Skala - 2022-05-22**

**Darryl McGee - 2022-06-01**

**Alan - 2022-06-02**

Steve Cournane - 2022-05-22