Pitches

The user's interaction with specific pitches in slippery chicken is managed through sets and their related methods and functions. The make-slippery-chicken function has keyword arguments for interaction with sets, such as :set-palette, :set-map and :set-limits-high and -low.

It is important to point out the distinction between set objects, which are a static collection of pitches where actual pitches are specified, and pitch-seq objects and palettes, which govern the general linear contour of pitch sequences chosen from the sets, but which are not an interface for the user for specific pitch selection.

This page provides information on both set-related features as well as on the use of pitch-seq objects and palettes.

Separate documentation is also available for note-names and scales and chord functions.

set basics

+ set-palette

The user defines all the possible sets of pitches for a composition in the set-palette. Any number of set objects can be defined in any order within this palette. Each set is assigned an ID, which can be a number, a symbol, or a string, with which it is later referenced from within the set-map.

:set-palette '((set1 ((c3 g3 cs4 e4 fs4 a4 bf4 c5 d5 f5 gf5 af5 ef6)))
               (set2 ((c3 fs3 cs4 e4 g4 a4 b4 c5 df5 f5 g5 af5 ef6)))
               (set3 ((d3 f3 cs4 e4 fs4 a4 b4 c5 d5 e5 fs5 af5 ef6)))
               (set4 ((d3 e3 cs4 ef4 fs4 a4 b4 c5 d5 e5 fs5 af5 d6))))
pitches-set-pals
NB: This graphic was created by applying the cmn-display method directly to a set-palette object. See the page on output for more detail on this feature.

The combination of the static set-palette material and the curves defined in the pitch-seq-palette of each given rthm-seq will determine the linear attributes of the music generated for each instrument. If a set contains only a few pitches separated by large intervals, the instruments will have either large leaps in their linear pitch material or many consecutive repetitions of the same note.

close

+ set-map

The set-map is where the sets are assigned to each of the individual sequences (rthm-seqs) of the piece. It is made up of a list of the sections in the piece, each paired with a list that consists of one set ID for each of the sequences in that section. The set IDs can be assigned to the sequences in any order. They can be repeated within the set-map as many times as the user would like. Not all of the sets defined must be used in the set-map.

The pitches in a given set are the only pitches available to the ensemble for the duration of that sequence.

:set-map '((1 (set1 set1 set1 set1 set1))
           (2 (set2 set3 set2 set3 set2 set3 set3))
           (3 (set3 set3 set4 set3 set4 set3 set4 set4 set3 set4 set4))   
           (4 (set4 set4 set1 set4 set1 set4 set1 set1 set1)))

This set-map, with the sets defined in the set-palette section above, will result in the following progression:

pitches-set-map-a-b-c
NB: This example has one set per measure because the individual rthm-seq objects in the given rthm-seq-palette are each only one measure long. Each set applies to an entire rthm-seq, which may consist of multiple measures.

NB: This example graphic was created by setting the display-sets keyword argument of cmn-display to T when applied to a complete slippery-chicken object (see the page on output for more detail), with further tweaking of the output using the open source software Inkscape and GIMP.

close

pitch-seq basics

+ Understanding pitch-seq curves

The linear contours of pitches automatically chosen by slippery chicken from the current set for each playing instrument are governed by pitch-seq curves. These are defined by the user within the pitch-seq-palette of each individual rthm-seq object of the rthm-seq-palette, and are therefore only applied to instances of that rthm-seq in the music generated.

The pitch-seq curves consist of integers, one for each attacked rhythm (i.e. not for tied notes) of the given rthm-seq object. For example:

:rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -))
                        :pitch-seq-palette ((1 4 3 2 5 7 8 6)))))

The numbers chosen by the user for the pitch-seq can span any arbitrary numerical range, including negative numbers. The difference between two consecutive numbers in the pitch-seq indicates the direction and relative size of the linear interval between the corresponding two pitches selected by slippery chicken. Thus, a sequence of (1 2 13 4 3) indicates a linear pitch contour that has one small interval at the beginning and end, with a larger leap upwards and back down again in the middle.

The actual pitches chosen from the current set by slippery chicken for each curve depend on a number of factors (see the section on how slippery chicken selects pitches below). One of these factors is the given instrument's range. Each pitch-seq curve is only applied to those pitches within the current set that fall within the instrument's range, as defined in the instrument-palette being used for the piece. If there are fewer pitches within the current set that fall within the instrument's range than there are different integer values used to define the pitch-seq curve, then some of the pitches will be repeated.

As an example, the following application of the same pitch-seq with 8 different integers to both the flute and the bassoon parts, with a pitch set that has relatively few low notes, results in the bassoon line having a narrower range and a number of repeated pitches:

:set-palette '((1 ((b3 d4 g4 b4 e5 a5 d6 a6 b6))))
:rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -))
                        :pitch-seq-palette ((1 2 3 4 5 6 7 8)))))
:rthm-seq-map '((1 ((fl (1))
                    (bn (1)))))
pitches-single-pitch-seq.png

Avoiding melodic octaves

By default, slippery chicken will avoid melodic octaves when selecting pitches for the players. This feature can be turned off by setting the :avoid-melodic-octaves slot to NIL.

Default output:

	:set-palette '((1 ((c5 d5 e5 f5 g5 a5 b5 c6))))
	:set-map '((1 (1 1 1)))
	:rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -))
				:pitch-seq-palette (1 2 3 4 5 6 7 8))))
	:rthm-seq-map '((1 ((fl (1 1 1)))))
pitches-avoid-8ves-t.png

Setting :avoid-melodic-octaves to NIL:

	:set-palette '((1 ((c5 d5 e5 f5 g5 a5 b5 c6))))
	:set-map '((1 (1 1 1)))
	:rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -))
				:pitch-seq-palette (1 2 3 4 5 6 7 8))))
	:avoid-melodic-octaves nil
	:rthm-seq-map '((1 ((fl (1 1 1)))))
pitches-avoid-8ves-n.png

Defining only one pitch-seq in a pitch-seq-palette

If only one pitch-seq is defined for a given rthm-seq object, every instrument playing that rthm-seq will always have the same linear pitch contour whenever that rthm-seq appears in the piece. For information on the use of multiple pitch-seq curves, see the section on multiple curves in the same pitch-seq-palette below.

Indicating chords in the pitch-seq curve

Numbers in additional parentheses within a pitch-seq indicate chords:

:rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -))
                        :pitch-seq-palette ((1 (4) (3) 2 5 (7) 8 6)))))

If the given instrument is not capable of playing chords, as indicated by its definition in the instrument-palette being used for the piece, then single pitches are selected by slippery chicken instead. More information on topics related to chords can be found on the chord functions page.

close

+ Multiple curves in the same :pitch-seq-palette

There can be as many separate pitch-seq curves in each pitch-seq-palette as the user likes. A pitch-seq-palette with more than one pitch-seq will produce multiple linear pitch curves for the same rhythmic material. Depending on the structure of the rthm-seq-map, these different curves may be played by different players at the same time or by the same player at different times (or both).

slippery chicken applies each different pitch-seq consecutively starting at the top of the ensemble and moving downwards through the players. Thus, if three players are assigned within the rthm-seq-map to play the same rthm-seq at the same time, the first pitch-seq curve is given to the player that appears first in the ensemble list, the second to the next player in the ensemble list, and the third to the player after that.

For example, this very brief slippery-chicken piece has three players and defines three different pitch-seq curves with distinct contours within the one pitch-seq-palette of the one rthm-seq in the rthm-seq-palette. It then constructs the composition using a rthm-seq-map in which all three players play the same rthm-seq at the same time, only once:

(make-slippery-chicken
 '+multi-ps+
 :title "Multiple pitch-seqs"
 :instrument-palette +slippery-chicken-standard-instrument-palette+
 :ensemble '(((fl (flute :midi-channel 1))
              (ob (oboe :midi-channel 2))
              (cl (b-flat-clarinet :midi-channel 3))))
 :tempo-map '((1 (q 60)))
 :set-palette '((1 ((c4 d4 e4 f4 g4 a4 b4 c5))))
 :set-map '((1 (1)))
 :rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -))
                         :pitch-seq-palette ((8 7 8 7 8 7 8 7)
                                             (5 4 3 4 5 4 3 4)
                                             (1 2 1 2 1 2 1 2)))))
 :rthm-seq-map '((1 ((fl (1))
                     (ob (1))
                     (cl (1))))))

The resulting score fragment shows how the different pitch-seq curves of the above pitch-seq-palette determine the linear contours for each player. It also demonstrates the distinction between pitch contours and actual pitch selection in slippery chicken, as the numbers do not represent pitches, but directionality and relative distance within the linear pitch motion. Thus, the clarinet maintains the contour indicated by 1 2 1 2..., even though its 2 is higher in pitch than the oboe's 4. (More detail on this can be found in the section on how slippery chicken selects pitches below.)

resultsOfMultiplePitchSeqs.png

close

Advanced pitch-seq and set topics

+ How slippery chicken selects pitches

General

It is important to emphasize that slippery chicken is not designed to allow the user to determine specific pitches for specific instruments at any given point in the piece prior to the generation of the musical data. Instead, it chooses pitches automatically from the current set based on a number of rules and conditions.

The sequence of rules and conditions

slippery chicken selects the pitches for each instrument in a given sequence of the piece one instrument after the next. If no other specification is given, the order in which it processes the instruments defaults to the order in which the players are listed in the ensemble block. If the user would like to specify a different order, this can be done using the :instruments-hierarchy keyword argument of the make-slippery-chicken function. When choosing pitches for instruments, slippery chicken takes into account which pitches have already been assigned to other instruments playing at the same time in the same sequence, so the order in which it processes the instruments is important for pitch allocation.

Once the order is determined, slippery chicken follows specific steps to select pitches from the current set for each instrument:

  1. slippery chicken first limits the current set to only pitches that fall within the instrument's range.
  2. It then removes any pitches that have already been allocated to other instruments.
  3. If the definition of the instrument specifies a value for the subset-id slot, and the current set contains a subset with that ID, the pitches are further limited to those common to both the specified subset and the pitches remaining from step 2.
  4. If the ratio of the number of pitches now available to the number of different numerical values in the pitch-seq is less than the pitch-seq-index-scaler-min slot of the slippery-chicken object (0.5 by default), slippery chicken will add pitches that have already been allocated to other instruments until this ratio is met or exceeded. (The user can change the value of the pitch-seq-index-scaler-min by specifying the keyword argument of the same name within the call to the make-slippery-chicken function). This ratio—which may indeed be greater than one—is then used to multiply the numbers in the pitch-seq (which are subsequently rounded) to obtain the indices for getting the pitches for each number in the pitch-seq from the list of available pitches. In this case, the lowest number in the pitch-seq will be assigned to the lowest of the available pitches.
  5. If after the first three steps there are enough pitches to cover the different numbers in the pitch-seq, the pitch assigned to the lowest number in the pitch-seq will depend on the value of the prefers-notes slot of the instrument definition:
    1. If the prefers-notes slot has been set to high, the highest number in the pitch-seq will be assigned to the highest of the available pitches.
    2. If the prefers-notes slot has been set to low, the lowest number in the pitch-seq will be assigned to the lowest of the available pitches.
    3. If this slot has not been set (defaults to NIL), the range of pitches assigned to the numbers of the pitch-seq will correspond to the middle of the available pitches, with two exceptions:
      • If the lowest number in the pitch-seq is 5 or higher, this will have the same effect as the prefers-notes slot being set to high.
      • If the lowest number in the pitch-seq is 1, this will have the same effect as the prefers-notes slot being set to low.
      If the user would like to change either of these values, 1 or 5, do e.g.
      (setf +pitch-seq-lowest-equals-prefers-high+ 6)
      (setf +pitch-seq-lowest-equals-prefers-low+ 0)
  6. If at this point there are no available pitches, the function will trigger an error and exit. This could happen, for example, if the set-limits-high and set-limits-low take the available pitches outside of the instrument's range.

NB: By default, slippery chicken will also prevent melodic octaves from being assigned to a player. Setting the slippery-chicken object's avoid-melodic-octaves slot to NIL will disable this feature, as described in the understanding pitch-seq curves section above.

Changing notes post-generation

There are ways of narrowing the set of pitches available to an instrument at a given point, such as by using the set-limits-high and set-limits-low keywords of the make-slippery-chicken function (see below), or by defining subsets (see below) and setting subset-ids for the instrument objects (see the page on tailoring instrument definitions).

However, if the user would like to change the specific pitches of just a few notes here and there after a piece has been generated, a number of methods are available for modifying the data of existing slippery-chicken objects. The post-generation data-editing method double-events, for example, allows exact pitches and rhythms to be copied from one player to one or more others. This method can only be applied to an existing slippery-chicken object, meaning that the distribution of available pitches among the instruments is not repeated. (See the page on post-generation data editing).

Since slippery chicken can also be used to produce MIDI files from its data, importing these into commercial notation software such as Finale or Sibelius is also always an option. With a bit of searching, the corresponding pitch values can also be found and modified in any LilyPond files created. (Some versions of LilyPond also include a point-and-click feature by which clicking on a note in the PDF output jumps automatically to that note in the .ly file.)

close

+ set-limits-high and -low

In addition to the definition of the highest and lowest pitches of an instrument's absolute range (as defined in the individual instrument objects of the instrument-palette being used for a given piece), the user can further constrain the pitches assigned to a given instrument to sub-ranges for any number of consecutive sequences of a piece. This is done using the keyword arguments :set-limits-high and :set-limits-low with a list of 2-element lists, in the format seen here:

   :set-limits-high '((cl (0 c6 50 c5 100 c6))
                      (vc (0 g4 50 c5 100 g4))
                      (cb (0 f3 50 b3 100 f3)))

The first element of each 2-element list is the ID assigned by the user to the given player within the ensemble block of the make-slippery-chicken function (and not the ID of the instrument within the instrument-palette). If the symbol all is given here, the subsequent list of breakpoint pairs will apply to all instruments, further constraining the high and low limits of the individual curves if there is an overlap, thus allowing tessitura shaping for the whole ensemble over the course of the piece.

The second element of each 2-element list is a series of breakpoint pairs, each consisting of an x-axis number followed by either a note-name symbol or a MIDI note number. The pitch indicators refer to sounding pitches, not written (in the case of a transposing instrument). The x-axis range is arbitrary and will be scaled to fit the number of sequences in the entire piece. Since the x-axis numbers in this example span from 0 to 100, if the given piece consisted of 100 sequences, the second x-axis value here of 50 would indicate the 50th sequence in the piece.

The method interpolates a gradual curve between the values associated with each x-axis number. In this example the upper range of the instrument associated with player cl would be limited to C6 at the opening, gradually being lowered to C5 by the middle sequence, and gradually increasing to C6 again by the last sequence of the piece.

NB: Since the operations behind the set-limits- slots are based on interpolation, at least two pair of breakpoint are required. Correspondingly, set-limits- values cannot be used when generating a musical fragment that has only one sequence in the rhtm-seq-map. Attempting to do so will produce a division by zero error.

NB: If a single capping of an instrument's pitch range for an entire piece is required rather than a curve for range limits that change over the piece, another option for achieving this is to modify the highest- or lowest-written or -sounding values of the given instrument object instead. See the documentation on changing instrument attributes temporarily for more on this.

close

subsets and related-sets

+ Adding subsets and related-sets to a set

Each set in a set-palette can also contain subsets and related-sets. These will only be used during automatic pitch selection if there is a corresponding value set as the subset-id in the definition of an instrument object (see the page on tailoring instrument definitions and the section on limiting an instrument's pitches using subset-id below). They can also be very useful when writing user-defined functions, such as for chord selection (see the page on chord functions for more detail).

The primary difference between subsets and related-sets is that all pitches specified in the subsets slot must also be members of the primary set, whereas the related-sets slot can contain any pitch, whether part of the primary set or not.

When a subset is specified with pitches that are not members of the primary set, slippery chicken will produce an error:

sc-set::check-subsets: Note C4 given in subset MBA1 of set SET1 is not part of the main set.
   [Condition of type SIMPLE-ERROR]

Both subsets and related-sets can be entered as simple or nested key-data pairs, whereby the nested approach must be reflected in the additional set of parenthesis. Entry as simple key-data pairs would look like this:

 :set-palette '((1 ((f3 g3 a3 bf3 c4 d4 e4 f4 g4 a4 b4 c5 d5 e5 f5 g5)
                    :subsets ((pno1 (c4 e4 g4))
                              (pno2 (d4 f4 a4))
                              (mba1 (a3 c4 e4)))
                    :related-sets ((pno3 (gs4 bf4 df5))
                                   (mba2 (fs3 af3 cs4))))))
pitches-subsets-simple.png

Nested subsets and related-sets would be entered such:

 :set-palette '((1 ((c3 g3 cs4 e4 fs4 a4 bf4 c5 d5 f5 gf5 af5 ef6)
                    :subsets ((piano ((pno1 (cs4 e4 fs4))
                                      (pno2 (e4 fs4 a4))))
                              (marimba ((mba1 (c3 g3 cs4))
                                        (mba2 (g3 cs4 e4)))))
                    :related-sets ((piano ((pno3 (d3 a3 d5))
                                           (pno4 (c3 g3 d5))))))))
pitches-subsets-nested
NB: These graphics were created by applying the cmn-display method directly to a set-palette object. See the page on output for more detail on this feature.

close

+ Limiting an instrument's pitches using subset-id

The subset-id slot of an instrument object will cause slippery chicken to automatically limit an instrument's pitches to the pitches in the corresponding subset of the current set. This applies to both linear pitch contours and any chords made (see the section on chord functions and set-palette subsets of the chords page for more on restricting only the chords for an instrument to subsets without simultaneously limiting the linear pitch contours for that instrument). If there is no subset in the current set with a matching ID, the default rules for pitch selection apply.

This example sets the subset-id slots of the flute, oboe, and b-flat-clarinet instruments that are contained in the +slippery-chicken-standard-instrument-palette+ to flute-notes, oboe-notes, and clarinet-notes, and creates corresponding subsets with the same ID in the set:

(set-slot 'subset-id 'flute-notes 'flute
          +slippery-chicken-standard-instrument-palette+) 

(set-slot 'subset-id 'oboe-notes 'oboe
          +slippery-chicken-standard-instrument-palette+)

(set-slot 'subset-id 'clarinet-notes 'b-flat-clarinet
          +slippery-chicken-standard-instrument-palette+)

(let ((subset-id-piece
       (make-slippery-chicken
        '+subset-id-piece+
        :title "subset id piece"
        :instrument-palette +slippery-chicken-standard-instrument-palette+
        :ensemble '(((fl (flute :midi-channel 1))
                     (ob (oboe :midi-channel 2))
                     (cl (b-flat-clarinet :midi-channel 3))))
        :tempo-map '((1 (q 60)))
        :set-palette '((1 ((b3 c4 d4 e4 f4 g4 a4 b4 c5 d5 e5 f5 g5 a5 b5 c6
                               d6 e6 f6 g6 a6 b6) 
                           :subsets ((flute-notes (b5 c6 d6 e6 f6 g6 a6 b6)) 
                                     (oboe-notes (a4 b4 c5 d5 e5 f5 g5 a5))
                                     (clarinet-notes (b3 c4 d4 e4 f4 g4)))))) 
        :set-map '((1 (1 1 1)))
        :rthm-seq-palette '((1 ((((4 4) - e. s - - e e - 
                                  - +s s s s - - (s) s s s - )) 
                                :pitch-seq-palette ((2 2 3 1 1 2 1 2 2 2) 
                                                    (6 8 5 5 7 7 9 6 8 10) 
                                                    (5 4 3 1 1 2 3 3 4 4)
                                                    (1 3 3 2 1 2 3 1 1 1))))) 
        :rthm-seq-map '((1 ((fl (1 1 1))
                            (ob (1 1 1))
                            (cl (1 1 1))))))))
  (write-lp-data-for-all subset-id-piece :base-path "/tmp/"))

When the piece is generated, each part will only contain pitches from the corresponding subset:

pitches-subset-id.png

close