Score layout

+ Associated example files

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 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:

scores-header.png

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)
scores-key-sig.png
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))
scores-key-change-cmn.png
CMN output of the above code
scores-key-change-lp.png
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))))
scores-order.png

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)
scores-group.png

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))
scores-bars-per-sys.png

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.

scores-barlines-default.png

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:

0normal
1double
2final double
3begin repeat
4begin and end repeat
5end 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/"))
scores-barlines-change.png

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)
scores-letters-single.png

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))
scores-clefs.png

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))
scores-delete-clefs.png

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:

scores-transposed.png

Setting the :in-c argument to T:

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

…produces C-scores:

scores-in-c.png

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))

cross-staff-notation.png

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")))))