slippery chicken documentation - score layout

## Score layout

### + Associated example files

- scores-examples.lsp

close

NB: An exercise relating to the material covered in this tutorial can be found on the Exercises page.

Score layout in slippery chicken is done primarily using keyword arguments to the `make-slippery-chicken` function. Arguments are available for inserting elements into the header, for defining attributes of the systems, and for attributes related to measures. Not all arguments are available for both CMN and LilyPond output.

slippery chicken itself does not produce printable output. Instead, it generates the data and files necessary for printable output to be produced by third-party software, namely Common Music Notation (CMN) and LilyPond. See the installation page for details on how to obtain these applications and prepare slippery chicken for use with them. Specifics on how to generate the output, once the keyword arguments have been set in the `make-slippery-chicken` function, can be found on the output page.

Because the printable output is not produced by slippery chicken itself, tweaking of scores (such as moving colliding symbols on the page etc.) is not possible using slippery chicken code. However, since both CMN and LilyPond produce vector-based graphics files, their output can be easily edited in a click-and-drag manner using third-party SVG software such as Adobe Illustrator or the open source alternative Inkscape. More on tweaking output using these applications can be found on the output page.

### + The header

The header in a score generally consists of the title and the composer of the work. For LilyPond, these can be set within the `make-slippery-chicken` function using the `:title` and `:composer` keywords:

    (make-slippery-chicken
     '+new-piece+
     :title "A Slippery Chicken Piece"
     :composer "Joe Green"

LilyPond output for the above settings would produce the following header:

NB: Only English characters can be used in the title. Accents and umlauts etc. are not supported.

NB: Only the `:title`, and not the `:composer` keyword, is available for CMN.

close

### + Key signatures

Key signatures in slippery chicken can be placed by two means. Firstly, the user can place an initial key signature in the first bar using the `:key-sig` argument of the `make-slippery-chicken` function. Secondly, mid-piece key changes can also be inserted using the `add-mark-to-note` post-generation editing method.

#### CMN vs. LilyPond

Key signatures are handled differently by CMN and LilyPond. CMN places the key signature as a graphic symbol, and does not automatically change accidentals in the subsequent musical notation. The user will have to enter pitches without accidentals in order for the score to appear correct, which will affect the MIDI output.

LilyPond allows the user to enter actual pitches, and will automatically remove any accidentals in the key signature from the subsequent music (or add natural signs accordingly), while maintaining the original pitch. The resulting MIDI output will accurately reflect the score.

#### Initial key signatures

Key signatures for the start of a piece can be placed by using the `:key-sig` argument of the `make-slippery-chicken` function and specifying a note-name symbol (without octave indicator) and `major` or `minor`, as such:

    :set-palette '((1 ((ef4 f4 g4 af4 bf4 c5 d5 ef5))))
    :key-sig '(ef major)

LilyPond output using the above parameters

#### Key changes

Key changes after the first bar are added as a mark. A key signature mark can be added for CMN output using the post-generation editing methods `add-mark-before` or `add-mark-before-note`. For LilyPond, key signature marks can be added using either of those methods or the `add-mark-to-note` method.

The `add-mark-before` and `add-mark-before-note` methods result in the key signature being placed immediately before the specified event object in the resulting score. The `add-mark-to-note` method results in the key signature being placed immediately after the specified event, so key changes at the bar line must be placed on the last note of the previous bar.

The key-signature mark takes the form of a list, with the first element being the word `key`, followed by the note-name symbol and mode type:

    (let* ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))))
            :key-sig '(ef major)
            :avoid-melodic-octaves nil
            :set-palette '((1 ((ef4 f4 g4 af4 bf4 c5 d5 ef5))))
            :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 ((vn (1 1 1))))))))
      (add-mark-before-note mini 2 1 'vn '(key af major))
      (add-mark-before-note mini 3 1 'vn '(key a major))
      (cmn-display mini)
      (add-mark-to-note mini 2 8 'vn '(key a major))
      (add-mark-to-note mini 1 8 'vn '(key af major))
      (write-lp-data-for-all mini))

CMN output of the above code

LilyPond output of the above code

#### Key signatures in non-C scores

The key signature feature of slippery chicken does not currently automatically transpose key signatures for non-C scores, which is the default output for both `cmn-display` and `write-lp-data-for-all`. A simple work-around is to change the key signatures manually when generating scores in which the players' parts are displayed as written pitches, or when extracting parts (also see the section on extracting parts below).

close

### Systems

#### + Score order

The order in which instruments appear in the printable score output is determined in slippery chicken by the order in which players are listed in the `ensemble` block.

    :ensemble '(((fl (flute :midi-channel 1))
                 (ob (oboe :midi-channel 2))
                 (hn (french-horn :midi-channel 3))
                 (tp (b-flat-trumpet :midi-channel 4))
                 (vn (violin :midi-channel 5))
                 (va (viola :midi-channel 6))
                 (vc (cello :midi-channel 7))))

close

#### + Staff groups

By default, slippery chicken will place all of the players of the ensemble into one group, resulting in a single group bracket in the score that encloses all players, as seen in the example above. However, the user can specify groupings of players using the `staff-groupings` keyword argument.

This argument takes a list of integers that indicate how many consecutive players from the `ensemble` are to be grouped together in one bracket in each system of the score. Thus, a `staff-groupings` value of `'(2 2 3)` applied to the ensemble above would indicate groupings of 2 players (`fl` and `ob`), 2 players (`hn` and `tp`), and 3 players (`vln`, `vla`, and `vlc`). When setting the value of `staff-groupings`, the sum of the numbers in the list must be equal to the total number of players in the ensemble.

    :ensemble '(((fl (flute :midi-channel 1))
                 (ob (oboe :midi-channel 2))
                 (hn (french-horn :midi-channel 3))
                 (tp (b-flat-trumpet :midi-channel 4))
                 (vn (violin :midi-channel 5))
                 (va (viola :midi-channel 6))
                 (vc (cello :midi-channel 7))))
    :staff-groupings '(2 2 3)

NB: CMN and LilyPond handle single-staff groups differently. By default, CMN will place a group bracket around single-staff groups while LilyPond will leave the group bracket out if there is only one instrument in that group.

close

#### + Bars per system

CMN has an additional option for determining the number of bars placed in each system. This can be done using the `:bars-per-system-map` keyword argument of the `make-slippery-chicken` function. This feature does not affect LilyPond layout, as LilyPond determines bars-per-system automatically.

The value passed to this argument must be a list of two-item lists, each of which consists of a bar number paired with a number of measures. An entry such as (3 5), for example, would indicate that CMN is to place 5 measures per system starting with bar 3.

The following, for example, will result in CMN output that has one measure in the first system, two in the next, three in the system after that (starting with bar 3), and four and five measures in the last two systems (starting with bars 7 and 11 respectively).

    :bars-per-system-map '((1 1) (2 2) (3 3) (7 4) (11 5))

close

### Bars

#### + Bar line types

By default slippery chicken produces data for score output in which all bar lines are normal (i.e. single) except for the right bar line of the last measure, which is a final double bar line.

Bar line types can be changed by the user by means of post-generation editing, using the `change-bar-line-type` method. slippery chicken currently has 6 bar line types, which are indicated by number IDs. They are:

0 | normal
1 | double
2 | final double
3 | begin repeat
4 | begin and end repeat
5 | end repeat

The `change-bar-line-type` method takes as its first argument a `slippery-chicken` object (or the variable it has been assigned to), followed by the number of the bar whose right bar line is to be changed, and the ID of the bar line type:

    (let* ((bar-lines-piece
           (make-slippery-chicken
            '+bar-lines-piece+
            :title "bar-lines piece"
            :ensemble '(((fl (flute :midi-channel 1))))
            :set-palette '((1 ((c4 d4 e4 f4 g4 a4 b4 c5))))
            :set-map '((1 (1 1 1)))
            :rthm-seq-palette '((1 ((((4 4) - e e e e - - e e e e -)))))
            :rthm-seq-map '((1 ((fl (1 1 1))))))))
      (change-bar-line-type bar-lines-piece 1 1)
      (change-bar-line-type bar-lines-piece 3 5)
      (write-lp-data-for-all bar-lines-piece :base-path "/tmp/"))

NB: This is a score function only. Repeat bar lines will not be reflected in playback with MIDI or CLM.

close

#### + Rehearsal letters

Data for rehearsal letters can be attached either by including a value for the `rehearsal-letters` keyword argument of the `make-slippery-chicken` function, or through post-generation editing.

The `rehearsal-letters` keyword argument takes a list of measure numbers, to which consecutive rehearsal letters are automatically added. No indication of the actual letter is necessary.

    :rehearsal-letters '(3 6 10)

Placing individual rehearsals through post-generation editing is done using the `set-rehearsal-letter` method, which takes a `slippery-chicken` object (which can also be given as a local variable or the global variable defined as the first argument to the `make-slippery-chicken` function), a bar number, and a letter as its arguments.

    (set-rehearsal-letter mini 3 'A)

##### Difference between CMN and LilyPond

CMN and LilyPond differ in their manner of drawing rehearsal letters into a score. CMN enters the letter in a large, bold font, with no frame. LilyPond frames each letter in a thin box.

##### Right bar lines only

slippery chicken attaches rehearsal letters to bar lines, which are only placed at the end of a given measure. When attaching a letter to measure 5, therefore, the letter will actually be attached to the right bar line of measure 4 (the user still enters `5` in the `rehearsal-letters` list). Thus, no rehearsal letter can be placed on the first measure of a piece.

##### Adding rehearsal letters to all parts

By default, rehearsal letters are only added to those players' parts that are at the top of each group. This means that rehearsal letters will not be present in the other players' music when extracting parts. The user can indicate that letters are to be added to all players' parts by setting the `:rehearsal-letters-all-players` argument of the `cmn-display` and `write-lp-data-for-all` methods to `T`. Although the rehearsal letters will now be in all players' parts, LilyPond will still automatically only place them above the groups in the score, while CMN will also place the letters over all instruments in the score as well.

close

#### + Clefs

By default, clefs in slippery chicken are handled automatically based on the values of the `clefs`, `starting-clef`, and `clefs-in-c` slots of the individual `instrument` objects. (See the page on instruments and the source code documentation on `make-instrument` for more detail on these three slots.) The `write-lp-data-for-all` and `cmn-display` methods will also automatically place mid-measure clefs by default if a given `instrument` object has been defined with more than one clef.

##### Disabling the automatic clef-changes feature of the output methods

The user can choose to prevent the `write-lp-data-for-all` and `cmn-display` methods from automatically placing clef changes by setting their `:auto-clefs` keyword argument to `NIL`. Disabling this feature prevents these methods from running the `auto-clefs` algorithm internally before writing their output to a file. Turning this feature off does not affect the placement of the `starting-clef` for the given instrument.

    (cmn-display +sc-object+ :file "/tmp/mini.eps" :auto-clefs nil)

    (write-lp-data-for-all +sc-object+ :base-path "/tmp/" :auto-clefs nil)

##### Using auto-clefs as a post-generation editing method instead

Setting the `:auto-clefs` argument to `NIL` will require the user to manually add all clef changes. If the user is basically satisfied with the results of the `auto-clefs` algorithm but would like to delete or move a number of the resulting clef changes manually, the method can be disabled as a feature of the output methods and called as a post-generation editing method in conjunction with the `add-clef` and `delete-clefs` methods instead, prior to the call to `cmn-display` or `write-lp-data-for-all`. This enables the user to have slippery chicken automatically place clef changes and then manually delete some of those clefs or insert others.

    (auto-clefs +sc-object+)
    (delete-clefs +sc-object+ 'vc 1 5)
    (add-clef +sc-object+ 'vc 2 2 'tenor)
    (add-clef +sc-object+ 'vc 3 3 'treble)
    (write-lp-data-for-all +sc-object+ :base-path "/tmp/" :auto-clefs nil)

##### The add-clef and delete-clefs methods

The user can manually insert or remove a clef for a given player at any point in the piece using the post-generation editing methods `add-clef` and `delete-clefs`. If these methods are used, the `:auto-clefs` argument within the calls to `cmn-display` or `write-lp-data-for-all` must be set to `NIL`, as changes made using `add-clef` and `delete-clefs` will otherwise be overwritten.

The `add-clef` method can be used to place a clef sign before a given event object (including rests) in the score by specifying the player, bar number, event number, and new clef:

    (let* ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vc (cello :midi-channel 1))))
            :tempo-map '((1 (q 72)))
            :set-palette '((1 ((g3 a3 b3 c4 d4 e4 f4 g4))))
            :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 ((vc (1 1 1))))))))
      (add-clef mini 'vc 2 2 'tenor)
      (add-clef mini 'vc 3 3 'treble)
      (write-lp-data-for-all mini :base-path "/tmp/" :auto-clefs nil))

The `delete-clefs` method functions in a similar manner, but does not require a new clef to be specified, and does require that a clef is already present in the given event object:

    (let* ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vc (cello :midi-channel 1))))
            :tempo-map '((1 (q 72)))
            :set-palette '((1 ((g3 a3 b3 c4 d4 e4 f4 g4))))
            :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 ((vc (1 1 1))))))))
      (add-clef mini 'vc 2 2 'tenor)
      (add-clef mini 'vc 3 3 'treble)
      (delete-clefs mini 'vc 2 2)
      (delete-clefs mini 'vc 3 3)
      (write-lp-data-for-all mini :base-path "/tmp/" :auto-clefs nil))

close

### C- scores and generating parts

#### + C-scores

By default, all scores generated from the data of a `slippery-chicken` object will be produced at written pitch. Scores at concert pitch, or "in C", can be generated by setting the `:in-c` argument of the `cmn-display` and `write-lp-data-for-all` methods to `T`.

Default generation at written pitch:

Setting the `:in-c` argument to `T`:

    (write-lp-data-for-all mini :base-path "/tmp/" :in-c t)

…produces C-scores:

NB: If the `clefs-in-c` slot of a given `instrument` object is set, the clefs used in C scores for a given instrument will be drawn only from those clefs. This can be helpful, for instance, when writing for an instrument that sounds in the bass clef but is written in the treble, such as the bass clarinet or the baritone saxophone.

close

#### + Parts and sectional scores

##### CMN

Generating parts using `cmn-display` is done by specifying a value for the optional keyword argument `:players`. This argument takes a list of one or more of the `player` IDs from the `ensemble` and produces scores with only those players.

Parts are generated for individual players in CMN by setting the `players` keyword argument to a list of only one player.

    (cmn-display mini :file "/tmp/mini.eps" :players '(tbn))

Using `cmn-display` to produce a sectional score that contains only the music for the players `hrn`, `tpt`, `tbn`, and `tba`, can be done as such:

    (cmn-display mini :file "/tmp/mini.eps" :players '(hrn tpt tbn tba))

##### LilyPond

The files required to generate parts using LilyPond are produced automatically by the `write-lp-data-for-all` method, as described on the output page. All LilyPond parts are automatically generated in the transposing key of the given instruments regardless of the value of the `:in-c` argument, which only affects the `-score.ly` file.

Sectional scores in LilyPond are produced in the same manner as for CMN, by using the `:players` argument. The individual parts for this sectional score will also be automatically generated.

    (write-lp-data-for-all mini :base-path "/tmp/" :players '(hrn tpt tbn tba))

close

#### +

#### Some remarks on piano music

Anyone who has input a piano score into notation software knows that it's not as easy as, say, creating a woodwind part. First of all there are chords, then you have two staves, on top of which you might have multiple parts per stave, and on top of that you might have groups of beamed notes that cross back and forth from the left to the right hand (so-called cross-staff notation).

From the perspective of `slippery-chicken`, there's no difference whatsoever between a keyboard part and any other part. You add a piano to an ensemble as with any other player by setting the instrument to `'piano`. But each new player gets only one new staff, so if you want two staves you should probably add a second 'player'.

It's most convenient to think of the two hands as two separate 'players' and create separate contrapuntal parts for them. I've made several piano pieces with `slippery-chicken` and that's generally been my approach. In order to aid this, the `piano-lh` instrument is available---this is the same as the piano but it has no staff name and begins in the bass clef. You can then keep the two hands within a manageable range by using the set limits arguments to `make-slippery-chicken`, for example:

     :set-limits-high '((piano-lh (0 b3 100 b3)))
     :set-limits-low  '((piano-rh (0 c4 100 c4)))

Chords are handled as with any other instrument but bear in mind that you can specify your own chord-selection function and apply these to any instrument. More on this is given in the documentation for chords and in the section Indicating chords in the pitch-seq curve in the documentation for pitch-seq basics. Note that multiple voices on one stave are not supported in `slippery-chicken` so if you need to do this then your only option is to create several parts in `slippery-chicken` then combine them onto one stave via MIDI import into the notation software of your choice.

Cross-staff notation is possible in `slippery-chicken` but only when you use Lilypond output. In order to accomplish this you'll need to create a dummy part which has no notes then simply add marks to events in order to switch back and forth between staves (this could be automated by examining pitch height: see below). The staff name you pass as part of the mark will be the same as the lower case version of your player name but with all - and _ characters removed. If you're in any doubt, look at the "music = { " block in the generated Lilypond -def.ly file. In any case here's a complete example along with the output notation:

    (let ((sc
           (make-slippery-chicken
            '+cross-staff+
            :ensemble '(((rh (piano))
                         (lh (piano-lh))))
            :set-palette
            '((1 ((c1 a1 ds2 cs3 g3 d4 f4 bf4 e5 b5 gs6 fs7)))
              (2 ((bf1 ef2 af2 g3 cs4 e4 c5 e5 b5 f6 d7 fs7 a7))))
            :set-map '((1 (1 2)))
            :rthm-seq-palette '((1 ((((2 4) - e e e e -) (- e e e e -))
                                    :pitch-seq-palette ((1 2 (7) (8) 1 2 1 (8))))))
            :rthm-seq-map '((1 ((lh (1 1))))))))
      ;; we don't always want to use the double bass clef
      (set-standard-instrument-slot 'clefs '(bass) 'piano-lh)
      (add-mark-before-note sc 3 4 'lh '(staff "rh"))
      (add-mark-before-note sc 4 1 'lh '(staff "lh"))
      (add-mark-before-note sc 4 4 'lh '(staff "rh"))
     (lp-display sc :title nil :dummy-staves 'rh))

If you're using a lot of (nested) tuplets you might get Lilypond warnings similar to "no viable initial configuration found: may not find good beam slope" but in my experience you can ignore these and still get good output.

Here's an illustrative example (i.e. incomplete code so it won't run) of how to do automatic cross-staff notation:

    (flet ((change-staff (e which)
             (add-mark-before e (list 'staff which))))
      (next-event +jitterbug+ 'solo t 1)
      (loop with current-clef = 'bass
         for event = (next-event +jitterbug+ 'solo t nil nil)
         while event
         for pht = (get-degree event :average t)
         for clef = (if (> pht 59) 'treble 'bass)
         do
           (cond ((and (eq clef 'treble) (eq current-clef 'bass))
                  (setq current-clef 'treble)
                  (change-staff event "rh"))
                 ((and (eq clef 'bass) (eq current-clef 'treble))
                  (setq current-clef 'bass)
                  (change-staff event "solo")))))