rism-digital / verovio

🎵 Music notation engraving library for MEI with MusicXML and Humdrum support and various toolkits (JavaScript, Python)
https://www.verovio.org
GNU Lesser General Public License v3.0
683 stars 185 forks source link

Slur slur intersection #1150

Closed ndubo closed 2 years ago

ndubo commented 5 years ago

The following example shows two shorter slurs intersected by an overarching longer slur in the top part (clarinet), which simply does not look good. (Example taken form K. 581/01, NMA edition)

intersecting_slurs_581001

Here is the code (clarinet part only):

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<mei meiversion="3.0.0" xmlns="http://www.music-encoding.org/ns/mei">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title>K.581/01</title>
    <respStmt/>
   </titleStmt>
   <pubStmt/>
  </fileDesc>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mdiv_581001">
    <score xml:id="score_480">
     <scoreDef key.mode="major" key.pname="a" key.sig="3s" meter.count="4" meter.sym="common" meter.unit="4" xml:id="scoreDef_01">
      <staffGrp barthru="true" symbol="bracket" xml:id="staffGrp_01">
       <staffDef clef.line="2" clef.shape="G" key.sig="0" lines="5" n="1" trans.diat="-2" trans.semi="-3" xml:id="staffDef_P1">
        <label xml:id="label_P1">Clarinetto <lb xml:id="lb_P1"/>in La/A</label>
       </staffDef>              
      </staffGrp>
     </scoreDef>
     <section xml:id="section_564">
      <measure facs="#zoneOf_measure21" n="21" xml:id="m21_k581_001">
       <staff n="1" xml:id="staff_9144">
        <layer n="1" xml:id="layer_9150">
         <beam xml:id="beam_9156">
          <note dur="8" oct="6" pname="c" tstamp="1" xml:id="note_9162"/>
          <note dur="8" oct="5" pname="a" tstamp="1.5" xml:id="note_9168"/>
          <note dur="8" oct="5" pname="e" tstamp="2" xml:id="note_9174"/>
          <note accid="n" dur="8" oct="5" pname="f" tstamp="2.5" xml:id="note_9180"/>
         </beam>
         <beam xml:id="beam_9186">
          <note dur="8" oct="5" pname="b" tstamp="3" xml:id="note_9192"/>
          <note dur="8" oct="5" pname="g" tstamp="3.5" xml:id="note_9198"/>
          <note accid="s" dur="8" oct="5" pname="d" tstamp="4" xml:id="note_9204"/>
          <note dur="8" oct="5" pname="e" tstamp="4.5" xml:id="note_9210"/>
         </beam>
        </layer>
       </staff>
       <slur endid="#note_9180" staff="1" startid="#note_9162" xml:id="slur_9300"/>
       <slur endid="#note_9210" staff="1" startid="#note_9192" xml:id="slur_9306"/>
       <supplied xml:id="supplied_9307">
        <slur endid="#note_9210" lform="dotted" staff="1" startid="#note_9162" xml:id="slur_9307"/>
       </supplied>
      </measure>
      <measure facs="#zoneOf_measure22" n="22" xml:id="m22_k581_001">
       <staff n="1" xml:id="staff_9318">
        <layer n="1" xml:id="layer_9324">
         <beam xml:id="beam_9330">
          <note dur="8" oct="5" pname="a" tstamp="1" xml:id="note_9336"/>
          <note dur="8" oct="5" pname="f" tstamp="1.5" xml:id="note_9342"/>
          <note accid="s" dur="8" oct="5" pname="c" tstamp="2" xml:id="note_9348"/>
          <note dur="8" oct="5" pname="d" tstamp="2.5" xml:id="note_9354"/>
         </beam>
         <beam xml:id="beam_9360">
          <note dur="8" oct="5" pname="g" tstamp="3" xml:id="note_9366"/>
          <note dur="8" oct="5" pname="e" tstamp="3.5" xml:id="note_9372"/>
          <note dur="8" oct="4" pname="b" tstamp="4" xml:id="note_9378"/>
          <note accid="n" dur="8" oct="5" pname="c" tstamp="4.5" xml:id="note_9384"/>
         </beam>
        </layer>
       </staff>
       <slur endid="#note_9354" staff="1" startid="#note_9336" xml:id="slur_9474"/>
       <slur endid="#note_9384" staff="1" startid="#note_9366" xml:id="slur_9480"/>       
       <supplied xml:id="supplied_9475">
        <slur endid="#note_9384" lform="dotted" staff="1" startid="#note_9336" xml:id="slur_9475"/>
       </supplied>
      </measure>      
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

I assume that this may happen more often when there are shorter legato slurs and longer phrasing slurs at the same time, e.g. in 19th-century music.

craigsapp commented 5 years ago

Related to issues https://github.com/rism-ch/verovio/issues/1000 and https://github.com/rism-ch/verovio/issues/454.

craigsapp commented 5 years ago

Algorithm should probably be:

(1) If two slur endings occur on the same note, then the slur with the longer duration should be moved away from the notehead. (2) when a slur endpoint is moved in step 1, then also check for potential collisions and adjust the slur by moving the endpoints further away and/or increasing the curvature.

The following example is typeset in SCORE. The height of the shorter slurs is 2 diatonic steps (perpendicular to the line connecting the endpoints), while the height of the longer slurs is 4. The longer slurs needed a slight asymmetry in order to give them visual symmetry (curvature on the right is greater than on the left). The left endpoint of the long slurs were raised 1 diatonic step, and the right endpoint was raised 1.5 diatonic steps. This asymmetry and unequal vertical raising of the endpoints creates a visually balanced slur.

Screen Shot 2019-10-03 at 8 27 35 AM

SCORE PMX data:

8  1   0.000  0  0.0 100.00
14 1   0.000  1
1  1   3.240 15 20.0   0.00  0.5000  4
6  1   3.240 11 11.0  21.12 21.0000
1  1   9.049 13 20.0   0.00  0.5000  2
1  1  14.521 10 20.0   0.00  0.5000 -1
1  1  21.121 11 23.0   0.00  0.5000
1  1  26.593 14 20.0   0.00  0.5000  4
6  1  26.593 10 10.0  44.44 21.0000
1  1  32.065 12 20.0   0.00  0.5000  2
1  1  38.965  9 22.0   0.00  0.5000 -1
1  1  44.437 10 20.0   0.00  0.5000
14 1  50.169  1
1  1  53.409 13 20.0   0.00  0.5000  4
6  1  53.409  9  9.0  71.25 21.0000
1  1  58.881 11 20.0   0.00  0.5000  2
1  1  65.781  8 22.0   0.00  0.5000 -1
1  1  71.253  9 20.0   0.00  0.5000
1  1  76.725 12 20.0   0.00  0.5000  4
6  1  76.725  8  8.0  94.27 21.0000
1  1  82.197 10 20.0   0.00  0.5000  2
1  1  87.669  7 20.0   0.00  0.5000 -1
1  1  94.269  8 23.0   0.00  0.5000
14 1 100.000  1

5  1   3.240 17 13.0  21.12  2.0000 -1
5  1  26.593 16 12.0  44.44  2.0000 -1
5  1  53.409 15 12.0  71.25  2.0000 -1
5  1  76.725 14 10.0  94.27  2.0000 -1

5  1   3.240 18 13.5  44.44  4.0000 -1 0 0.6
5  1  53.409 16 11.5  94.27  4.0000 -1 0 0.6

Lines starting with 5 are slurs (at the bottom of the data). Slur height is 7th number on the line (2.0000 and 4.0000). For the longer slurs there is an asymmetry factor of 0.6 (10th number on the line).

craigsapp commented 4 years ago

Here is a related example:

Screen Shot 2020-01-28 at 07 09 30

The same measure typeset in Sibelius:

Screen Shot 2020-01-28 at 07 10 45

MEI data:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/4.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/4.0.0/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="4.0.0">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt />
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2020-01-28T07:09:34" version="2.5.0-dev-5ff46f4">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mdiv-0000001875792784">
    <score xml:id="score-0000000578266021">
     <scoreDef xml:id="scoredef-0000002066104050" midi.bpm="121">
      <staffGrp xml:id="staffgrp-0000000619969964">
       <staffDef xml:id="staffdef-0000001373207566" n="1" lines="5">
        <label xml:id="label-L4F1">Viola</label>
        <clef xml:id="clef-L6F1" shape="C" line="3" />
        <keySig xml:id="keysig-L8F1" pname="c" mode="major" sig="0" />
        <meterSig xml:id="metersig-L10F1" count="4" unit="4" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1" n="0">
       <staff xml:id="staff-0000001959347802" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <tuplet xml:id="tuplet-L14F1-L20F1" num="6" numbase="4" bracket.visible="false" num.format="count">
          <beam xml:id="beam-L14F1-L20F1">
           <note xml:id="note-L14F1" dur="8" oct="4" pname="f" accid.ges="n" />
           <note xml:id="note-L15F1" dur="8" oct="4" pname="d" accid="f" />
           <note xml:id="note-L16F1" dur="8" oct="4" pname="d" accid="n" />
           <note xml:id="note-L18F1" dur="8" oct="4" pname="d" accid.ges="n" />
           <note xml:id="note-L19F1" dur="8" oct="3" pname="b" accid="f" />
           <note xml:id="note-L20F1" dur="8" oct="4" pname="c" accid="f" />
          </beam>
         </tuplet>
         <tuplet xml:id="tuplet-L21F1-L26F1" num="6" numbase="4" bracket.visible="false" num.format="count">
          <beam xml:id="beam-L21F1-L26F1">
           <note xml:id="note-L21F1" dur="8" oct="4" pname="f" accid.ges="n" />
           <note xml:id="note-L22F1" dur="8" oct="4" pname="d" accid="f" />
           <note xml:id="note-L23F1" dur="8" oct="4" pname="d" accid="n" />
           <note xml:id="note-L24F1" dur="8" oct="4" pname="d" accid.ges="n" />
           <note xml:id="note-L25F1" dur="8" oct="3" pname="b" accid.ges="f" />
           <note xml:id="note-L26F1" dur="8" oct="4" pname="c" accid.ges="f" />
          </beam>
         </tuplet>
        </layer>
       </staff>
       <slur xml:id="slur-L14F1N1-L16F1" staff="1" startid="#note-L14F1" endid="#note-L16F1" />
       <slur xml:id="slur-L18F1-L20F1N1" staff="1" startid="#note-L18F1" endid="#note-L20F1" />
       <slur xml:id="slur-L14F1N2-L20F1N1" staff="1" startid="#note-L14F1" endid="#note-L20F1" />
       <slur xml:id="slur-L21F1N1-L23F1" staff="1" startid="#note-L21F1" endid="#note-L23F1" />
       <slur xml:id="slur-L24F1-L26F1N1" staff="1" startid="#note-L24F1" endid="#note-L26F1" />
       <slur xml:id="slur-L21F1N2-L26F1N1" staff="1" startid="#note-L21F1" endid="#note-L26F1" />
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>