verovio icon indicating copy to clipboard operation
verovio copied to clipboard

Time-reversed beamSpan@plist behavior

Open craigsapp opened this issue 2 years ago • 0 comments

When the time order of ID references in a beamSpan@plist are reversed, the slope of the beam is negated, caused by the assumption that the plist is time sorted (or at least that the endpoints are time sorted).

Here is an example:

Screen Shot 2022-02-20 at 5 40 27 PM
Click to view MEI data for above example
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt />
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2022-02-20T17:37:39" version="3.9.0-dev-93a6934">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="my1g1q7">
    <score xml:id="subgqe3">
     <scoreDef xml:id="sdi2iao">
      <staffGrp xml:id="sfodwl6">
       <staffDef xml:id="sscfq3m" n="1" lines="5">
        <clef xml:id="cl21gk7" shape="G" line="2" />
        <meterSig xml:id="metersig-L2F1" count="3" unit="8" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="s6qlbpv" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <rest xml:id="rest-L3F1" dur="4" />
         <note xml:id="note-L4F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="ba8be3h" plist="#note-L7F1 #note-L6F1 #note-L4F1" startid="#note-L4F1" endid="#note-L7F1" />
      </measure>
      <measure xml:id="measure-L5">
       <staff xml:id="staff-L5F1N1" n="1">
        <layer xml:id="layer-L5F1N1" n="1">
         <note xml:id="note-L6F1" dur="8" oct="4" pname="d" accid.ges="n" />
         <note xml:id="note-L7F1" dur="8" oct="4" pname="c" accid.ges="n" />
         <rest xml:id="rest-L8F1" dur="8" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L9">
       <staff xml:id="staff-L9F1N1" n="1">
        <layer xml:id="layer-L9F1N1" n="1">
         <rest xml:id="rest-L10F1" dur="4" />
         <note xml:id="note-L11F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="bajjy18" plist="#note-L14F1 #note-L13F1 #note-L11F1" startid="#note-L11F1" endid="#note-L14F1" />
      </measure>
      <measure xml:id="measure-L12">
       <staff xml:id="staff-L12F1N1" n="1">
        <layer xml:id="layer-L12F1N1" n="1">
         <note xml:id="note-L13F1" dur="8" oct="4" pname="f" accid.ges="n" />
         <note xml:id="note-L14F1" dur="8" oct="4" pname="g" accid.ges="n" />
         <rest xml:id="rest-L15F1" dur="8" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

Putting the ID refs in time order fixes the problem: Screen Shot 2022-02-20 at 5 50 21 PM

Click to view MEI data for above example
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt />
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2022-02-20T17:37:39" version="3.9.0-dev-93a6934">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="my1g1q7">
    <score xml:id="subgqe3">
     <scoreDef xml:id="sdi2iao">
      <staffGrp xml:id="sfodwl6">
       <staffDef xml:id="sscfq3m" n="1" lines="5">
        <clef xml:id="cl21gk7" shape="G" line="2" />
        <meterSig xml:id="metersig-L2F1" count="3" unit="8" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="s6qlbpv" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <rest xml:id="rest-L3F1" dur="4" />
         <note xml:id="note-L4F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="ba8be3h" plist="#note-L4F1 #note-L6F1 #note-L7F1" startid="#note-L4F1" endid="#note-L7F1" />
      </measure>
      <measure xml:id="measure-L5">
       <staff xml:id="staff-L5F1N1" n="1">
        <layer xml:id="layer-L5F1N1" n="1">
         <note xml:id="note-L6F1" dur="8" oct="4" pname="d" accid.ges="n" />
         <note xml:id="note-L7F1" dur="8" oct="4" pname="c" accid.ges="n" />
         <rest xml:id="rest-L8F1" dur="8" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L9">
       <staff xml:id="staff-L9F1N1" n="1">
        <layer xml:id="layer-L9F1N1" n="1">
         <rest xml:id="rest-L10F1" dur="4" />
         <note xml:id="note-L11F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="bajjy18" plist="#note-L11F1 #note-L13F1 #note-L14F1" startid="#note-L11F1" endid="#note-L14F1" />
      </measure>
      <measure xml:id="measure-L12">
       <staff xml:id="staff-L12F1N1" n="1">
        <layer xml:id="layer-L12F1N1" n="1">
         <note xml:id="note-L13F1" dur="8" oct="4" pname="f" accid.ges="n" />
         <note xml:id="note-L14F1" dur="8" oct="4" pname="g" accid.ges="n" />
         <rest xml:id="rest-L15F1" dur="8" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

Of course, it is more logical to place the @plist in time-sorted order, but I do not see that requirement here: https://music-encoding.org/guidelines/dev/attribute-classes/att.plist.html

Putting a sanity check to test if the @plist is time ordered would be good (checking against reverse time order and random order). If discouraged, then perhaps add a time order rule for beamSpan@plist in MEI Schematron.


An interesting case occurs if the @plist does not include the @startid or @endid elements:

Screen Shot 2022-02-20 at 5 55 27 PM
Click to view MEI data for above example
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt />
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2022-02-20T17:37:39" version="3.9.0-dev-93a6934">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="my1g1q7">
    <score xml:id="subgqe3">
     <scoreDef xml:id="sdi2iao">
      <staffGrp xml:id="sfodwl6">
       <staffDef xml:id="sscfq3m" n="1" lines="5">
        <clef xml:id="cl21gk7" shape="G" line="2" />
        <meterSig xml:id="metersig-L2F1" count="3" unit="8" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="s6qlbpv" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <rest xml:id="rest-L3F1" dur="4" />
         <note xml:id="note-L4F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="ba8be3h" plist="#note-L4F1 #note-L6F1" startid="#note-L4F1" endid="#note-L7F1" />
      </measure>
      <measure xml:id="measure-L5">
       <staff xml:id="staff-L5F1N1" n="1">
        <layer xml:id="layer-L5F1N1" n="1">
         <note xml:id="note-L6F1" dur="8" oct="4" pname="d" accid.ges="n" />
         <note xml:id="note-L7F1" dur="8" oct="4" pname="c" accid.ges="n" />
         <rest xml:id="rest-L8F1" dur="8" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L9">
       <staff xml:id="staff-L9F1N1" n="1">
        <layer xml:id="layer-L9F1N1" n="1">
         <rest xml:id="rest-L10F1" dur="4" />
         <note xml:id="note-L11F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="bajjy18" plist="#note-L13F1 #note-L14F1" startid="#note-L11F1" endid="#note-L14F1" />
      </measure>
      <measure xml:id="measure-L12">
       <staff xml:id="staff-L12F1N1" n="1">
        <layer xml:id="layer-L12F1N1" n="1">
         <note xml:id="note-L13F1" dur="8" oct="4" pname="f" accid.ges="n" />
         <note xml:id="note-L14F1" dur="8" oct="4" pname="g" accid.ges="n" />
         <rest xml:id="rest-L15F1" dur="8" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

This is a corner case to think about: Probably it is better to allow the @startid and @endid ID refs to be added to @plist if they are not present in the list? Otherwise, printing a warning would be good when the @startid or @endid are not included in @plist (if @plist is explicitly given).

This leads to interesting cases where (1) The endpoints are excluded, and there is a single-note beam in the next example (which results in a visual quarter note). And (2) where the non-plist notes are not attached to the beam:

Screen Shot 2022-02-20 at 6 11 50 PM
Click to view MEI data for above example
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt />
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2022-02-20T17:37:39" version="3.9.0-dev-93a6934">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="my1g1q7">
    <score xml:id="subgqe3">
     <scoreDef xml:id="sdi2iao">
      <staffGrp xml:id="sfodwl6">
       <staffDef xml:id="sscfq3m" n="1" lines="5">
        <clef xml:id="cl21gk7" shape="G" line="2" />
        <meterSig xml:id="metersig-L2F1" count="3" unit="8" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="s6qlbpv" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <rest xml:id="rest-L3F1" dur="4" />
         <note xml:id="note-L4F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="ba8be3h" plist="#note-L6F1" startid="#note-L4F1" endid="#note-L7F1" />
      </measure>
      <measure xml:id="measure-L5">
       <staff xml:id="staff-L5F1N1" n="1">
        <layer xml:id="layer-L5F1N1" n="1">
         <note xml:id="note-L6F1" dur="8" oct="4" pname="d" accid.ges="n" />
         <note xml:id="note-L7F1" dur="8" oct="4" pname="c" accid.ges="n" />
         <rest xml:id="rest-L8F1" dur="8" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L9">
       <staff xml:id="staff-L9F1N1" n="1">
        <layer xml:id="layer-L9F1N1" n="1">
         <rest xml:id="rest-L10F1" dur="4" />
         <note xml:id="note-L11F1" dur="8" oct="4" pname="e" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="bajjy18" plist="#note-L11F1 #note-L14F1" startid="#note-L11F1" endid="#note-L14F1" />
      </measure>
      <measure xml:id="measure-L12">
       <staff xml:id="staff-L12F1N1" n="1">
        <layer xml:id="layer-L12F1N1" n="1">
         <note xml:id="note-L13F1" stem.dir="down" dur="8" oct="4" pname="f" accid.ges="n" />
         <note xml:id="note-L14F1" dur="8" oct="4" pname="g" accid.ges="n" />
         <rest xml:id="rest-L15F1" dur="8" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

The first case is not desired (since the eighth note looks like a quarter note), but the second case is useful to create a single layer with interlocking beamSpans:

Screen Shot 2022-02-20 at 6 20 21 PM
Click to view MEI data for above example
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt />
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2022-02-20T18:14:39" version="3.9.0-dev-93a6934">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mri4t7s">
    <score xml:id="s9lhrs0">
     <scoreDef xml:id="s3nbx86">
      <staffGrp xml:id="s95jbbt">
       <staffDef xml:id="s8t0tdi" n="1" lines="5">
        <clef xml:id="c2g68nc" shape="G" line="2" />
        <meterSig xml:id="metersig-L2F1" count="4" unit="4" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="snawn0w" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <note xml:id="note-L3F1" type="placed" dur="8" oct="4" pname="b" stem.dir="up" accid.ges="n" />
         <note xml:id="note-L4F1" type="placed" dur="8" oct="4" pname="b" stem.dir="down" accid.ges="n" />
         <note xml:id="note-L5F1" type="placed" dur="8" oct="4" pname="b" stem.dir="up" accid.ges="n" />
         <note xml:id="note-L6F1" type="placed" dur="8" oct="4" pname="b" stem.dir="down" accid.ges="n" />
         <note xml:id="note-L8F1" type="placed" dur="8" oct="4" pname="b" stem.dir="up" accid.ges="n" />
         <note xml:id="note-L9F1" type="placed" dur="8" oct="4" pname="b" stem.dir="down" accid.ges="n" />
         <note xml:id="note-L10F1" type="placed" dur="8" oct="4" pname="b" stem.dir="up" accid.ges="n" />
         <note xml:id="note-L11F1" type="placed" dur="8" oct="4" pname="b" stem.dir="down" accid.ges="n" />
        </layer>
       </staff>
       <beamSpan xml:id="bbtkp99" plist="#note-L3F1 #note-L5F1" startid="#note-L3F1" endid="#note-L5F1" />
       <beamSpan xml:id="asegser" plist="#note-L4F1 #note-L6F1" startid="#note-L4F1" endid="#note-L6F1" />
       <beamSpan xml:id="est32te" plist="#note-L8F1 #note-L10F1" startid="#note-L8F1" endid="#note-L10F1" />
       <beamSpan xml:id="f32tewe" plist="#note-L9F1 #note-L11F1" startid="#note-L9F1" endid="#note-L11F1" />
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

craigsapp avatar Feb 21 '22 02:02 craigsapp