slippery chicken documentation - tonal composition with sc

## Tonal composition with slippery chicken

### + Associated example files

- tonal-algo-example.lsp
- tonal.mid
- tonal.eps
- _tonal-example-score.pdf

close

slippery chicken was not explicitly designed to produce tonal music. However, with a bit of planning and some careful programming, the software can be used to algorithmically generate tonal compositions as well.

The approach used in this demo composition defines 17 fixed, polyphonic fragments that can be transposed, interchanged, and interconnected in a kind of modular composition technique. These modules are then assembled algorithmically using a repeatable pseudo-random function together with the `get-linear-sequence` method of the `l-for-lookup` class.

### + The modules: 3- and 4-voiced improvisation patterns

The modules that serve as the building blocks for this piece are based on an approach to classical keyboard improvisation and voice-oriented (rather than harmony-based) musical analysis taught to by Volkhardt Preuss at the Hochschule für Musik und Theater in Hamburg, Germany.

This method collects fundamental musical structures into five basic categories: Fauxbourdon (parallel triads in first inversion, often with 7-6 suspensions), Ruggiero (Dominant-Tonic cadences), Sekundakkord (Dominant-seventh chords with the 7 in the bass), Orgelpunkt (pedal-point sequences over a sustained bass), and Terzfall (falling third sequences). The first four of these have been implemented in this piece.

In this categorical approach, the five pattern types are first reduced and presented as core sequences, in which all of the voices progress in simultaneous half-note motion. This half-note basis can then be extended and elaborated (possibly over several measures) to create more fluid music. The demo composition in this tutorial sticks to just the short, core progressions with half-note motion.

A core fauxbourdon with no suspensions

An elaborated version of the same fauxbourdon with octave-displaced voice-crossings (from Bach's WTK I, Prelude 2)

close

### + sc's pitch-selection algorithm and voice-leading

slippery chicken's automatic pitch-selection algorithm was designed to produce atonal music, and it needs the use of some creative constraints to get it to produce tonal melodies with traditional voice-leading.

Because slippery chicken uses the same pitch set for all players in any given sequence, the approach taken here is to confine each set to different subsets for each player in each sequence using the `set-limits-high` and `set-limits-low` slots, thereby enabling an exact mapping of the numbers in each `pitch-seq` to specific pitches of the current set.

The code for this composition applies this technique once for each `rthm-seq`, and then transposes the pitch sets using the `transposition` slot of the `set-palette` object, thereby ensuring that the same scale degrees are selected for the pitches of each `rthm-seq` when that `rthm-seq` is repeated in conjunction with different sets.

close

### + Converting note-names to pitch-seq numbers

A small function has been written for this piece that makes it easier to determine the numbers required for the tonal `pitch-seqs`. It takes as its two arguments a list of note-name symbols that are to be converted into `pitch-seq` numbers, and the "source" list of note-name symbols to which the `pitch-seq` numbers are to be applied.

This function allows the user to enter note-name symbols directly, which are then automatically converted into `pitch-seq` numbers, rather than counting through all the pitches in the set or subset to determine which numbers are needed in order to produce them. The function requires that the `:avoid-melodic-octaves` and `:avoid-used-notes` arguments of the `make-slippery-chicken` function are both set to `NIL` in order to work properly.

Every pitch in the first list must be present in the "source" list (second argument) to prevent errors. Enharmonically equivalent pitches are not considered equal; the note-name symbols must be exact (i.e. `GS4` must be written as `GS4` and not `AF4`). The function then determines the resulting `pitch-seq` numbers by returning the `position` (index number) of each specified pitch in the source set and subtracting the required offset so that the lowest pitch is always `1`.

    (defun pitches-to-pseq (pitch-list set)
      (let* (positions lowest pseq)
        (setf positions (mapcar #'(lambda (x) (position x set)) pitch-list))
        (setf lowest (1- (first (sort (copy-list positions) #'<))))
        (setf pseq (mapcar #'(lambda (x) (- x lowest)) positions))
        pseq))

    SC> (pitches-to-pseq '(c4 e4 g4 f4 d4 e4 c4) '(a3 b3 c4 d4 e4 f4 g4 a4))
    (1 3 5 4 2 3 1)

close

### + Generating the set-palette with :transposition

#### Core sets

The code for this piece uses two primary sets: one that is predominantly major, with chromatic passing pitches, and one that is predominantly minor, also with chromatic passing pitches. These are defined at the top of the variable declarations within the `let*` enclosure. Since the `pitches-to-pseq` function requires exact note-name symbols, the sets contain both enharmonic spellings of some of the pitches, such as `fs4` and `gf4`.

           (core-set-maj '(g2 a2 bf2 b2 c3 d3 ef3 e3 f3 g3 a3 b3 c4 cs4 d4 ef4 e4
                           f4 fs4 gf4 g4 gs4 af4 a4 bf4 b4 c5 d5 e5 f5 fs5 g5 b5
                           c6))
           (core-set-min '(g2 af2 bf2 c3 ef3 f3 fs3 g3 af3 bf3 b3 c4 d4 ef4 e4 f4
                           fs4 gf4 g4 af4 a4 bf4 b4 c5 ef5 e5 f5))

#### Using a loop to create the set-palette

The following loop is used to create the `set-palette` and assign it to the variable `sp`:

           (sp
            (loop for i from 0 to 11
               if (= i 0)
               collect (list "0-MAJ" (list core-set-maj))
               and collect (list "0-MIN" (list core-set-min))
               else
               collect (list (format nil "~a-MAJ" i)
                             (list "0-MAJ" ':transposition i))
               and collect (list (format nil "~a-MIN" i)
                                 (list "0-MIN" ':transposition i))))

#### The :transposition slot

The `set-palette` is assembled automatically in the loop by collecting 12 transpositions (from `0` to `11` semitones) of each of the `core-set-` variables declared above. The integer value passed to the `:transposition` slot of a set within a `set-palette` object will automatically transpose the source set by that many semitones.

Assembling the `set-palette` in this way means there will be one major and one minor set for each of the 12 chromatic pitch-classes (`0` = C, `1` = C-sharp, `2` = D, etc.). Modulating to a different key within the piece, then, is made possible by selecting the corresponding set in the `set-map`.

#### Using strings as IDs

The IDs for the individual sets of this `set-palette` are strings, such as `"0-MAJ"` or `"0-MIN"`, rather than the numbers or symbols used in the other tutorials. This allows for easier concatenation of numbers and symbols when automatically assembling the `set-palette` within the `loop` macro.

The same number used for the semitone transposition is combined with either `"-MAJ"` or `"-MIN"` to create the ID for the given set.

The resulting `set-palette` would thus look like this, if written out in full:

    (("0-MAJ"
      ((G2 A2 BF2 B2 C3 D3 EF3 E3 F3 G3 A3 B3 C4 CS4 D4 EF4 E4 F4 FS4 GF4 G4
        GS4 AF4 A4 BF4 B4 C5 D5 E5 F5 FS5 G5 B5 C6)))
     ("0-MIN"
      ((G2 AF2 BF2 C3 EF3 F3 FS3 G3 AF3 BF3 B3 C4 D4 EF4 E4 F4 FS4 GF4 G4 AF4
        A4 BF4 B4 C5 EF5 E5 F5)))
     ("1-MAJ" ("0-MAJ" :TRANSPOSITION 1))
     ("1-MIN" ("0-MIN" :TRANSPOSITION 1))
     ("2-MAJ" ("0-MAJ" :TRANSPOSITION 2))
     ("2-MIN" ("0-MIN" :TRANSPOSITION 2))
     ("3-MAJ" ("0-MAJ" :TRANSPOSITION 3))
     ("3-MIN" ("0-MIN" :TRANSPOSITION 3))
     ("4-MAJ" ("0-MAJ" :TRANSPOSITION 4))
     ("4-MIN" ("0-MIN" :TRANSPOSITION 4))
     ("5-MAJ" ("0-MAJ" :TRANSPOSITION 5))
     ("5-MIN" ("0-MIN" :TRANSPOSITION 5))
     ("6-MAJ" ("0-MAJ" :TRANSPOSITION 6))
     ("6-MIN" ("0-MIN" :TRANSPOSITION 6))
     ("7-MAJ" ("0-MAJ" :TRANSPOSITION 7))
     ("7-MIN" ("0-MIN" :TRANSPOSITION 7))
     ("8-MAJ" ("0-MAJ" :TRANSPOSITION 8))
     ("8-MIN" ("0-MIN" :TRANSPOSITION 8))
     ("9-MAJ" ("0-MAJ" :TRANSPOSITION 9))
     ("9-MIN" ("0-MIN" :TRANSPOSITION 9))
     ("10-MAJ" ("0-MAJ" :TRANSPOSITION 10))
     ("10-MIN" ("0-MIN" :TRANSPOSITION 10))
     ("11-MAJ" ("0-MAJ" :TRANSPOSITION 11))
     ("11-MIN" ("0-MIN" :TRANSPOSITION 11)))

close

### + Using the l-for-lookup class for harmonic progressions

The `l-for-lookup` class has a method called `get-linear-sequence` which lends itself to the generation of harmonic progressions. Instead of using the rules of a standard `l-for-lookup` (Lindenmayer System) object to create its resulting list, it uses the items retrieved from the data associated with each key as the ID for the next look-up. All of the items in the data lists must therefore also be present as keys.

Each time a particular key-data pair is accessed, the method selects the next item in the data list associated with the given key. When it has used the last item in a data list, it cycles around and begins at the top of the list the next time that key-data pair is accessed.

The `l-for-lookup` object and call to `get-linear-sequence` in this simple example here illustrate this method:

    (let ((lfl (make-l-for-lookup 'lfl
                                  '((1 ((2 3)))
                                    (2 ((1)))
                                    (3 ((1 2))))
                                  nil)))
      (get-linear-sequence lfl 1 30))

    => (1 2 1 3 1 2 1 3 2 1 2 1 3 1 2 1 3 2 1 2 1 3 1 2 1 3 2 1 2 1)

The `rules` slot of the `l-for-lookup` object can be set to `NIL` when used with `get-linear-sequence`, since this method does not use that slot. The call to `get-linear-sequence` states the name of the object to access, the first ID to use as a look-up key (a.k.a. the "seed" or "axiom"; `1` in this example), and the length of the list to return (`30` here).

The method then gets the first item in the data list associated with the seed argument, which in this example is `2`, and uses that item as the look-up key to get the next item. The only item in the list associated with key `2` in this example is `1`. The number `1` is then used again here as the look-up key, but this time it gets the next item from the associated data list: `3`. Now that all items associated with key `1` have been used, the next time `1` is used as a look-up key, it will select the first item of the list again, namely `2`, and so on.

#### The procedure for this piece

The procedure used to generate the sequence of modules in this piece (i.e. the `rthm-seq-map`) function similarly. Instead of using numbers, however, the keys consist of symbols that identify the different module types, and the associated data consist of symbols that identify the module types to which each given module type may progress. The key-data items of this initial object, and the resulting list, are used later as keys again to look up data from two further association lists, namely `transposition-rules-al` and `combos-al`.

The symbol names for each of the module types here are created from their kind, their variation, and their modality (major, minor, starting major but ending minor, etc.). They each represent groups of modules, as defined in the `combos-al` variable below. Each group may have one or more possible combination of voices (e.g., the cantizans may appear in the soprano voice in one combination, but in the alto voice in another, etc.)

           (seq-rules
            (make-l-for-lookup 'seq-rules
                               '((fauxbourdon-a-maj
                                  ((ruggiero-a-maj ruggiero-b-maj
                                    ruggiero-b-maj-to-min ruggiero-c-maj)))
                                 (fauxbourdon-a-min
                                  ((ruggiero-a-min ruggiero-d-min-to-maj)))
                                 (ruggiero-a-maj
                                  ((fauxbourdon-a-maj sekund-a-maj ped-a-maj)))
                                 (ruggiero-a-min
                                  ((fauxbourdon-a-min sekund-a-min)))
                                 (ruggiero-b-maj
                                  ((fauxbourdon-a-maj sekund-a-maj ped-a-maj)))
                                 (ruggiero-b-maj-to-min
                                  ((fauxbourdon-a-min sekund-a-min)))
                                 (ruggiero-c-maj
                                  ((fauxbourdon-a-maj sekund-a-maj ped-a-maj)))
                                 (ruggiero-d-min-to-maj
                                  ((fauxbourdon-a-maj sekund-a-maj ped-a-maj)))
                                 (ruggiero-e-maj
                                  ((fauxbourdon-a-maj sekund-a-maj ped-a-maj)))
                                 (sekund-a-maj
                                  ((ruggiero-e-maj)))
                                 (sekund-a-min
                                  ((ruggiero-a-min ruggiero-d-min-to-maj)))
                                 (ped-a-maj
                                  ((sekund-a-maj))))
                               nil))

#### Getting the linear sequence

The sequence of modules is then created by calling the `get-linear-sequence` method with the symbol `fauxbourdon-a-maj` as the seed, and a list length of `num-seqs`, which is the first variable declared in this `let*` enclosure (`29` here). The resulting list is stored in the variable `seq-seq-`.

           (seq-seq (get-linear-sequence seq-rules 'fauxbourdon-a-maj num-seqs))

The resulting sequence of modules in this instance is:

    (FAUXBOURDON-A-MAJ RUGGIERO-A-MAJ FAUXBOURDON-A-MAJ RUGGIERO-B-MAJ
     FAUXBOURDON-A-MAJ RUGGIERO-B-MAJ-TO-MIN FAUXBOURDON-A-MIN RUGGIERO-A-MIN
     FAUXBOURDON-A-MIN RUGGIERO-D-MIN-TO-MAJ FAUXBOURDON-A-MAJ RUGGIERO-C-MAJ
     FAUXBOURDON-A-MAJ RUGGIERO-A-MAJ SEKUND-A-MAJ RUGGIERO-E-MAJ
     FAUXBOURDON-A-MAJ RUGGIERO-B-MAJ SEKUND-A-MAJ RUGGIERO-E-MAJ SEKUND-A-MAJ
     RUGGIERO-E-MAJ PED-A-MAJ SEKUND-A-MAJ RUGGIERO-E-MAJ FAUXBOURDON-A-MAJ
     RUGGIERO-B-MAJ-TO-MIN SEKUND-A-MIN RUGGIERO-A-MIN)

#### Adding a coda

This particular sequence, created using a list length of `29`, generates a sequence that ends with a V-I cadence (a ruggiero module). However, not all list lengths will generate lists with a ruggiero as their last element; a length of `30`, for example, would generate a sequence that ends with `SEKUND-A-MIN`, and the piece would sound like it gets cut off in the middle of a phrase.

To remedy this, a small loop is used to generate a coda if necessary. The loop looks at the last item in the `seq-seq` list, and if it does not start with the characters `RUG`, it collects a new linear sequence of module symbol names, using the same rules as above, until a ruggiero is reached. It saves this new short list to the variable `coda`, which is then appended to the end of the `seq-seq`. The sequence is now complete and will end with a V-I cadence.

           (coda
            (loop
               with l = (first (last seq-seq))
               until (equalp (subseq (format nil "~a" l) 0 3)
                             "RUG")
               do
                 (setf l (first (last (get-linear-sequence seq-rules l 2))))
               collect l))
           (seq-seq (append seq-seq coda))

close

### + An assoc-list object to store transposition rules

A number of the modules selected for this particular `slippery-chicken` object modulate to different keys and different modes (major or minor). The `ruggiero-b-maj-to-min` module, for example, starts on the V (Dominant) of a given major key and uses a musical sequence to modulate to the minor key three half-steps higher (e.g. from C major to E-flat minor).

Each consecutive set chosen for the `set-map` is therefore dependent on whether the previous module modulates or not. Accordingly, then, a list of transposition rules are first collected into an association list (an `assoc-list` object), and each of the symbol names defined for each module in the `l-for-lookup` object above are once again used as keys to store lists of two items: a positive or negative integer to determine the number of half-steps by which the piece is to modulate at the end of each module, and a symbol to indicate whether the new key is to be major or minor. This `assoc-list` object is stored in the variable `transposition-rules-al`.

           (transposition-rules-al
            (make-assoc-list 'transposition-rules
                             '((fauxbourdon-a-maj (0 maj))
                               (fauxbourdon-a-min (0 min))
                               (ruggiero-a-maj (0 maj))
                               (ruggiero-a-min (0 min))
                               (ruggiero-b-maj (3 maj))
                               (ruggiero-b-maj-to-min (3 min))
                               (ruggiero-c-maj (-3 maj))
                               (ruggiero-d-min-to-maj (0 maj))
                               (ruggiero-e-maj (0 maj))
                               (sekund-a-maj (0 maj))
                               (sekund-a-min (0 min))
                               (ped-a-maj (0 maj)))))

A small loop is then used to collect the key-change progression by calculating the transpositions associated with each of the modules listed in the `seq-seq` variable created above. To this end, each item in the `seq-seq` is consecutively used as the key to perform a look-up into the `transposition-rules-al` association list.

           (transpositions-changes
            (let ((n 0)
                  rule)
              (loop for seq in (subseq seq-seq 0 (1- (length seq-seq)))
                 do (setf rule (get-data-data seq transposition-rules-al))
                 collect (list
                          (setf n (mod (+ n (first rule)) 12))
                          (second rule)))))

The resulting list, which is stored in the variable `transpositions-changes`, consists of a series of two-item lists, each of which contain the number and symbol (`MAJ` or `MIN`) required to create the string ID of one of the sets in the `set-palette`. The loop therefore performs a cumulative summation of the corresponding transposition integers from the `transposition-rules-al` in modulo 12 to ensure that the transposition always returns a number between `0` and `11`, the first part of an existing set ID. The results for this particular piece (with 29 initial sequences) is:

    ((0 MAJ) (0 MAJ) (0 MAJ) (0 MAJ) (3 MAJ) (3 MAJ) (6 MIN) (6 MIN) (6 MIN)
     (6 MIN) (6 MAJ) (6 MAJ) (3 MAJ) (3 MAJ) (3 MAJ) (3 MAJ) (3 MAJ) (3 MAJ)
     (6 MAJ) (6 MAJ) (6 MAJ) (6 MAJ) (6 MAJ) (6 MAJ) (6 MAJ) (6 MAJ) (6 MAJ)
     (9 MIN) (9 MIN))

However, this list is just a list of the key changes that occur at the end of each module. In order to have one key for each module, the next variable, `transpositions`, pushes `(0 MAJ)` to the head of this list. There is now one key and one mode stored for each item in the `seq-seq`

           (transpositions (push '(0 MAJ) transpositions-changes))

close

### + Assembling the set-map from the transpositions list

The `set-map` is then created from the `transpositions` variable. A small loop collects a list of strings constructed by concatenating the integer from each two-item list with the corresponding symbol.

           (sm
            (loop for trnsp in transpositions
               collect (format nil "~a-~a" (first trnsp) (second trnsp))))

Each of these strings will be equal to the ID of one of the transposed sets in the `set-palette`. The resulting list is stored in the variable `sm`, which is passed directly to the `set-map` slot of the `slippery-chicken` object made below. The `set-map` for this particular sequence of 29 modules looks like this:

    ("0-MAJ" "0-MAJ" "0-MAJ" "0-MAJ" "3-MAJ" "3-MAJ" "6-MIN" "6-MIN" "6-MIN"
     "6-MIN" "6-MAJ" "6-MAJ" "3-MAJ" "3-MAJ" "3-MAJ" "3-MAJ" "3-MAJ" "3-MAJ"
     "6-MAJ" "6-MAJ" "6-MAJ" "6-MAJ" "6-MAJ" "6-MAJ" "6-MAJ" "6-MAJ" "6-MAJ"
     "9-MIN" "9-MIN")

close

### + An assoc-list object to store module combinations

As mentioned above, each module type named in the `l-for-lookup` object and the subsequent `seq-seq` variable represents a group of possible voice combinations that have the same pitch, rhythm, and harmonic structure. These combinations are defined in another `assoc-list` object here and assigned to the variable `combos-al`:

           (combos-al
            (make-assoc-list
             'combos
             '((fauxbourdon-a-maj ((fx-1-maj-c fx-1-maj-a fx-1-maj-t 2-rest)
                                   (fx-1-maj-c fx-1-maj-a 2-rest fx-2-maj-t)
                                   (fx-3-maj-c fx-1-maj-c 2-rest fx-2-maj-t)))
               (fauxbourdon-a-min ((fx-1-min-c fx-1-min-a fx-1-min-t 2-rest)
                                   (fx-1-min-c fx-1-min-a 2-rest fx-2-min-t)))
               (ruggiero-a-maj ((rg-1-maj-c rg-1-maj-a rg-1-maj-t 2-rest)))
               (ruggiero-a-min ((rg-1-min-c rg-1-min-a rg-1-min-t 2-rest)
                                (rg-4-min-c rg-4-min-a 2-rest rg-4-min-b)))
               (ruggiero-b-maj ((rg-2-maj-c rg-2-maj-a 5-rest rg-2-maj-t)))
               (ruggiero-b-maj-to-min ((rg-2-min-c rg-2-min-a 5-rest rg-2-min-t)))
               (ruggiero-c-maj ((rg-3-maj-c rg-3-maj-a rg-3-maj-t rg-3-maj-b)))
               (ruggiero-d-min-to-maj ((rg-5-min-c rg-5-min-a rg-5-min-t
                                                   rg-5-min-b)))
               (ruggiero-e-maj ((rg-6-maj-c rg-6-maj-a 2-rest rg-6-maj-b)))
               (sekund-a-maj ((sek-1-maj-c sek-1-maj-a sek-1-maj-t sek-1-maj-b)
                              (sek-2-maj-c sek-2-maj-a sek-2-maj-t sek-2-maj-b)))
               (sekund-a-min ((sek-3-min-c sek-3-min-a sek-3-min-t sek-3-min-b)))
               (ped-a-maj ((ped-1-maj-c ped-1-maj-a ped-1-maj-t ped-1-maj-b))))))

Each key in this association list is exactly the same as the keys in the `l-for-lookup` object and the `transposition-rules-al`. The data lists associated with each key consist of the IDs of `rthm-seq` objects defined in the `rthm-seq-palette` below.

Each `rthm-seq` below consists of one voice within one of the modules. Each data item in the `combos-al` is therefore a set of four `rthm-seq` IDs, one for each player. These are first collected here in combination to make the identification easier for the programmer. They will then be disassembled and reassembled into the `rthm-seq-map` in the next two steps below.

close

### + Assembling the rthm-seq-map from the combos-al

#### Collecting the random combos first

A small loop is first used to collect the list of `rthm-seq` combinations for the subsequent `rthm-seq-map`. It passes through the list of module types stored in the `seq-seq` variable and uses each one as a look-up key into the `combos-al`. It uses slippery chicken's own `random-rep` function to select a random voice combo from the data list associated with each module type.

           (rsm-combos
            (let* (c)
              (random-rep 1 t) ; reset random state each time for same results
              (loop for s in seq-seq
                 do (setf c (get-data-data s combos-al))
                 collect
                   (nth (random-rep (length c)) c))))

The `random-rep` function has an optional argument that allows the user to reset the current Lisp's random state, allowing for the exact same list of randomly selected items to be returned each time. In this example, `random-rep` is called first, prior to the loop, so that the random state is reset. The result of this loop is stored in the `rsm-combos` variable and produces the following list for this example:

    ((FX-1-MAJ-C FX-1-MAJ-A FX-1-MAJ-T 2-REST)
     (RG-1-MAJ-C RG-1-MAJ-A RG-1-MAJ-T 2-REST)
     (FX-1-MAJ-C FX-1-MAJ-A FX-1-MAJ-T 2-REST)
     (RG-2-MAJ-C RG-2-MAJ-A 5-REST RG-2-MAJ-T)
     (FX-1-MAJ-C FX-1-MAJ-A FX-1-MAJ-T 2-REST)
     (RG-2-MIN-C RG-2-MIN-A 5-REST RG-2-MIN-T)
     (FX-1-MIN-C FX-1-MIN-A 2-REST FX-2-MIN-T)
     (RG-4-MIN-C RG-4-MIN-A 2-REST RG-4-MIN-B)
     (FX-1-MIN-C FX-1-MIN-A 2-REST FX-2-MIN-T)
     (RG-5-MIN-C RG-5-MIN-A RG-5-MIN-T RG-5-MIN-B)
     (FX-1-MAJ-C FX-1-MAJ-A FX-1-MAJ-T 2-REST)
     (RG-3-MAJ-C RG-3-MAJ-A RG-3-MAJ-T RG-3-MAJ-B)
     (FX-1-MAJ-C FX-1-MAJ-A FX-1-MAJ-T 2-REST)
     (RG-1-MAJ-C RG-1-MAJ-A RG-1-MAJ-T 2-REST)
     (SEK-2-MAJ-C SEK-2-MAJ-A SEK-2-MAJ-T SEK-2-MAJ-B)
     (RG-6-MAJ-C RG-6-MAJ-A 2-REST RG-6-MAJ-B)
     (FX-3-MAJ-C FX-1-MAJ-C 2-REST FX-2-MAJ-T)
     (RG-2-MAJ-C RG-2-MAJ-A 5-REST RG-2-MAJ-T)
     (SEK-2-MAJ-C SEK-2-MAJ-A SEK-2-MAJ-T SEK-2-MAJ-B)
     (RG-6-MAJ-C RG-6-MAJ-A 2-REST RG-6-MAJ-B)
     (SEK-1-MAJ-C SEK-1-MAJ-A SEK-1-MAJ-T SEK-1-MAJ-B)
     (RG-6-MAJ-C RG-6-MAJ-A 2-REST RG-6-MAJ-B)
     (PED-1-MAJ-C PED-1-MAJ-A PED-1-MAJ-T PED-1-MAJ-B)
     (SEK-2-MAJ-C SEK-2-MAJ-A SEK-2-MAJ-T SEK-2-MAJ-B)
     (RG-6-MAJ-C RG-6-MAJ-A 2-REST RG-6-MAJ-B)
     (FX-1-MAJ-C FX-1-MAJ-A FX-1-MAJ-T 2-REST)
     (RG-2-MIN-C RG-2-MIN-A 5-REST RG-2-MIN-T)
     (SEK-3-MIN-C SEK-3-MIN-A SEK-3-MIN-T SEK-3-MIN-B)
     (RG-1-MIN-C RG-1-MIN-A RG-1-MIN-T 2-REST))

#### Separating the list of combos into a list for the rthm-seq-map

The next little loop then parses the `rsm-combos` list into separate lists for each player, with the syntax necessary to make a `rthm-seq-map` object, and stores the resulting list in the variable `rsm`. This variable will then be used directly within the call to `make-slippery-chicken`.

           (rsm
            (loop for p in '(vo vt va vc)
               for n from 0
               collect
                 (list p
                       (flatten
                        (loop for c in rsm-combos
                           collect
                             (list (nth n c)))))))

The result of this loop for this example is as follows:

    ((VO
      (FX-1-MAJ-C RG-1-MAJ-C FX-1-MAJ-C RG-2-MAJ-C FX-1-MAJ-C RG-2-MIN-C
       FX-1-MIN-C RG-4-MIN-C FX-1-MIN-C RG-5-MIN-C FX-1-MAJ-C RG-3-MAJ-C
       FX-1-MAJ-C RG-1-MAJ-C SEK-2-MAJ-C RG-6-MAJ-C FX-3-MAJ-C RG-2-MAJ-C
       SEK-2-MAJ-C RG-6-MAJ-C SEK-1-MAJ-C RG-6-MAJ-C PED-1-MAJ-C SEK-2-MAJ-C
       RG-6-MAJ-C FX-1-MAJ-C RG-2-MIN-C SEK-3-MIN-C RG-1-MIN-C))
     (VT
      (FX-1-MAJ-A RG-1-MAJ-A FX-1-MAJ-A RG-2-MAJ-A FX-1-MAJ-A RG-2-MIN-A
       FX-1-MIN-A RG-4-MIN-A FX-1-MIN-A RG-5-MIN-A FX-1-MAJ-A RG-3-MAJ-A
       FX-1-MAJ-A RG-1-MAJ-A SEK-2-MAJ-A RG-6-MAJ-A FX-1-MAJ-C RG-2-MAJ-A
       SEK-2-MAJ-A RG-6-MAJ-A SEK-1-MAJ-A RG-6-MAJ-A PED-1-MAJ-A SEK-2-MAJ-A
       RG-6-MAJ-A FX-1-MAJ-A RG-2-MIN-A SEK-3-MIN-A RG-1-MIN-A))
     (VA
      (FX-1-MAJ-T RG-1-MAJ-T FX-1-MAJ-T 5-REST FX-1-MAJ-T 5-REST 2-REST 2-REST
       2-REST RG-5-MIN-T FX-1-MAJ-T RG-3-MAJ-T FX-1-MAJ-T RG-1-MAJ-T
       SEK-2-MAJ-T 2-REST 2-REST 5-REST SEK-2-MAJ-T 2-REST SEK-1-MAJ-T 2-REST
       PED-1-MAJ-T SEK-2-MAJ-T 2-REST FX-1-MAJ-T 5-REST SEK-3-MIN-T
       RG-1-MIN-T))
     (VC
      (2-REST 2-REST 2-REST RG-2-MAJ-T 2-REST RG-2-MIN-T FX-2-MIN-T RG-4-MIN-B
       FX-2-MIN-T RG-5-MIN-B 2-REST RG-3-MAJ-B 2-REST 2-REST SEK-2-MAJ-B
       RG-6-MAJ-B FX-2-MAJ-T RG-2-MAJ-T SEK-2-MAJ-B RG-6-MAJ-B SEK-1-MAJ-B
       RG-6-MAJ-B PED-1-MAJ-B SEK-2-MAJ-B RG-6-MAJ-B 2-REST RG-2-MIN-T
       SEK-3-MIN-B 2-REST)))

close

### + set-limits for the C-transpositions of the rthm-seqs

The next three variables form the core of this modular approach to creating tonal music with slippery chicken, and they involve the `set-limits-high` and `set-limits-low` slots of the `slippery-chicken` object.

By constraining the current set for each player in every sequence of the piece and setting the `:avoid-melodic-octaves` and `:avoid-used-notes` keyword arguments of the `make-slippery-chicken` function to `NIL`, the user can enable an exact mapping of the `pitch-seq` numbers of the `rthm-seq` objects to specific pitches in the current set.

#### Defining the pitch limits and storing them in an assoc-list

This demo piece does this by first creating an `assoc-list` object that stores the lowest and highest pitch of each `rthm-seq` in its C (0) transposition. Each key in this association list (which is assigned to the variable `lims-al`) is identical to the ID of one of the `rthm-seqs` defined in the `rthm-seq-palette` below.

           (lims-al
            (make-assoc-list 'set-lims
                             '((2-rest (a4 a4))
                               (5-rest (a4 a4))
                               (fx-1-maj-c (fs4 a4))
                               (fx-1-maj-a (b3 e4))
                               (fx-1-maj-t (g3 c4))
                               (fx-1-min-c (fs4 af4))
                               (fx-1-min-a (b3 ef4))
                               (fx-1-min-t (g3 c4))
                               (fx-2-maj-t (g2 c3))
                               (fx-2-min-t (g2 c3))
                               (fx-3-maj-c (b4 e5))
                               (rg-1-maj-c (b4 c5))
                               (rg-1-maj-a (c4 g4))
                               (rg-1-maj-t (c3 g3))
                               (rg-1-min-c (b4 c5))
                               (rg-1-min-a (c4 g4))
                               (rg-1-min-t (c3 g3))
                               (rg-2-maj-c (ef4 c5))
                               (rg-2-maj-a (c4 f4))
                               (rg-2-maj-t (bf2 g3))
                               (rg-2-min-c (ef4 c5))
                               (rg-2-min-a (c4 f4))
                               (rg-2-min-t (bf2 g3))
                               (rg-3-maj-c (gs4 c5))
                               (rg-3-maj-a (e4 g4))
                               (rg-3-maj-t (b3 e4))
                               (rg-3-maj-b (a2 a3))
                               (rg-4-min-c (b4 c5))
                               (rg-4-min-a (c4 g4))
                               (rg-4-min-b (g2 g3))
                               (rg-5-min-c (b4 c5))
                               (rg-5-min-a (e4 g4))
                               (rg-5-min-t (c4 d4))
                               (rg-5-min-b (g2 af3))
                               (rg-6-maj-c (c5 g5))
                               (rg-6-maj-a (b4 c5))
                               (rg-6-maj-b (c3 g3))
                               (sek-1-maj-c (e5 f5))
                               (sek-1-maj-a (c5 c5))
                               (sek-1-maj-t (f4 g4))
                               (sek-1-maj-b (a2 c3))
                               (sek-2-maj-c (e5 g5))
                               (sek-2-maj-a (c5 d5))
                               (sek-2-maj-t (g4 a4))
                               (sek-2-maj-b (b2 c3))
                               (sek-3-min-c (ef5 f5))
                               (sek-3-min-a (c5 c5))
                               (sek-3-min-t (f4 g4))
                               (sek-3-min-b (af2 c3))
                               (ped-1-maj-c (c5 c5))
                               (ped-1-maj-a (g4 a4))
                               (ped-1-maj-t (e4 f4))
                               (ped-1-maj-b (c3 c3)))))

#### Creating the set-limits- lists

A small loop is then used to collect just the pitches, in MIDI-note number form, for the `set-limits-low` and `set-limits-high` slots for every sequence and every player in the piece. It collects them as MIDI-note numbers in order to facilitate their transposition in the next step.

           (lims-lo-hi
            (loop for n from 0 to 1
               collect
                 (loop for p in rsm
                    collect
                      (loop for rs in (second p)
                         collect (note-to-midi
                                  (nth n (get-data-data rs lims-al)))))))

The list created consists of two lists, one for the low set limits and one for the high set limits, each of those lists in turn containing a list of pitches for each player, with one pitch for each sequence. This list is assigned to the variable `lims-lo-hi`. The result of this list in this instance with 29 sequences looks like this:

    (((66 71 66 63 66 63 66 71 66 71 66 68 66 71 76 72 71 63 76 72 76 72 72 76
       72 66 63 75 71)
      (59 60 59 60 59 60 59 60 59 64 59 64 59 60 72 71 66 60 72 71 72 71 67 72
       71 59 60 72 60)
      (55 48 55 69 55 69 69 69 69 60 55 59 55 48 67 69 69 69 67 69 65 69 64 67
       69 55 69 65 48)
      (69 69 69 46 69 46 43 43 43 43 69 45 69 69 47 48 43 46 47 48 45 48 48 47
       48 69 46 44 69))
     ((69 72 69 72 69 72 68 72 68 72 69 72 69 72 79 79 76 72 79 79 77 79 72 79
       79 69 72 77 72)
      (64 67 64 65 64 65 63 67 63 67 64 67 64 67 74 72 69 65 74 72 72 72 69 74
       72 64 65 72 67)
      (60 55 60 69 60 69 69 69 69 62 60 64 60 55 69 69 69 69 69 69 67 69 65 69
       69 60 69 67 55)
      (69 69 69 55 69 55 48 55 48 56 69 57 69 69 48 55 48 55 48 55 48 55 48 48
       55 69 55 48 69)))

close

### + Transposing the set-limits- curves

Since some of the modules in this piece result in transpositions, as addressed above, the set limits too must be transposed in order to accurately apply to the transposed sets. This is done conveniently using a small loop, in which the integer from each two-item sublist of the `transpositions` variable is accessed and added to the MIDI-note numbers in the `lims-lo-hi` list.

           (transposed-lims-lo-hi
            (loop for hl in lims-lo-hi
               collect
                 (loop for p in hl
                    for pl in '(vo vt va vc)
                    collect
                      (list pl
                            (loop for n in p
                               for i in transpositions
                               for x from 1
                               collect x
                               collect (+ n (first i)))))))

This loop also adds the player ID and the sequence number for each pitch limit to its output, ensuring that the resulting list has two items at the top level: A properly-formatted list for both `set-limits-low` and `set-limits-high`, including player IDs and lists of x-y break-point pairs, that can be passed directly to the `set-limits-low` and `-high` slots from within the `make-slippery-chicken` function below.

    (((VO
       (1 66 2 71 3 66 4 63 5 69 6 66 7 72 8 77 9 72 10 77 11 72 12 74 13 69
        14 74 15 79 16 75 17 74 18 66 19 82 20 78 21 82 22 78 23 78 24 82 25
        78 26 72 27 69 28 84 29 80))
      (VT
       (1 59 2 60 3 59 4 60 5 62 6 63 7 65 8 66 9 65 10 70 11 65 12 70 13 62
        14 63 15 75 16 74 17 69 18 63 19 78 20 77 21 78 22 77 23 73 24 78 25
        77 26 65 27 66 28 81 29 69))
      (VA
       (1 55 2 48 3 55 4 69 5 58 6 72 7 75 8 75 9 75 10 66 11 61 12 65 13 58
        14 51 15 70 16 72 17 72 18 72 19 73 20 75 21 71 22 75 23 70 24 73 25
        75 26 61 27 75 28 74 29 57))
      (VC
       (1 69 2 69 3 69 4 46 5 72 6 49 7 49 8 49 9 49 10 49 11 75 12 51 13 72
        14 72 15 50 16 51 17 46 18 49 19 53 20 54 21 51 22 54 23 54 24 53 25
        54 26 75 27 52 28 53 29 78)))
     ((VO
       (1 69 2 72 3 69 4 72 5 72 6 75 7 74 8 78 9 74 10 78 11 75 12 78 13 72
        14 75 15 82 16 82 17 79 18 75 19 85 20 85 21 83 22 85 23 78 24 85 25
        85 26 75 27 78 28 86 29 81))
      (VT
       (1 64 2 67 3 64 4 65 5 67 6 68 7 69 8 73 9 69 10 73 11 70 12 73 13 67
        14 70 15 77 16 75 17 72 18 68 19 80 20 78 21 78 22 78 23 75 24 80 25
        78 26 70 27 71 28 81 29 76))
      (VA
       (1 60 2 55 3 60 4 69 5 63 6 72 7 75 8 75 9 75 10 68 11 66 12 70 13 63
        14 58 15 72 16 72 17 72 18 72 19 75 20 75 21 73 22 75 23 71 24 75 25
        75 26 66 27 75 28 76 29 64))
      (VC
       (1 69 2 69 3 69 4 55 5 72 6 58 7 54 8 61 9 54 10 62 11 75 12 63 13 72
        14 72 15 51 16 58 17 51 18 58 19 54 20 61 21 54 22 61 23 54 24 54 25
        61 26 75 27 61 28 57 29 78))))

close

### + Variables for repetition in the rthm-seqs

The rhythms used in the `rhtm-seq` objects to create each voice of each module are highly repetitive. In order to make the rather long `rthm-seq-palette` both more efficient and more intelligible, a series of variables are created that not only store the more frequent rhythm combinations but also give them more recognizable names based on their function. In a few cases, the same rhythm combinations are given more than one variable name, as they serve more than one voice-leading function within the tonal modules that follow.

The time signature (`ts`) and ten "bare" (i.e., without a function ascribed to them) rhythms are defined (`r-0` to `r-9`). These are then turned into longer sequences using Lisp's backquote and at-comma syntax for list splicing.

The terms "cantus", "altus", "tenor", and "bassus" are used to indicate the four voices, and the terms "cantizans", "altizans", "tenorizans", and "bassizans" are used to denote specific voice-leading structures.

           ;; time signature
           (ts '((4 4)))
           ;; basic rest rhythm
           (r-0 '((w)))
           ;; various multi-bar rest sequences
           (2-bars-rest-ts `((,@ts ,@r-0) ,r-0))
           (5-bars-rest-ts `((,@ts ,@r-0) ,r-0 ,r-0 ,r-0 ,r-0))
           ;; first three bare (functionless) rhythm sequences
           (r-1 '(q h q))
           (r-2 '(+q q h))
           (r-3 '(h h))
           ;; BASIC FAUXBOURDON RHYTHM SEQ
           ;; assigning functions (as variable names) to bare rhythm sequences
           (5-6-sus-7-6 `(,@r-1))
           (tie-to-cantizans `(,@r-2))
           ;; creating variables for fauxbourdon voices
           (sus-7-6-to-half-cadence-cntzns-ts `((,@ts ,@5-6-sus-7-6)
                                                ,tie-to-cantizans))
           (four-halves-to-half-cadence-altzns-tnzns-ts `((,@ts ,@r-3) ,r-3))
           ;; fourth and fifth bare rhythms
           (r-4 '(w))
           (r-5 '(- e e - q h))
           ;; BASIC 2-BAR RUGGIERO RHYTHM SEQ
           ;; assigning functions (as variable names) to bare rhythm sequences
           (cantizans-interruptus `(,@r-1))
           (whole `(,@r-4))
           ;; creating variables for 2-bar ruggiero voices
           (2-bar-cadence-cantizans-ts `((,@ts ,@cantizans-interruptus) ,whole))
           (2-bar-cadence-tenorizans-ts `((,@ts ,@r-5) ,whole))
           (2-bar-cadence-bassizans-ts `((,@ts ,@whole) ,whole))
           ;; sixth bare rhythm
           (r-6 '(q q h))
           ;; assigning functions (as variable names) to bare rhythm sequences
           (tenorizans-interruptus-1 `(,@r-2))
           (tenorizans-interruptus-2 `(,@r-6))
           ;; BASIC 5-BAR FALLING-5THS RUGGIERO SEQUENCE
           ;; creating variables for 5-bar falling-5ths ruggiero voices
           (5-bars-falling-fifths-cntzns-tnzs-ts
            `((,@ts ,@cantizans-interruptus) ,tenorizans-interruptus-1
              ,cantizans-interruptus ,tenorizans-interruptus-1 ,whole))
           (5-bars-falling-fifths-tnzs-cntzns-ts
            `((,@ts ,@tenorizans-interruptus-2) ,cantizans-interruptus
              ,tenorizans-interruptus-1 ,cantizans-interruptus ,whole))
           (5-bars-falling-fifths-bsszns-ts
            `((,@ts ,@whole) ,whole ,whole ,whole ,whole))
           ;; seventh bare rhythm
           (r-7 '(h. q))
           ;; 3-BAR RUGGIERO IV-I-V-I MODULATION SEQUENCE
           ;; creating variables for 3-bar ruggiero IV-I-V-I modulation voices
           (two-halves `(,@r-3))
           ;; eighth and ninth bare rhythms
           (r-8 '(q q q q))
           (r-9 '(q q q. e))
           ;; NEIGHBOR ELABORATIONS FOR RUGGIERO VOICES
           ;; creating elaborated upper-/lower-neighbor 2-bar bassizans
           (2-bar-upper-lower-neighbor-octave-bassizans-ts `((,@ts ,@r-8) ,whole))
           ;; creating elaborated lower-neighbor 2-bar altizans and tenorizans
           (2-bar-lower-neighbor-altizans-ts `((,@ts ,@r-9) ,whole))
           (2-bar-lower-neighbor-tenorizans-ts `((,@ts ,@r-6) ,whole))
           ;; BASIC 2-BAR SEKUND-AKKORD SEQUENCE
           ;; creating variable for basic sekund-akkord sequence
           (sekund-core `((,@ts ,@r-3) ,whole))
           ;; BASIC 2-BAR PEDAL-POINT SEQUENCE
           ;; creating variables for the inner and outer voices of the basic 2-bar
           ;; pedal-point sequence
           (2-bar-pedal-sustained-outer-voices-ts `((,@ts ,@whole) ,whole))
           (2-bar-pedal-moving-inner-halves-ts `((,@ts ,@r-3) ,whole))

close

### + The call to make-slippery-chicken

The call to `make-slippery-chicken` is then also made within the `let*` enclosure, and its resulting object is stored in the variable `tonal-example`.

The majority of the keyword arguments within the function are set by using the variables defined above. Only the `rthm-seq-palette` is defined within the function itself.

           (tonal-example
            (make-slippery-chicken
             '+tonal-example+
             :title "tonal example"
             :tempo-map '((1 (q 112)))
             :ensemble '(((vo (violin :midi-channel 1))
                          (vt (violin :midi-channel 2))
                          (va (viola :midi-channel 3))
                          (vc (cello :midi-channel 4))))
             :set-palette sp
             :set-map `((1 ,sm))
             :set-limits-low (first transposed-lims-lo-hi)
             :set-limits-high (second transposed-lims-lo-hi)
             :avoid-melodic-octaves nil
             :avoid-used-notes nil
             [...]
             :rthm-seq-map `((1 ,rsm))))

close

### + The individual voices in the rthm-seq-palette

Each `rthm-seq` in the `rthm-seq-palette` then consists of one voice of one of the tonal 3- and 4-voiced modules. They are grouped together according to similar types (fauxbourdon, ruggiero etc.)

#### How the IDs are created

The IDs of these `rthm-seqs` are selected based on the module type, the variation number, the mode, and the voice. In this case, as above, the top voice is abbreviated "c" for cantus; and the remaining voices are abbreviated "a", "t", and "b" for "altus", "tenor", and "bassus". These IDs are used in the `combos-al` variable defined above when automatically generating the `rthm-seq-map`

#### Splicing in the variables for longer rhythm patterns

The majority of the `rthm-seq` objects defined here make use of the variables declared above for the multi-bar combinations of repeating rhythm patterns. They are spliced into the definition of the `rthm-seq` objects using Lisp's backquote and comma syntax.

               (fx-1-maj-c (,sus-7-6-to-half-cadence-cntzns-ts

#### Implementing the pitches-to-pseq function

The `rthm-seq` objects defined in this piece each have only one `pitch-seq` in their `pitch-seq-palette`. This one `pitch-seq` always applies to one of the two `core-set-` variables, which are both the C/0 transpositions of the given sets. By populating the `set-palette` with exact copies of the original two sets, which are merely transposed, the interval structure of each set will always remain the same, and the `pitch-seq` numbers will always return the pitch on the same scale degree in the transposed set.

The `pitch-seq` numbers are generated automatically using the `pitches-to-pseq` function defined above. Each `:pitch-seq-palette` is created by splicing the results of calling that function with specified note-name symbols (as they would apply to the C/0 transposition of the module) and the core-set variable to which they apply into the `pitch-seq-palette`, again using Lisp's backquote and comma syntax.

                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 a4 g4 fs4 g4) core-set-maj))))

The `rthm-seq-palette` in full:

             :rthm-seq-palette
             ;; The rthm-seqs: "-c" means cantus, "-a" means alto, "-t" means
             ;; tenor, "-b" means bass.
             `((2-rest (,2-bars-rest-ts))
               (5-rest (,5-bars-rest-ts))
               ;; FAUXBOURDON SEQUENCES
               ;; fauxbourdon 1 major
               (fx-1-maj-c (,sus-7-6-to-half-cadence-cntzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 a4 g4 fs4 g4) core-set-maj))))
               (fx-1-maj-a (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(e4 d4 c4 b3) core-set-maj))))
               (fx-1-maj-t (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(c4 b3 a3 g3) core-set-maj))))
               ;; fauxbourdon 1 minor
               (fx-1-min-c (,sus-7-6-to-half-cadence-cntzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 af4 g4 fs4 g4) core-set-min))))
               (fx-1-min-a (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(ef4 d4 c4 b3) core-set-min))))
               (fx-1-min-t (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(c4 bf3 af3 g3) core-set-min))))
               ;; fauxbourdon 2 major
               (fx-2-maj-t (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(c3 b2 a2 g2) core-set-maj))))
               ;; fauxbourdon 2 minor
               (fx-2-min-t (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(c3 bf2 af2 g2) core-set-min))))
               ;; fauxbourdon 3 major
               (fx-3-maj-c (,four-halves-to-half-cadence-altzns-tnzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(e5 d5 c5 b4) core-set-maj))))
               ;; RUGGIERO SEQUENCES
               ;; ruggiero 1 major
               (rg-1-maj-c (,2-bar-cadence-cantizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 b4 c5) core-set-maj))))
               (rg-1-maj-a (,2-bar-cadence-tenorizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 f4 e4 d4 c4) core-set-maj))))
               (rg-1-maj-t (,2-bar-cadence-bassizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 c3) core-set-maj))))
               ;; ruggiero 1 minor
               (rg-1-min-c (,2-bar-cadence-cantizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 b4 c5) core-set-min))))
               (rg-1-min-a (,2-bar-cadence-tenorizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 f4 ef4 d4 c4) core-set-min))))
               (rg-1-min-t (,2-bar-cadence-bassizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 c3) core-set-min))))
               ;; ruggiero 2 major
               (rg-2-maj-c (,5-bars-falling-fifths-cntzns-tnzs-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 bf4 a4 g4 a4 bf4 af4 g4 f4
                                                 ef4) core-set-maj))))
               (rg-2-maj-a (,5-bars-falling-fifths-tnzs-cntzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(f4 e4 d4 e4 f4 ef4 d4 c4 d4 ef4 d4
                                                 ef4) core-set-maj))))
               (rg-2-maj-t (,5-bars-falling-fifths-bsszns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 c3 f3 bf2 ef3) core-set-maj))))
               ;; ruggiero 2 minor
               (rg-2-min-c (,5-bars-falling-fifths-cntzns-tnzs-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 bf4 a4 g4 a4 bf4 af4 gf4 f4
                                                 ef4) core-set-maj))))
               (rg-2-min-a (,5-bars-falling-fifths-tnzs-cntzns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(f4 e4 d4 e4 f4 ef4 d4 c4 d4 ef4
                                                 d4 ef4) core-set-maj))))
               (rg-2-min-t (,5-bars-falling-fifths-bsszns-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 c3 f3 bf2 ef3) core-set-maj))))
               ;; ruggiero 3 major
               (rg-3-maj-c (((,@ts ,@cantizans-interruptus) ,whole
                             ,tie-to-cantizans)
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 bf4 a4 gs4 a4)
                                               core-set-maj))))
               (rg-3-maj-a (((,@ts ,@r-6) ,tenorizans-interruptus-1 ,two-halves)
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 g4 g4 f4 e4 e4 e4)
                                               core-set-maj))))
               (rg-3-maj-t (((,@ts ,@r-6) ,r-7 ,two-halves)
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(d4 e4 d4 d4 c4 b3 cs4)
                                               core-set-maj))))
               (rg-3-maj-b (((,@ts ,@whole) ,two-halves ,two-halves)
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 d3 a3 e3 a2) core-set-maj))))
               ;; ruggiero 4 minor
               (rg-4-min-c (,2-bar-cadence-cantizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 b4 c5) core-set-min))))
               (rg-4-min-a (,2-bar-cadence-tenorizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 f4 ef4 d4 c4) core-set-min))))
               (rg-4-min-b (,2-bar-upper-lower-neighbor-octave-bassizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 fs3 g3 g2 c3) core-set-min))))
               ;; ruggiero 5 minor
               (rg-5-min-c (,2-bar-cadence-cantizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 b4 c5) core-set-min))))
               (rg-5-min-a (,2-bar-lower-neighbor-altizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g4 fs4 g4 f4 e4) core-set-min))))
               (rg-5-min-t (,2-bar-lower-neighbor-tenorizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(d4 c4 d4 c4) core-set-min))))
               (rg-5-min-b (,2-bar-upper-lower-neighbor-octave-bassizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 af3 g3 g2 c3) core-set-min))))
               ;; ruggiero 6 major
               (rg-6-maj-c (,2-bar-cadence-tenorizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g5 f5 e5 d5 c5) core-set-maj))))
               (rg-6-maj-a (,2-bar-cadence-cantizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(b4 c5 b4 c5) core-set-maj))))
               (rg-6-maj-b (,2-bar-cadence-bassizans-ts
                            :pitch-seq-palette
                            (,(pitches-to-pseq '(g3 c3) core-set-maj))))
               ;; SEKUND SEQUENCES
               ;; sekund 1 major
               (sek-1-maj-c (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(e5 e5 f5) core-set-maj))))
               (sek-1-maj-a (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c5 c5 c5) core-set-maj))))
               (sek-1-maj-t (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(g4 g4 f4) core-set-maj))))
               (sek-1-maj-b (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c3 bf2 a2) core-set-maj))))
               ;; sekund 1 major
               (sek-2-maj-c (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(e5 fs5 g5) core-set-maj))))
               (sek-2-maj-a (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c4 d5 d5) core-set-maj))))
               (sek-2-maj-t (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(g4 a4 g4) core-set-maj))))
               (sek-2-maj-b (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c3 c3 b2) core-set-maj))))
               ;; sekund 3 minor
               (sek-3-min-c (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(ef5 e5 f5) core-set-min))))
               (sek-3-min-a (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c5 c5 c5) core-set-min))))
               (sek-3-min-t (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(g4 g4 f4) core-set-min))))
               (sek-3-min-b (,sekund-core
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c3 bf2 af2) core-set-min))))
               ;; PEDAL SEQUENCES
               ;; pedal 1 major
               (ped-1-maj-c (,2-bar-pedal-sustained-outer-voices-ts
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c5 c5) core-set-maj))))
               (ped-1-maj-a (,2-bar-pedal-moving-inner-halves-ts
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(g4 a4 g4) core-set-maj))))
               (ped-1-maj-t (,2-bar-pedal-moving-inner-halves-ts
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(e4 f4 e4) core-set-maj))))
               (ped-1-maj-b (,2-bar-pedal-sustained-outer-voices-ts
                             :pitch-seq-palette
                             (,(pitches-to-pseq '(c3 c3) core-set-maj)))))

close

### + Enharmonic spellings that reflect the tonality

By default, slippery chicken will automatically attempt to respell all of the pitches in the resulting score in a manner that makes sense in an atonal setting. The result of that automatic procedure in this example results in a number of pitches needing to be enharmonically flipped, in order to accurately reflect their function within a tonal setting.

There are three options for changing the enharmonic pitches of one or more notes in a `slippery-chicken` object: the `respell-notes`, `enharmonic`, and `enharmonics` methods. This example uses the latter two methods.

In order for these three methods to be effective, they must be called as post-generation editing methods prior to the calls to any of the printable output methods, and therefore require that the `respell-notes` option of `cmn-display` and `write-lp-data-for-all` be set to `NIL`.

      (cmn-display tonal-example :file "/tmp/tonal.eps"
                   :auto-bar-nums 5
                   :respell-notes nil
                   :auto-clefs nil)
      (write-lp-data-for-all tonal-example
                             :respell-notes nil
                             :auto-clefs nil))

#### enharmonics

The `enharmonics` method allows the user to specify a range of measures in which pitches are to be enharmonically flipped, as well as a list of note-name symbols that are to be affected. The code for this piece therefore uses a loop in which the starting and ending bars, the player, and the list of pitches, are passed as a `for` value to the macro, and a `do` statement that applies the `enharmonics` method with these different values at each iteration. This method does not allow for the enharmonic spelling of "white-key" notes (e.g. C as B-sharp etc.)

      (loop for d in '((14 16 vo (cs5)) (15 16 vt (fs4)) (19 27 vt (af4))
                       (25 25 va (af4)) (27 28 vo (cs5)) (27 30 vt (fs4 cs5))
                       (27 30 va (fs4)) (42 45 vo (cs5)) (43 44 vt (fs4))
                       (47 59 vo (bf5 af5)) (47 59 vt (ef5 af5))
                       (47 59 va (bf4 ef5)) (61 65 vo (ef5)) (61 66 vt (bf4 af4))
                       (70 70 vo (af5)))
         do
           (enharmonics tonal-example (first d) (second d) (third d)
                        :pitches (fourth d)))

#### enharmonic

The `enharmonic` method always applies to only one sounding event object at a time. The optional `:force-naturals` argument of this method allows the method to be used to respell "white-key" pitches as enharmonic equivalents. The method is used here as well within a loop whose `for` statement specifies a list of sublists consisting of the measure number, event number and player ID of the notes to be altered.

      (loop for en in '((17 1 vt) (17 3 vo) (17 3 vt) (20 2 vo) (20 2 vt) (21 1 vo)
                        (21 3 vo) (21 2 vc) (24 2 vo) (24 2 vt) (25 1 vo) (25 3 vo)
                        (25 2 vt) (26 1 vt) (27 2 vt) (28 2 va) (29 2 vo) (29 3 vo)
                        (29 1 vc) (30 2 vt) (45 2 vo) (45 3 vo) (45 1 vt) (45 3 vt)
                        (47 2 vo) (48 1 vc) (49 1 vt) (49 3 vt) (52 1 vc) (53 1 vt)
                        (53 3 vt) (57 2 vo) (58 1 vc) (59 1 vt) (59 3 vt) (62 2 vo)
                        (63 1 vo) (62 2 vt) (61 2 va) (62 1 va))
         do (enharmonic (get-event tonal-example (first en) (second en) (third en))
                        :force-naturals t))

close

### + Inserting key changes and double-bars

Another small loop is used to insert key changes and double-bar lines into the printable output. It is important to point out here that CMN always prints the accidentals into the score, even if a key signature has been added; whereas, LilyPond will hide accidentals already present in a key signature and automatically add cautionary accidentals where suited.

This little loop takes care of both the key signature and the double-bar placement at the same time.

      (loop for b-k in '((12 (ef major)) (19 (fs minor)) (27 (gf major))
                         (32 (ef major)) (47 (fs major)) (68 (a minor)))
         do
           (loop for p in '(vo vt va vc)
              do
                (change-bar-line-type tonal-example (1- (first b-k)) 1)
                (add-mark-before
                 (get-event tonal-example (first b-k) 1 p)
                 `(key ,@(second b-k)))))

close

### + Changing staff names for same instruments

The final step undertaken by the code for this piece is to change the instrument staff names of the two violin parts for the printable output. By default these will both be identified in the score as violin. The following little loop uses `setf` to change the value of the `staff-name` and `staff-short-name` slots of the corresponding instrument objects stored in this `slippery-chicken` object's `ensemble` slot to violin 1 and violin 2.

      (loop for n in '((vo "violin 1" "vln 1") (vt "violin 2" "vln 2"))
         do
           (setf (staff-name
                  (get-data-data (first n) (ensemble tonal-example)))
                 (second n))
           (setf (staff-short-name
                  (get-data-data (first n) (ensemble tonal-example)))
                 (third n)))

close

### + Output

The output for this piece is generated in the same way already covered in other tutorials. Of note here is the use of the `auto-bar-nums` argument to the `cmn-display` method, which causes bar numbers to be placed into the score at intervals of 5 measures, and the setting of both the `respell-notes` and `auto-clefs` options to `NIL` in both the `cmn-display` and `write-lp-data-for-all` methods. The former is necessary in order for the enharmonic changes described above to be effective. The latter is merely a matter of preference.

close