Custom Staff Properties

2014-05-28By Paul Morris LilyPond

This post is about going beyond global variables.  It is the last entry in a series of posts about recent improvements to the clairnote-code.ly clairnote.ly file.  Previously certain values that are used when producing music notation in Clairnote were stored in global variables.  But if you have more than one staff then you really need to have a separate set of these values for each staff.  So it was quite a breakthrough to learn how to create custom staff properties that make this possible.

Now any value that needs to be stored "per staff" is stored either as a context property added to the Staff context or as a layout object property added to the StaffSymbol object (or "grob" which is short for "graphical object").  The functions used to add these properties were cut and pasted (with some minor modifications) from LilyPond's source code.  Whether to use context properties or layout object properties is a question of how easy it is to access each kind of property in the places where they need to be accessed.  Engravers can easily access context properties, while functions that override layout object properties can usually access a related layout object's properties fairly easily.

Using these custom properties makes things more robust and prevents certain problems that used to happen when you had more than one staff.  For example, Clairnote uses fewer accidental signs than are used in traditional music notation. That's because there are twelve positions per octave on the staff rather than seven, so there is much less need for accidental signs that cancel or supersede a previous accidental sign (see the Accidenal Signs page).  As in traditional notation, if an accidental sign has already appeared in a measure there is no need to print it again, so we use some custom code to track which accidentals are currently active in a given measure.

Previously the list of currently active accidental signs was stored globally.  That meant that if you had more than one staff, the accidental signs on one staff would affect all the other staves too.  As shown in the following image, the sharp sign in the first staff (that indicates that the following note is a G sharp) would prevent the same sharp sign from appearing later in the same measure on the other staves.

Previously accidental signs on one staff cancelled accidental signs on other staves.

[What's missing here?]

Now the list of active accidentals is stored for each staff in a custom context property (added to the Staff context).  Accidental signs in one staff no longer affect the appearance of accidental signs in other staves, as shown here:

Now accidental signs are tracked for each staff.

[That's more like it!]

Another example is that there is now a custom layout object property added to the StaffSymbol object that simply stores whether a staff is a Clairnote staff or a traditional staff.  The code for positioning the dots in repeat signs can just check this property to determine the type of staff and thus where the dots should go.  Previously for each repeat sign it had to check the positions of the staff lines to determine the type of staff.

In short, custom staff properties are an important new tool that allows for better support for Clairnote music notation. These are all of the custom properties currently being used:

  • StaffSymbol.clnt-is-clairnote-staff -- Stores whether a staff is a Clairnote staff or not. Used for repeat sign dots.
  • StaffSymbol.clnt-vscale-staff -- Stores the vertical scaling factor of a staff. Used for key signatures and \staffSize function.
  • StaffSymbol.clnt-note-head-stencils -- Stores Clairnote notehead stencils. Used to replace default notehead glyphs.
  • clnt-key-stils -- (Staff context property) Stores Clairnote key signature stencils. Used by the Clairnote key signature engraver.
  • clnt-acc-list and clnt-bar-num -- (Staff context properties) Stores the active accidental signs in the current measure and stores the bar number when the last accidental sign was printed (to tell when to clear the list of active accidentals for a new bar/measure).  Used by Clairnote accidental engraver.

In an unrelated note, a bug related to \omit has also been fixed.  The clairnote.ly file overrides the stencils of accidental signs, key signatures, noteheads, and the stems of half notes.  This was preventing \omit from working for these notation elements.  Basically \omit overrides a stencil to false (#f) so that it will not be shown (and will take up no space, as opposed to \hide), but the functions overriding these stencils were just overriding it again.  Now these functions check to see if the stencil is false before overriding it.  This lets \omit work as it should.  (This bug was discovered while making the images for this post...)

As always these improvements are found in the clairnote.ly file which can be downloaded from the Software page.  This concludes this series of posts on these recent improvements!


UPDATE, SEPT 2014: In the interest of simpler code, closures are now used instead of custom staff context properties to store per-staff data for the accidental sign code (acclist and barnum).  Also in the interest of simpler code, notehead stencils and key signature stencils are no longer stored in custom properties (probably a "premature optimization," better to rely on memoization).  So there are now only two custom properties currently in use (StaffSymbol.cn-is-clairnote-staff and StaffSymbol.cn-vscale-staff).

Update: the "clairnote-code.ly" file was renamed "clairnote.ly" on May 15, 2017.