w3c / mnx

Music Notation CG next-generation music markup proposal.
174 stars 19 forks source link

Add a way to encode beaming #198

Closed adrianholovaty closed 3 years ago

adrianholovaty commented 3 years ago

Now that we've removed the old <beamed> element in da4d3334, we need a way to encode beaming.

A quick thought: It would be nice to be able to encode high-level rules, such as "always beam eighth notes together, but never beam across the middle of a bar in 4/4 time." Of course there would also need to be a way to override this for a particular <event>.

notator commented 3 years ago

My current position re the low-level rules can be found in https://github.com/w3c/mnx/issues/193#issuecomment-691708030. Such code would override any high-level rules that are currently in force.

A high-level rule might be defined as follows: Add an optional beams attribute to the time element. If this attribute is defined, then beams would be drawn automatically between all events, except that they would break at the given positions and at measure boundaries. If the attribute is missing, then the default would be to draw no automatic beams at all. For example:

<global>
  <measure>
    <directions>
      <time signature="7/8" beams="3/8, 2/8, 2/8"/>
    </directions>
    ...
  </measure>
  ...
</global>

The beams attribute might be allowed to have the value "auto" for simple time signatures that have known, standard ways of beaming things. So <time signature="4/4" beams="auto"/> would mean the same as <time signature="4/4" beams="1/4, 1/4, 1/4, 1/4"/> and <time signature="6/8" beams="auto"/> would mean the same as <time signature="6/8" beams="3/8, 3/8"/>

Note that:

  1. The time signatures that can have "auto" beaming would need to be documented together with their standard beaming structures .
  2. The <time> element applies to all parts. This would be a truly global setting.
bhamblok commented 3 years ago

I'm not such a big fan of encoding highly repeatable and often irregular "items" (as beams are) on a high level.

I believe it will strongly increase the complexity for applications to draw the actual beams.

This becomes even more complex for things that shouldn't even be complex at all, like syncopes.

So why should we create the possibility to define beams on a global high level when we have to define how beams could/should be defined on a low level anyway in case of irregularities.

When we apply beams in places where beams should occur, all complexity I described above would simply vanish.

So, here's my 2 cents worth: we scratch the idea of globally defined encoding of beaming, and we stick to the 2 possible solutions:

samuelbradshaw commented 3 years ago

Avoiding high-level encoding rules doesn't really reduce complexity overall – instead, it passes the complexity on to the user.

ahankinson commented 3 years ago

It seems to me that with an encoding format you want to capture what the user has written in their user interface, or what they've deemed to be acceptable notation according to the visual output of their encoding software.

I don't know what the definitions of "high level" and "low level" are here (is a dedicated 'beam' element high or low?), but there seems to be a confusion in this issue about whether the replacement for 'beam' is a notation formatting language ("high level"?), or a notation capture structure ("low level"?). While you gain some "cool" factor in doing automated beaming, you're also likely to frustrate users who, having no idea of the internals and interpretations of each notation application, just want to send what they wrote to their colleague and have it come out on the other end the same way. If you leave this up to interpretation between developers, you will get divergent behaviours.

Perhaps unsurprisingly, if you don't want hierarchical beam elements I think the MEI <beamSpan> method is a particularly elegant way of encoding the beam literals, using standard XML IDs to supply the membership of that beam. (@startid, @endid, and @plist, particularly)

notator commented 3 years ago

I rather agree with both @bhamblok and @ahankinson that introducing additional, overridable "high level" rules would be a mistake. They lead to the interpretation and divergent behaviours problem that @ahankinson mentions.

But I can see why we have been asked to look at high-level rules. There are many use cases for music notations that use simple, conventional beam structures that should not need to be coded in low-level detail all the time.

[Begin Aside, for the benefit of those who might still want to have overridable "high-level" rules]: The problem lies in the details. Unless the rules are defined in extreme detail, one ends up with applications treating them differently, and chaos ensues. And how do we know if the details have been defined precisely enough for that not to happen? Taking my high-level rule for example: What happens if a short triplet crosses a beam-boundary without actually coinciding with it anywhere? Partially beamed triplets might actually confuse things by implying that one of the notes is actually on the beam-border... So we need an extra rule for tuplets. And so on... [End Aside]

It might still be possible to define very restrictive rules for defining beam structures, as a strict alternative to the usual "low level" rules. There are probably quite a lot of use-cases for music notation that is simple and consistent enough not to allow exceptions to some rule... I'm not really pushing for this. Just thought it worth mentioning.

On the sub-issue of using ids in the beaming algorithm: I think the use of ids should be avoided where possible. Like GOTOs in old programming languages, they lead to unstructured, impenetrable code. Especially when used en masse, as would be the case when implementing beams. Also, there is an appreciable overhead to assigning them. They should be reserved for cases where they are really necessary. MNX consists of ordered lists of parts, measures, staves, events etc., and that ordering should be leveraged by using indexing, rather than treating the whole data structure as an amorphous lump. As I showed in https://github.com/w3c/mnx/issues/193#issuecomment-685799364, we don't even need ids to implement beams that cross measure boundaries.

ahankinson commented 3 years ago

Unless the rules are defined in extreme detail...

Which was, I think, my point. The more you go towards defining these "high-level" rules in increasing detail, with validation for violations of the rules, the closer you get to defining a Turing-complete language. At this point your encoding crosses into being an XML-based programming language. (Imagine if MNX wasn't defining an XML schema, but an XSLT library or Schematron... If you want to encode the rules for interpretation of the data, those would probably be a better tool for the job.)

There are many use cases for music notations that use simple, conventional beam structures that should not need to be coded in low-level detail all the time.

Agreed, but shouldn't the "simple" beaming behaviours be defined by the encoding application, and not in the encoding rules of the format? With the former you give the user the ability to confirm that any automated inference of the rules is to their liking before they click the 'export' button. With the latter, you take the user out of the loop. Given that beams have no sounding manifestation and are entirely visual components of music notation, it would seem to me that you would want a visual means of confirming or adjusting any inferred behaviours?

I think the use of ids should be avoided where possible. Like GOTOs in old programming languages, they lead to unstructured, impenetrable code...

Having used @xml:id for almost 10 years now in MEI as the standard method for structuring and linking notation elements, and having been responsible for assigning (probably) millions of these IDs through the various incarnations of software and encoding libraries I have written for others, I can pretty safely say that, in my experience, they don't lead to unstructured, impenetrable encoding.

In fact, any notation encoding format of sufficient expressiveness will naturally grow to be impenetrable in order to encompass the breadth of musical idioms, and require tools to manage this data. Using a standard mechanism for linking and addressing the data within the encoding is the solution for bringing order to this impenetrability; otherwise, you're on the hook for doing it all (and maintaining and bug-fixing the software) yourself! That's the whole point of using XML to express your encoding.

If you use XML but choose not to take advantage of the slew of XML tools that work with these standard idioms (xpath, xslt, xquery all use @xml:id values out of the box) then wouldn't you be better off choosing a different carrier for your format? With apologies to Henry Spencer, "Those who do not understand XML are condemned to re-invent it, poorly."* ;)

I'm also not sure about the reference to GOTOs... they're not really the same. If you define an @xml:id but never reference it, it's harmless. If you specify a reference to an ID, but never point to it, your software writing the encoding is broken. The programming equivalent is defining a function that is never called (useless, but harmless) or calling a function that is not defined (a crash-and-burn error). The problem with GOTOs wasn't that they were called by something, it's that they specified an exact line in the program on which to find it...

The only argument I could see against IDs in beams or any other element is that they bloat the text encoding. But in the age of multi-terabyte drives and unlimited cloud storage, the extra disk space occupied by these strings is less than negligible. If you're that worried about space, then, again, you would probably be better served by a different carrier format than XML (the angle brackets on their own would occupy more disk space than the IDs...). A more efficient format would be something like **kern.

But maybe these thoughts are better off in #65 ...

* I can definitely speak to this -- I spent a significant amount of time writing software that does XML namespace handling and DOM traversals, badly.

notator commented 3 years ago

There are many use cases for music notations that use simple, conventional beam structures that should not need to be coded in low-level detail all the time.

Agreed, but shouldn't the "simple" beaming behaviours be defined by the encoding application, and not in the encoding rules of the format? With the former you give the user the ability to confirm that any automated inference of the rules is to their liking before they click the 'export' button. With the latter, you take the user out of the loop.

Agreed. End users should be able to rely on their files looking the way they did when exported. "High-level" rules can't guarantee that, so it would be wrong to include them in the format specification.


I think the use of ids should be avoided where possible. Like GOTOs in old programming languages, they lead to unstructured, impenetrable code...

Having used @xml:id for almost 10 years now in MEI as the standard method for structuring and linking notation elements, and having been responsible for assigning (probably) millions of these IDs through the various incarnations of software and encoding libraries I have written for others, I can pretty safely say that, in my experience, they don't lead to unstructured, impenetrable encoding.

Sorry, I was trying to say what I think as clearly as possible. (The quote makes more sense in its original, complete form.) Of course there are situations in which IDs are the only correct solution. I just think that MNX beaming is not one of them. Using IDs unnecessarily just adds clutter to the file, makes it less humanly readable/debuggable, and adds a burden to the applications having to assign them.

I didn't mention it in my previous post, but an important reason for not using IDs, is that MusicXML's solution doesn't use them either. Migrating from MusicXML will be easier if we stay close to that strategy. @bhamblok raises an objection in https://github.com/w3c/mnx/issues/193#issuecomment-687076756 describing his reasons for wanting to use IDs as follows:

I would definitely not make use of a "number"-attribute, which caused me a lot of developer-friction in the past (especially when dealing with cross-measure-beams in combination with multiple voices and the <backup>- and <forward>-elements), but I would use unique id's instead.

I think this objection no longer applies in MNX. The <backup> element and its related problems no longer exist. And MNX is defined in parts and sequences, so beams can be coded in the same way, regardless of whether they cross barlines or not.


In fact, any notation encoding format of sufficient expressiveness will naturally grow to be impenetrable in order to encompass the breadth of musical idioms...

That may be true of MEI but, as I understand the situation, our co-chair has decided that the MNX format currently being developed (the "standard profile") only encompasses CWMN as it was around 1900. Later accretions (such as the fanned beams handled by MusicXML or tuplets crossing barlines) can/will be dealt with in a different, but related format. And there's no reason to stop there: Related formats can also be developed for the world's other music notations. All music notations have common constructs (such as "staff" or "event") so we are talking about a family of formats. If each format has well defined, finite scope, there's no question of it becoming impenetrable.


If you use XML but choose not to take advantage of the slew of XML tools that work with these standard idioms (xpath, xslt, xquery all use @xml:id values out of the box) then wouldn't you be better off choosing a different carrier for your format? With apologies to Henry Spencer, "Those who do not understand XML are condemned to re-invent it, poorly."* ;)

I use lots of ready-made tools when trying to achieve things with XML, so I'm certainly not trying to re-invent it. Just trying to use it properly. :-)

I'm also not sure about the reference to GOTOs... they're not really the same.

The problem with GOTOs was that they allowed programmers to ignore (program) structure...

adrianholovaty commented 3 years ago

Here are four proposals for encoding beaming in MNX. Feedback welcome!

Each proposal encodes the following simple example:

Screenshot

For each proposal, I've listed pros and cons as I see them. I've also added a "Possible developer gotchas" section to each; this is something we should weigh heavily, to make this as developer-friendly as possible.

Proposal 1: elements with explicit event IDs

<mnx>
    <global>
        <measure>
            <directions>
                <time signature="4/4"/>
            </directions>
        </measure>
    </global>
    <part>
        <part-name>Music</part-name>
        <measure>
            <directions>
                <clef sign="G" line="2"/>
            </directions>
            <beams>
                <beam events="event1 event2 event3 event4"></beam>
                <beam events="event5 event6 event7 event8"></beam>
            </beams>
            <sequence>
                <event value="/8" id="event1">
                    <note pitch="C5"/>
                </event>
                <event value="/8" id="event2">
                    <note pitch="D5"/>
                </event>
                <event value="/8" id="event3">
                    <note pitch="E5"/>
                </event>
                <event value="/8" id="event4">
                    <note pitch="F5"/>
                </event>
                <event value="/8" id="event5">
                    <note pitch="D4"/>
                </event>
                <event value="/8" id="event6">
                    <note pitch="E4"/>
                </event>
                <event value="/8" id="event7">
                    <note pitch="F4"/>
                </event>
                <event value="/8" id="event8">
                    <note pitch="G4"/>
                </event>
            </sequence>
        </measure>
    </part>
</mnx>

Here, each beam is encoded in a distinct <beam> element. Each beam explicitly lists all events within, using id.

This is similar to MEI's beamSpan element.

I've put the <beam> elements in a <beams> container element in the <sequence>, but I don't feel strongly about this. We could rename/generalize <beams> to <visual> (or something similar) and use it for other data at this semantic level. It could also live in some other area, though I think it makes sense for it to live as close to the affected <event>s as possible.

Pros:

Cons:

Possible developer gotchas:

Proposal 2: MusicXML-style

<mnx>
    <global>
        <measure>
            <directions>
                <time signature="4/4"/>
            </directions>
        </measure>
    </global>
    <part>
        <part-name>Music</part-name>
        <measure>
            <directions>
                <clef sign="G" line="2"/>
            </directions>
            <sequence>
                <event value="/8">
                    <note pitch="C5"/>
                    <beam number="1" type="start"/>
                </event>
                <event value="/8">
                    <note pitch="D5"/>
                    <beam number="1" type="continue"/>
                </event>
                <event value="/8">
                    <note pitch="E5"/>
                    <beam number="1" type="continue"/>
                </event>
                <event value="/8">
                    <note pitch="F5"/>
                    <beam number="1" type="end"/>
                </event>
                <event value="/8">
                    <note pitch="D4"/>
                    <beam number="1" type="start"/>
                </event>
                <event value="/8">
                    <note pitch="E4"/>
                    <beam number="1" type="continue"/>
                </event>
                <event value="/8">
                    <note pitch="F4"/>
                    <beam number="1" type="continue"/>
                </event>
                <event value="/8">
                    <note pitch="G4"/>
                    <beam number="1" type="end"/>
                </event>
            </sequence>
        </measure>
    </part>
</mnx>

Here, each beam is encoded with separate <beam type="start"> and <beam type="end"> elements. These elements go in the first and last <event> elements of the beam. Each inner <event> gets <beam type="continue">.

This is similar to MusicXML's approach to beaming.

Pros:

Cons:

Possible developer gotchas:

Proposal 3: "Beam to next event"

<mnx>
    <global>
        <measure>
            <directions>
                <time signature="4/4"/>
            </directions>
        </measure>
    </global>
    <part>
        <part-name>Music</part-name>
        <measure>
            <directions>
                <clef sign="G" line="2"/>
            </directions>
            <sequence>
                <event value="/8" beamnext="1">
                    <note pitch="C5"/>
                </event>
                <event value="/8" beamnext="1">
                    <note pitch="D5"/>
                </event>
                <event value="/8" beamnext="1">
                    <note pitch="E5"/>
                </event>
                <event value="/8">
                    <note pitch="F5"/>
                </event>
                <event value="/8" beamnext="1">
                    <note pitch="D4"/>
                </event>
                <event value="/8" beamnext="1">
                    <note pitch="E4"/>
                </event>
                <event value="/8" beamnext="1">
                    <note pitch="F4"/>
                </event>
                <event value="/8">
                    <note pitch="G4"/>
                </event>
            </sequence>
        </measure>
    </part>
</mnx>

Here, each beam is reduced to the question of "does this <event> beam to the following <event>?"

This is sort of a simplified version of proposal 2. Rather than requiring <beam> elements, this uses a much more lightweight beamnext attribute.

Pros:

Cons:

Possible developer gotchas:

Proposal 4: Higher-level beaming rules

<mnx>
    <global>
        <measure>
            <directions>
                <time signature="4/4" beaming="/2 /2" />
            </directions>
        </measure>
    </global>
    <part>
        <part-name>Music</part-name>
        <measure>
            <directions>
                <clef sign="G" line="2"/>
            </directions>
            <sequence>
                <event value="/8">
                    <note pitch="C5"/>
                </event>
                <event value="/8">
                    <note pitch="D5"/>
                </event>
                <event value="/8">
                    <note pitch="E5"/>
                </event>
                <event value="/8">
                    <note pitch="F5"/>
                </event>
                <event value="/8">
                    <note pitch="D4"/>
                </event>
                <event value="/8">
                    <note pitch="E4"/>
                </event>
                <event value="/8">
                    <note pitch="F4"/>
                </event>
                <event value="/8">
                    <note pitch="G4"/>
                </event>
            </sequence>
        </measure>
    </part>
</mnx>

Here, the <time> element has a beaming attribute that specifies the beam-break locations as a higher-level "rule." Any note that can be beamed should be beamed, taking care not to beam across the beam-break locations.

This is similar to MEI's beam.group attribute.

Pros:

Cons:

Possible developer gotchas:

Some other cases to consider

Here are some other cases to consider when evaluating these proposals (or adding proposals). I've given them names, so that we can refer to them quickly in conversation.

Case 1: Unbeamed grace note

Screenshot

Case 2: Rest within beam

Screenshot

Case 3: Beam hooks

Screenshot

Case 4: Locations of secondary beam breaks

Screenshot

Case 5: Beamed grace notes

Screenshot

Case 6: Beam across barline

Screenshot

Upshot

Having given these some consideration, I prefer Proposal 1. It's unambiguous, it's easy to consume, it's semantically tightly contained, and the structure minimizes risk of bad/incomplete data.

Thoughts and reactions welcome!

notator commented 3 years ago

@adrianholovaty Thanks for this summary of the four possible proposals. Proposal 1 looks very promising...

In reverse order: Proposal 4: Higher-level beaming rules @ahankinson and I agreed above that high-level rules lead to users being unable to rely on files looking the way they did when exported. So this is a non-starter.

Proposal 3: "Beam to next event" is an unexplored version of Proposal 2. Its less promising than Proposal 1 because, as you say,

There's no natural place to put additional beam-specific metadata, such as locations of secondary beams. Likely we'd use an additional attribute on <event>, but that might start to feel heavy.

Proposal 2: MusicXML-style has already been discussed. See https://github.com/w3c/mnx/issues/193#issuecomment-691708030. I still think this is a possible option. Its main advantage is that migrating from MusicXML would be easier than using Proposal 1. Disadvantages are 1) that it does not have Proposal 1's Pros and 2) we would have to find a way to encode fanned beams that is as powerful as the one that is possible using a variation of Proposal 1. See below.

Proposal 1 needs exploring: The Pros are very convincing:

There is a one-to-one mapping between a beam rendered in notation and a <beam> element. This is conceptually elegant, and it gives us a place to add additional beam-specific metadata, such as rhythmic positions of secondary beams or data about feathered beaming. It also would easily support beams across barlines.

and the Cons (use of IDs) can be avoided (see below).

You said:

I think it makes sense for [the <beams> element] to live as close to the affected <event>s as possible.

That means, to me, that the <beams> element should live in the <sequence> element. That's where all <beam>s begin. The vast majority of <beam>s end in the same <sequence> as the one in which they began. The only exception is when a <beam> crosses a barline, in which case it ends in the corresponding <sequence> in the following <measure>. Beams never change to a different <sequence> in the same <measure>. (Question: Should beams be able to cross multiple barlines?). So we have:

<mnx>
    <global>...</global>
    <part>
        ...
        <measure>
            ...
            <sequence>
                <event ... id="event1">...</event>
                <event ... id="event2">...</event>
                <event ... id="event3">...</event>
                <event ... id="event4">...</event>
                <event ... id="event5">...</event>
                <event ... id="event6">...</event>
                <event ... id="event7">...</event>
                <event ... id="event8">...</event>
                <beams>
                    <beam events="event1 event2 event3 event4"></beam>
                    <beam events="event5 event6 event7 event8"></beam>
                </beams>                
            </sequence>
        </measure>
    </part>    
</mnx>

Including all the event IDs in a single beam looks a bit redundant. The above <beams> element could be replaced by

<beams>
    <beam begin="event1" end="event4"></beam>
    <beam begin="event5" end="event8"></beam>
</beams>

which would be easier to parse (no string analysis), and less error-prone (no way to include non-sequential events). And we can easily use indices (event numbers) instead of IDs

<beams>
    <beam beginEventNum="1" endEventNum="4"></beam>
    <beam beginEventNum="5" endEventNum="8"></beam>
</beams>

That enables easy plausibility checking. When parsing the file, we know how many events there are in the sequence, so we can check that all the beginEventNums and endEventNums are in range. Coding impossible beams is more difficult than when using IDs. Defining beams that cross barlines (a rare but important requirement) could be done by using an optional integer <beam> attribute endMeasureOffset, whose default value is 0. If defined, this attribute declares that the endEventNum is the number of an <event> in the corresponding <sequence> that number of <measure>s in the future:

    <beam beginEventNum="1" endMeasureOffset="1" endEventNum="4"></beam>

Summary, so far: Here's the above example again, without using IDs:

<mnx>
    <global>...</global>
    <part>
        ...
        <measure>
            ...
            <sequence>
                <event ...>...</event>
                <event ...>...</event>
                <event ...>...</event>
                <event ...>...</event>
                <event ...>...</event>
                <event ...>...</event>
                <event ...>...</event>
                <event ...>...</event>
                <beams>
                    <beam beginEventNum="1" endEventNum="4"></beam>
                    <beam beginEventNum="5" endEventNum="8"></beam>
                </beams>                
            </sequence>
        </measure>
    </part>    
</mnx>

If that looks more difficult to read than having IDs, it would be very easy to provide event numbers in comments next to the <event>s. Also, remember that eventIDs would get much bigger (less legible) in a real file, while event numbers never get bigger than the number of events in a <sequence>. Note too, that this code disentangles the <beams> from any <tuplet> elements that might be enclosing some of the <event>s.

The other Cases:

Case 1 (grace-notes inside beams) is no problem because grace notes and normal events never share beams, so grace-notes are simply ignored when constructing the surrounding beam. Presumably, the reverse is also true: beamed grace notes should follow the same pattern as for ordinary events. TODO: Be more precise about how to beam grace-notes.

Case 2 (rests inside beams) is also no problem, basically for the same reason. Beams crossing barlines are also possible (see above).

Case 4 (secondary beams): Conveniently, these could be nested inside <beam> elements (to any depth) to create beam blocks: If there are 16 events in the bar (as in Case 4), then the secondary beams could be coded like this:

<beams>
    <beam beginEventNum="1" endEventNum="8">
        <beam beginEventNum="1" endEventNum="4"></beam>
        <beam beginEventNum="5" endEventNum="8"></beam>
    </beam>
    <beam beginEventNum="9" endEventNum="16">
        <beam beginEventNum="9" endEventNum="12"></beam>
        <beam beginEventNum="13" endEventNum="16"></beam>
    </beam>
</beams>

It would be helpful if this nesting were to be mandatory, since it makes the construction of beam blocks easier: One doesn't have to look through all the <beam>s in the <beams> element to see which <beam>s belong together, and how they nest. Each beam's level (=number in MusicXML) is coded as its level of nesting, so its possible to do plausibility checking to see that beam blocks are well formed: (A <beam> should never extend beyond the <beam> within which it is nested.)

Case 3 (beam-hooks) These could be expressed as <beamhook> elements, which would be like <beam>s, but only have either a beginEventNum or an endEventNum attribute. Case 3 (having 6 events) would be coded like this:

<beams>
    <beam beginEventNum="1" endEventNum="3">
        <beamhook beginEventNum="1" />
        <beamhook endEventNum="3" />
    </beam>
    <beam beginEventNum="4" endEventNum="6">
        <beamhook beginEventNum="4" />
        <beamhook endEventNum="6" />
    </beam>
</beams>

Note that <beamhook>s have a definition that distinguishes them clearly from <beam>s:

  1. they have either a beginEventNum attribute or an endEventNum attribute
  2. they can only exist as <beam> content
  3. they can have no content of their own

Fanned (Feathered) beaming: I'm not convinced that this should be supported in V1 of the MNX format (=standard profile), since it complicates the implementation for applications that don't need it. But it would be as well to be aware that it is going to be supported later, and to have some idea of how that might be done. Here's a possible solution, that fits the above scheme:

<beams>
    <beam beginEventNum="1" endEventNum="4" fan="accel">  <!-- "accel" -->
        <fannedBeam beginEventNum="1" >
            <fannedBeam beginEventNum="1"></fannedBeam>
        </fannedBeam>
    </beam>
</beams>

and

<beams>
    <beam beginEventNum="1" endEventNum="4" fan="rit"> <!-- "rit" -->
        <fannedBeam endEventNum="4" >
            <fannedBeam endEventNum="2"></fannedBeam> <!-- N.B. endEventNum="2" for example -->
        </fannedBeam>
    </beam>
</beams>

Note that the <fannedBeam> elements

  1. either have a beginEventNum attribute (for fan="accel") or an endEventNum attribute (for fan="rit"). The final event for fan="accel" is always the final event in the enclosing <beam>. The first event for fan="rit" is always the first event in the enclosing .
  2. need not have the full length of their enclosing <beam> or <fannedBeam>. One end of the beam is always at the usual height determined by the nesting, The other end is at the current height of the enclosing <beam> or <fannedBeam>. (Question: Is that more powerful than MusicXML's current code?)
  3. have a logical duration equal to the sum of the logical durations of the beamed events. For example: (/32 + /32 + /32 + /32 + /16 + /16 +/8 + /8) = /2 . Its still an open question as to how performance events should be encoded (see #197), but I think we should concentrate on getting the graphics sorted out before we start discussing temporal information. Possibly, the alignments of the events inside a <fannedBeam> should be related to their performance durations rather than their logical durations. Or is that up to the rendering application?

As usual in a sketch like this, all the element and attribute names are debatable. There may well be better ways of doing some things. Like @adrianholovaty , I also have no strong feelings about having a <beams> element surrounding the <beam> elements. Discussion welcome.

webern commented 3 years ago

Proposal 1 looks the best to me. I think referring to event IDs is going to be useful and natural for programmers.

Proposals 2 and 3 both put a lot of burden on the programmer to manage the state of variables outside the loop. This is one of the main things I hope MNX can improve upon, so these both make Proposal 1 look even better!

Proposal 4 is interesting, but it is orthogonal to the other proposals. I don't think it would eliminate the need for explicit beaming for 'overrides', and I don't think support for explicit beaming means that Proposal 4 can't also coexist.

bhamblok commented 3 years ago

I also support proposal 1. In particular:

There is a one-to-one mapping between a beam rendered in notation and a <beam> element.

I would like this statement to be true for (almost) all rendered items in notation. After all, we are designing a data-structure for "music notation" which is by nature a visual representation of music. In this vision, Proposal 4 does not match very well.

I agree with @webern

Proposals 2 and 3 both put a lot of burden on the programmer to manage the state of variables outside the loop. This is one of the main things I hope MNX can improve upon, so these both make Proposal 1 look even better!

I'm also in favor of @notator his idea of nesting secondary beams and/or beamhooks. Although I would like to argue the statement of @notator saying:

Beams never change to a different <sequence> in the same <measure>.

What about cross-staff beams(?) which are very common in Piano literature, where in MNX every staff is being represented by another <sequence>.

notator commented 3 years ago

@webern said:

I think referring to event IDs is going to be useful and natural for programmers

The problem here with using event IDs is that you can't check the beams to see that they are well-formed.

@bhamblok Nesting secondary beams is not entirely my idea. :-) Its implied in the Pros for Proposal 1 mentioned by @adrianholovaty:

[having <beam> elements] gives us a place to add additional beam-specific metadata, such as rhythmic positions of secondary beams...

MNX manages cross-staff beams by displaying their <sequence> on a different staff at some point. See, for example, https://github.com/w3c/mnx/issues/193#issuecomment-689510641. In fact

Beams never change to a different <sequence> in the same <measure>

should be re-phrased more precisely as: Beams never leave the "voice" in which they begin. (A "voice" is a sequence of <sequence>s in consecutive <measure>s.)

notator commented 3 years ago

I've been taking a closer look at using <tuplet>, <grace>, and <beams> elements together in <sequence>s to see if I can find any hidden snags... (The Draft Spec contains useful diagrams showing how <tuplet> and <grace> elements are currently used in <sequence>s.)

Here's an example of how a complex <sequence> containing <tuplet>, <grace>, <event>, rest and <beams> elements might look: Edit 17.11.2020: Added this diagram and the coded <event> value values for clarity: complexBeams

...
    <sequence>
        <grace>
            <event value="/8">...</event> <!-- event 1 -->
            <event value="/8">...</event> <!-- event 2 -->
        </grace>
        <tuplet>
            <event value="/8">...</event> <!-- event 3 -->
            <event value="/8">...</event> <!-- event 4 -->
            <grace>
                <event value="/8">...</event> <!-- event 5 -->
                <event value="/8">...</event> <!-- event 6 -->
                <event value="/16">...</event> <!-- event 7 -->
                <event value="/8"><rest></event> <!-- event 8 (a rest) -->
                <event value="/16">...</event> <!-- event 9 -->
            </grace>
            <event value="/16">...</event> <!-- event 10 -->
            <event value="/16">...</event> <!-- event 11 -->
        </tuplet>
        <event value="/8"><rest></event> <!-- event 12 (a rest) -->
        <event value="/8">...</event> <!-- event 13 -->
        <event value="/8">...</event> <!-- event 14 -->
        <beams>
            <beam beginEvent="1" endEvent="2" /> <!-- grace -->
            <beam beginEvent="3" endEvent="11"> <!-- tuplet -->
                <beam beginEvent="10" endEvent="11" /> <!-- secondary beam -->
            </beam>
            <beam beginEvent="5" endEvent="9"> <!-- grace (enclosing an /8 rest) -->
                <beamhook beginEvent="7" />
                <beamhook endEvent="9" />
            </beam>
        </beams>
    <sequence>
...

I now think that:

  1. Having a <beams> element is definitely a good idea. It clearly separates the <beams> from the list of <event>s.
  2. The order in which <beam> elements are defined inside <beams> or <beam> elements doesn't matter. Only the nesting levels are important.
  3. The event numbers used in the <beam> definitions should be the flat event numbers ignoring the <grace> and <tuplet> groups (as above). Maybe that could be done differently?
  4. We need a clear set of rules as to what is and is not legal, otherwise people will start defining beams that don't display consistently across applications (as with the "high-level" rules). Contrary to the "high-level" rules case, I think it is possible to have a finite and complete set of such rules for this proposal. Here's a first attempt (which I'll continue to edit until someone replies). Is this list correct and/or complete? It should be:
    1. illegal for all beam types to extend across duration classes greater than /8
    2. illegal for secondary beams to extend beyond their parent beam
    3. illegal for beams not to maintain each enclosed event's duration class (i.e. all /16 events have two beams). This also applies for enclosed rests.
    4. illegal for all beam types to begin or end on a rest
    5. illegal for beams to change thickness (i.e. a grace beam can't end as a tuplet beam or an ordinary beam, and vice versa)
    6. illegal for grace beams to cross tuplet or ordinary events,
    7. illegal for tuplet beams to enclose ordinary beams, but
    8. legal for ordinary beams to enclose tuplet beams
    9. legal for all beam types to cross rests.
    10. legal for both ordinary and tuplet beams to cross grace events.

The Spec seems to say that <grace> elements can contain <tuplet> elements. I think that's wrong, and that the correction means rewriting §6.3 Sequence Content. That section is going to have to be rewritten anyway if/when we agree to include <beams>.

<directions>: §6.3 says:

... directions occurring within sequence content must omit [the location] attribute as their location is determined during the procedure of sequencing the content.

I'm not sure that I completely understand "sequencing the content". Its important that the spec is comprehensible and unambiguous, so §6.3 really needs completely rewriting. Shall I have a go? As I understand it, any <event> in a <sequence> can be immediately preceded by a <directions> element (for changing the staff or default orientation of the stems) -- even inside <grace> or <tuplet> elements. Is that correct? If so, the above beaming code is independent of the staff and stem direction. I think that's okay. Applications have enough information to draw the beams correctly. But could there be a way to make their job easier?

clnoel commented 3 years ago

My only thought is that whatever way we encode this, we don't forget about two-note tremolos.

image

The above image clearly has beams connecting two half notes that only take up quarter note space, and are not played as either.

I'm not suggesting we consider how to encode these precisely now. I think tremolos need their own topic. But whatever we decide about beams, can't be specified in a way that will make these impossible to do.

notator commented 3 years ago

Good point! Such tremolo notations definitely belong in MNX V1, even though the spec doesn't mention them.

The Wikipedia article says that tremolo beams for half-note tremolos are (all) drawn between the stems, but that they can alternatively all be joined to the stems (as in the examples in the article). My copy of Gardner Read (1974) says that half-note tremolos have the outer beam joined to the stems, and the secondary beams between them (as in the above example). Sorting out details like that does indeed need a different thread. The code we define may have to be able to describe different tremolo notations...

However, (as with fanned beams) its important for the current discussion to know if/how tremolo beams can be integrated with normal beaming code.

Here's a possiblility: A half-note tremolo (e.g. in the top left measure of the above example) could be coded as a single <event>:

<event value="\2" isBeamedTremolo>...</event>

where isBeamedTremolo is a boolean attribute, and the content (to be worked out later) describes the <note>s in the two chords and the beaming.

That would mean adding a further condition to the above list:

Is that precisely correct?

TODO: Add tremolo beams to MNX V1 and the Draft Spec, and open a new issue to discuss how they should be coded.

notator commented 3 years ago

Here's a proposal for defining isBeamedTremolo <event>s. Its not so complicated after all. Maybe we can even agree on this without having to open a new thread.

For reference here's the Wikipedia diagram: wikiTrems

There seem to be the following alternatives for notating half-note (=minim) tremolos: minimTrems

Note the following:

  1. The <event>'s value (=duration class) always defines the shape of the noteheads (and the number of augmentation dots) in the two chords, so that does not have to be defined again.
  2. For duration classes other than "\2" (=minim), the event's duration class always defines the number of beams (if any) connecting the two stems (if any).
  3. If the duration class is "/2", special long tremolo beams can be drawn.

So the general case, valid for all duration classes, might look like this:

<event value="/4d" isBeamedTremolo>
    <tremoloBeams number="3">
    <leftChord>
        <note pitch="E5"/>
        <!-- add more notes here ad lib. -->
    </leftChord>
    <rightChord>
        <note pitch="E4" />
        <!-- add more notes here ad lib. -->
    </rightChord>
</event>

If the duration class is "/2", then its possible to include <longTremoloBeams> in the code: Alternative A would look like:

<event value="/2" isBeamedTremolo>
    <longTremoloBeams number="3" />
    <leftChord>
        <note pitch="E5"/>
    </leftChord>
    <rightChord>
        <note pitch="E4" />
    </rightChord>
</event>

Alternative B would look like:

<event value="/2" isBeamedTremolo>
    <longTremoloBeams number="1" />
    <tremoloBeams number="2" />
    <leftChord>
        <note pitch="E5"/>
    </leftChord>
    <rightChord>
        <note pitch="E4" />
    </rightChord>
</event>

Alternative C would use the general form.

adrianholovaty commented 3 years ago

Thanks for the thoughts, everybody!

I've edited my above comment to add two more cases ("Case 5: Beamed grace notes" and "Case 6: Beam across barline").

Here's a stab at how Proposal 1 would handle all of the cases 1-6.

Case 1: Unbeamed grace note

Screenshot

The <beam> excludes the grace note:

<beam events="event1 event3 event4 event5"></beam><!-- no event2 -->

Case 2: Rest within beam

Screenshot

The <beam> includes the rest:

<beam events="event1 event2 event3 event4"></beam><!-- event2 is the rest -->

Case 3: Beam hooks

Screenshot

The <beam-hook> element encodes the hooks:

<beam events="event1 event2 event3">
    <beam-hook event="event1" direction="right">
    <beam-hook event="event3" direction="left">
</beam>

Technically they don't need to be encoded in this case, as the consuming application has enough information (the events' rhythmic durations) and should use default hook directions.

Case 4: Locations of secondary beam breaks

Screenshot

Note that the first eight notes are considered a single <beam> element (even though there are two beam "levels" and three separate rendered rectangles). This is in MNX's spirit of simplicity.

It contains a <beam-level> element, to encode the break:

<beam events="event1 event2 event3 event4 event5 event6 event7 event8">
    <beam-level event="event4" value="1" />
</beam>

The value attribute specifies the beam level (i.e., how many visual beams are rendered) between event4 and event5. I needed to make a call on whether to encode the event before the break or or after it; I didn't see an obvious benefit to either approach but using the first one just "felt right."

I'm curious — does this handle any and all types of beam breaks? Would love to put this idea through its paces.

Case 5: Beamed grace notes

Screenshot

There's a separate <beam> for the grace notes:

<beam events="event1 event4 event5 event6"></beam>
<beam events="event2 event3"></beam> <!-- grace notes -->

Case 6: Beam across barline

Screenshot

The <beam> references the event in the next bar via its ID:

<beam events="event4 event5 event6 event7"></beam>

Responses to comments

Regarding using event IDs vs. numeric indexes: I strongly favor event IDs. Numeric indexes have a level of indirection and implicitness that I fear will cause unexpected bugs. With numeric indexes, both the MNX-consuming and MNX-producing code need to know more about the document state (specific <event> positions within the <sequence>) than simple event IDs. While it's true that numeric indexes make it easier to validate, it's still possible to validate beams using event IDs (and isn't too difficult).

Regarding cross-staff beams: I imagine this will be solved by adding something like other-staff="true" (or staff-idx="1") to the <note> object rather than at the beam level. The reason: the note definitely needs to know whether it's in the other staff, for rendering. So the beam would be encoded the same way for both of these cases:

Screenshot Screenshot

In both cases, it would be:

<beam events="event1 event2 event3 event4">

Regarding tremolos: I don't think this is related to beams, is it? Those look to be "multi-note tremolos" and are equally valid on beamed notes as on non-beamed notes. Let me know if I'm missing something here.

Pinging @mdgood for a review on these (he'd requested these examples).

bhamblok commented 3 years ago

Hi @adrianholovaty,

I support all your examples above, except for Case 4: Locations of secondary beam breaks. This example does not meet "a one-to-one mapping between a beam rendered in notation and a <beam> element." As you say there are "three separate rendered rectangles", I believe it would be even better to work with three elements to represent these "three rendered rectangles".

<beam events="event1 event2 event3 event4 event5 event6 event7 event8">
    <beam-level events="event1 event2 event3 event4" value="2" />
    <beam-level events="event5 event6 event7 event8" value="2" />
</beam>

It's a little more verbose, but I think it's better to encode the things that are visible (three rendered rectangles), instead of encoding the things that are "not visible" (like in this example, the second level of beaming which is not visible between event4 and event5).

PS: I'm not really sure if the name <beam-level> is the correct name for this element... any thoughts?

notator commented 3 years ago

Case 4: Leaving aside the issue of using IDs here, I agree with @bhamblok that it would be better to have a separate element for each rectangle. And, since the rectangles are beams, that's what I'd call them. Technically, the secondary beams are all constructed in the same way as the primary beam, so I don't see any real need to distinguish between the two. If the beams are nested, then the value attribute seems to be redundant. Nested beams make the construction of complex beam-block structures much easier than it would be using defined beam breaks.

Questions have been raised in this thread that have not yet been sufficiently discussed. For example:

  1. Should <beam>s be defined inside <sequence> elements?
  2. How should cross-staff beams be organised?
  3. How does one validate IDs (without looking at indices)?
  4. How do tremolo beams fit into the scheme of things?

So I think we need more time before the co-chair makes any final decisions.

adrianholovaty commented 3 years ago

@bhamblok and @notator: thanks for the feedback.

For case 4, I believe the most consistent, "MNX-y" approach is to not have to specify the secondary beams unless something is out of the ordinary. So this music...

Screenshot

...would be encoded simply as:

<beam events="event1 event2 event3 event4"></beam>

That is, the secondary beam would not need to be encoded, because it can be deduced from the notes' rhythmic durations (16th notes). This would be interpreted as "draw secondary beams with whatever break locations you desire."

This is consistent with other parts of MNX, such as the fact that you don't have to explicitly encode the final barline (because that's the common case).

Can anybody make a strong argument for requiring those secondary beams to always be encoded?

--

For situations where one does want to encode the secondary beam break locations, I like @bhamblok's suggestion of explicitly encoding the secondary (and tertiary, etc.) beams rather than the locations of the breaks. This is more explicit and direct. Hence the above example could also be encoded as:

<beam events="event1 event2 event3 event4">
    <beam events="event1 event2 event3 event4">
</beam>

This would be interpreted as "Draw a secondary beam, unbroken, across all four notes."

And case 4 from above would be encoded like this:

<beam events="event1 event2 event3 event4 event5 event6 event7 event8">
    <beam events="event1 event2 event3 event4"></beam>
    <beam events="event5 event6 event7 event8"></beam>
</beam>

I just made some small changes from @bhamblok's proposal:

This feels pretty good to me! Any other thoughts?

--

Regarding the location of <beams>: It could live within <measure> or <sequence>, and I don't see a huge advantage to either approach. The advantage of <measure> is that the beams are in a single place for the measure (rather than having to have a separate <beams> element for each <sequence>, which might get slightly irritating for a developer). The advantage of <sequence> is that the beam data lives a bit "closer" to the affected events.

Regarding cross-staff beams and tremolo, I gave some thoughts on those in my last comment.

Regarding validating event IDs in beams, you'd write code that looked at each <event> in the beam and made sure its rhythmic duration was valid, it was in a valid order, etc. I don't think it would be possible to do deep semantic validation at the DTD level, but proper semantic validation is likely not possible at the DTD level anyway.

notator commented 3 years ago

@adrianholovaty said

Can anybody make a strong argument for requiring those secondary beams to always be encoded?

The argument is that you then don't have to remember (or code for) different ways of coding beams. Coding beam breaks quickly gets difficult to follow in complex beam blocks -- I even find the simplest case (above) confusing: Is the break after <event4> or before it? Confusions like that can be completely avoided if the beams are coded explicitly. The depth of nesting can, of course, be compared to the duration classes to see that its consistent.

The advantage of coding <beam> inside <sequence> is that <sequence> controls the staff on which the (possibly cross-staff) notes are notated. So you don't need any other way to do that. As I said above, in MNX:

Beams never leave the "voice" in which they begin. (A "voice" is a sequence of <sequence>s in consecutive <measure>s.)

Since that's the case, and the vast majority of beams stay inside a single measure, Measure Location Syntax, or simple indexing, would be easier to use and maintain than IDs.

Can you say exactly how you want to code tremolo beams? I agree with @clnoel that they should be considered as part of this issue.

validating event IDs in beams, you'd write code that looked at each in the beam and made sure its rhythmic duration was valid, it was in a valid order, etc.

If you are going to check that the IDs are in the correct part and voice, and that they are in valid order, you are going to have to maintain a list of ID positions in the entire data structure. If you've already got the data structure, you don't need the IDs... The alternative is simply not to validate the IDs, but I think that's a recipe for disaster.

mdgood commented 3 years ago

This is looking good. Just a few comments on some topics that have come up:

Regarding beams and tremolos, MusicXML 1.0 followed MuseData in trying to encode tremolos with "repeater" beams. But that was impractical and we had to deprecate it. Beams and tremolos are really semantically different things, even if they sometimes share an element of appearance, and I think they are best represented separately. @notator, you may want to take a look at the way MusicXML 3.1 represents tremolos. I think most of it could be adopted by MNX, with some tweaks to the interaction between beams and tremolos to better fit within MNX's design.

bhamblok commented 3 years ago

I would again like to argument against using measure location syntax instead of event ID's. First my simple, meaningless, arguments...

But most importantly, it would not work nicely when MNX is being used as a living document, when it is being used as a data-structure during runtime. I mentioned this before in other issues (#193), and I would like again to reference to all arguments written down nicely by @jsutdolph in his comment: https://github.com/w3c/mnx/issues/65#issuecomment-368899649. But... as I said, I think using UUID's, or any variant of this kind of concept, would be a little overkill. Short unique ID's would suffice.

notator commented 3 years ago

@mdgood said:

I am in favor of <beam> inside <sequence> ...

Thanks for the clarification. :-) Its not vital, but I'd prefer to have a <beams> element enclosing the <beam> elements. What do you think?


I wonder if we could use measure location syntax as James suggests. [...] The problem I see is with grace note beams, which currently are not encoded separately with measure location syntax unless you use an event ID.

I've occasionally been a bit confused about this myself, so its probably my fault that you've got me wrong there. I'm not suggesting that we use measure location syntax, I'm suggesting we use indexing. If we use indices, there is no problem with grace note beams. See https://github.com/w3c/mnx/issues/198#issuecomment-719932556. Case 5:

Case5

would be coded like this:

...
    <sequence>
        <event>...</event> <!-- event 1 -->
        <grace>
            <event>...</event> <!-- event 2 -->
            <event>...</event> <!-- event 3 -->
        </grace>
        <event>...</event> <!-- event 4 -->
        <event>...</event> <!-- event 5 -->
        <event>...</event> <!-- event 6 -->
        <event>...</event> <!-- event 7 -->
        <event>...</event> <!-- event 8 -->
        <event>...</event> <!-- event 9 -->
        <event>...</event> <!-- event 10 -->
        <beams>
            <beam beginEvent="1" endEvent="6" />
            <beam beginEvent="2" endEvent="3">      <!-- primary grace note beam -->
                <beam beginEvent="2" endEvent="3" /> <!-- secondary grace note beam -->
            </beam>
            <beam beginEvent="7" endEvent="10" />
        </beams>
    <sequence>
...

Cross-measure beams would be defined using a cross-measure index consisting of a ":"-separated string containing a (relative) measure index + ":" + the end event's index in that measure. Case 6;

Case6

would be coded like this:

...
<measure>
    <sequence>
        <event><rest/></event>
        <event>...</event>
        <event>...</event> 
        <event>...</event>
        <event>...</event>
        <beams>
            <beam beginEvent="4" endEvent="1:2" />
        </beams>
    <sequence>
</measure>
<measure>
    <sequence>
        <event>...</event>
        <event>...</event>
        <event><rest/></event>
        <event><rest/></event>
    <sequence>
</measure>
...

I've left out the comments here, and it still looks intuitively comprehensible. Note that the use of indices scales much better than using IDs in large files (the indices stay at this order of size, and don't explode). A further possibility might be to define the beam in the target measure, and index backwards. (That would be easier to connect up when parsing sequentially, but its less intuitive to read, so I'm not sure if it should be allowed. I'm generally not in favour of allowing more than one way to do something - that just leads to code bloat.) The beam definition, if put in the second measure, could be either

        <beam beginEvent="2" endEvent="-1:4" />

or

        <beam beginEvent="-1:4" endEvent="2" />

@mdgood again:

For secondary beams I think it would still be good to (perhaps optionally) encode the level, for complex situations such as 32nd's breaking within 16th's breaking within eighths.

Here's an example, to see how that would work: beams

        <beams>
            <beam beginEvent="1" endEvent="13">
                <beam beginEvent="1" endEvent="6">
                    <beam beginEvent="3" endEvent="6" />
                </beam>
                <beam beginEvent="7" endEvent=13">
                    <beam beginEvent="7" endEvent="8" />
                    <beam beginEvent="10" endEvent="11" />
                    <beam beginEvent="12" endEvent="13" />
                </beam>
            </beam>
            <beam beginEvent="14" endEvent="17">
                <beam beginEvent="14" endEvent="17">
                    <beam beginEvent="15" endEvent="16" />
                </beam>
            </beam>
            <beam beginEvent="18" endEvent="21">
                <beam beginEvent="18" endEvent=21">
                    <beam beginEvent="18" endEvent="21" />
                </beam>
            </beam>
            <beam beginEvent="22" endEvent="25">
                <beam beginEvent="22" endEvent="25">
                    <beam beginEvent="22" endEvent="23" />
                    <beam beginEvent="24" endEvent="25" />
                </beam>
            </beam>
        </beams>

My own feeling is that optional level attributes would just be mistakes waiting to happen. What would happen if the optional level attribute conflicted with the given nesting? Of course, as with the <event> numbers in the first example above, one could always write comments into the file. I think the nesting is easy enough to understand as it is: the 32nds are all in the same column, as are the 16ths and 8ths. Its also very easy to see that nested beams have beginnings and endings in the range given by their containing beam, and that successive beams contained by the same beam (or no beam) don't overlap. (In the above example, the /8 beams go from event 1-13, then 14-17, 18-21, 22-25)

Contrary to my original suggestion (in https://github.com/w3c/mnx/issues/198#issuecomment-717915237), I now think it would be better to implement beam-hooks simply by allowing <beam> elements to omit either their beginEvent or endEvent attribute (we don't then need to create a new element type): beamhooks

        <beams>
            <beam beginEvent="1" endEvent="3">
                <beam beginEvent="1" />
                <beam endEvent="3" />
            </beam>
            <beam beginEvent="4" endEvent="6">
                <beam endEvent="5" />
            </beam>
            <beam beginEvent="7" endEvent="9">
                <beam beginEvent="8" />
            </beam>
        </beams>

Cross-staff beams would be coded using MNX's standard ways of moving <event>s or <sequence>s to a different staff: (This diagram was first used in https://github.com/w3c/mnx/issues/193#issuecomment-689510641, but the beams were being coded there using the more MusicXML-like syntax.) crossStaffBeam1 Here, the beam definitions simply go in the sequence to which they belong:

    <part> <!-- a part on a grand staff having two staves -->
       ...
       <measure>
           ...
           <sequence staff="1">  /*** default staff number for this voice */
               <event value="/4">
                   <note pitch="C5"/>
               </event>
           </sequence>
           <sequence staff="2">  /*** default staff number for this voice  */
                <event value="/16">
                    <note pitch="Ab3"/>
                </event>
                <event value="/16">
                   <note pitch="C4"/>
                </event>
                <event value="/16" staff="1">  /*** override this voice's default staff number*/
                   <note pitch="F4"/>
                </event>
                <event value="/16" staff="1">  /*** override this voice's default staff number*/
                   <note pitch="E4"/>
                </event>
                <beams>
                    <beam beginEvent="1" endEvent="4" >
                        <beam beginEvent="1" endEvent="4" />
                    </beam>
                </beams>
           </sequence>
       </measure>
   </part>

Stem directions can be controlled at the event level using each <event>'s orient attribute, and at the sequence level using the <sequence> orient attribute. We need to define some rules for what happens if there is a conflict (e.g. if, in the above example, event 3 was explicity defined to be stem-up, but event 4 was set to stem-down. I think the beam definition should take precedence in such cases, so, since the beam is defined by event 4, event 4's setting takes precedence over event 3's.


Tremolos:

you may want to take a look at the way MusicXML 3.1 represents tremolos

I've looked at tremolos in the MusicXML docs, but can't really see how two-note tremolos are supposed to work without seeing an example that uses "start and stop types". I'm okay with treating all tremolos as ornaments rather than as beam types, and moving them into a different issue at some point. The MNX Draft Spec §6.4.5 currently says that the code for ornaments has to be migrated from MusicXML, so there's obviously room for discussion! :-) Treating tremolos as ornaments would, if anything, support my original proposal. They are not unlike trills that are notated with an ancillary note that determines which note to trill with. The only real difference is that tremolos use a different graphical representation for the ancillary note(s). But applications can infer such a representation for tremolo ancillaries, so MNX does not have to go into the details (apart from coding the details I put in my proposal)...

adrianholovaty commented 3 years ago

Some related pull requests: https://github.com/w3c/mnx/pull/205 and https://github.com/w3c/mnxconverter/pull/6

adrianholovaty commented 3 years ago

Marking this as closed, as we've worked out the basics beaming (see docs here). One outstanding beaming issue is cross-staff beams; #219 has a proposal for those, so that issue remains open.