Closed adrianholovaty closed 1 year ago
Here is a refined proposal based on today's co-chair chat with @dspreadbury and @mscuthbert:
{
"position": [1, 4],
"graceIndex": 2
}
This is based on the previous option 1, with the differences being:
graceIndex
is an optional key. If it's not provided, the position should be interpreted as before all grace notes (which is the common case).For the extreme edge case of a clef change that affects multiple voices, where each voice has grace notes and the clef change is positioned at a specific grace note position, we could have a "graceIndexSequence"
key:
{
"position": [1, 4],
"graceIndex": 2,
"graceIndexSequence": "voice1"
}
This would be the ID of the sequence that the "graceIndex"
refers to. But, again, this is an extreme edge case and I'd suggest putting it aside for now (with the knowledge that we can always add it later in a backwards-compatible way).
This is now done, via the new "rhythmic position" object:
https://w3c.github.io/mnx/docs/mnx-reference/objects/rhythmic-position/
To see it in action, see the new clef changes example document. The inner-bar clef change is encoded with that rhythmic position:
https://w3c.github.io/mnx/docs/mnx-reference/examples/clef-changes/
This uses the new concept of a "positioned clef", documented here:
https://w3c.github.io/mnx/docs/mnx-reference/objects/positioned-clef/
At the most recent co-chairs meeting, @dspreadbury and I dove into the specific issue of how do we encode a particular position into a bar, accounting for the fact that grace notes don't have a distinct rhythmic position?
This came about due to issue #313 (inner-bar clef changes). Each clef change needs to know its rhythmic position — and the encoding needs to handle rhythmic positions within a run of grace notes.
Concretely, we need to support a clef change at the start of a grace note run, vs. a clef change within a grace note run, vs. a clef change immediately after a grace note run. In each of these situations, the rhythmic offset is the same but the position with respect to the grace notes is different.
Though it's tempting to come up with an ad hoc solution for clef changes, it would be nice to solve this in a unified, holistic way — because there are other parts of MNX that would benefit from it, such as placement of hairpins.
One solution would be to rely on IDs for this — for example, "this clef change comes immediately before event ID xyz" — but in our estimation this is a bit too fragile. More importantly, this fails in the case of a clef change that applies to multiple voices in multivoice music (multiple sequences in MNX parlance).
Daniel and I came to agree that a two-dimensional encoding could be the right approach. "Two-dimensional" means two pieces of information: (1) the rhythmic offset into the bar and (2) a way to identify a specific grace note relative to that rhythmic offset. Daniel says Dorico has been using this approach successfully in its own internal encoding.
Here are two options we came up with.
Option 1: Encode grace note index
The green grace note's position in the bar would be encoded as
[[1, 4], 2]
. The two elements of this array are:[1, 4]
— the rhythmic position into the bar (a quarter note's duration).2
— the grace note index, where0
means not a grace note,1
means the right-most grace note,2
means the second-right-most grace note, etc.Option 2: Encode grace note rhythmic offset
The green grace note's position in the bar would be encoded as
[[1, 4], [1, 8]
. The two elements of this array are:[1, 4]
— the rhythmic position into the bar, just as in option 1.[1, 8]
— the rhythmic position into the grace notes, as measured from the right edge and using the grace notes' notated rhythms. In this example, the green grace note has a distance of 1/8 from the right edge of the grace notes (two times a sixteenth note). Note: to encode positions that aren't grace notes, perhaps we'd usenull
here?The advantage of option 1 is: you don't need to worry about the grace notes' notated rhythms (i.e., how many beams they have). You merely count backward from the right. It also avoids dealing with fractions; the index is always an integer.
The advantage of option 2 is: it handles the case of multiple voices in which each voice has its own grace note run with different grace-note beaming for each voice (as long as the different beaming values still added up to an equal grace note rhythmic duration in both voices). This is admittedly an obscure edge case.
Another edge case is grace notes that appear at the end of a bar. Daniel and I discussed this and reasoned that they should be encoded as if they were in the subsequent bar (i.e., attached to their target note), so that they're always located with respect to their target note. We'd then use a simple boolean flag along the lines of
isActuallyDisplayedInPreviousBar=true
. But we don't need to work out the details on this particular edge case just yet.Thoughts or other ideas?