Anyone who has input a piano score into notation software knows that it’s not so 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 withslippery-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-chickenso if you need to do this then your only option is to create several parts inslippery-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 file. In any case here’s a complete example along with the output notation:

(let ((sc
        :ensemble '(((rh (piano))
                     (lh (piano-lh))))
        '((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 along the lines of “warning: no viable initial configuration found: may not find good beam slope” but in my experience you can ignore these and will generally get perfectly good scores.

To finish, here’s an illustrative example (i.e. incomplete code so it won’t run) of how to do automatic cross-staff notation. Bear in mind that this would create the cross-staff notation for a whole piece, no matter how many notes or bars. Those of you who’ve done this in Finale or Sibelius will know the significance of that. Ah…the power of algorithms…

(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)
       (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")))))
Share Button