Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System-level directions #1450

Open
craigsapp opened this issue Apr 17, 2024 · 44 comments
Open

System-level directions #1450

craigsapp opened this issue Apr 17, 2024 · 44 comments

Comments

@craigsapp
Copy link
Member

craigsapp commented Apr 17, 2024

It would be useful to have a concept of system-level directions (<dir>, and <tempo> in specific, possibly others).

Example:

Screenshot 2024-04-17 at 9 44 54 AM

The highlighted text is at the system level. Another example in the same score:

Screenshot 2024-04-17 at 9 44 36 AM

Not exactly the same since it is still staff-level directions, but MEI currently allows duplicating the text onto multiple staves:

Screenshot 2024-04-17 at 10 07 56 AM
Click to view MEI data for above example.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/5.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/5.0/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">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt>
    <unpub>This MEI file was created by Verovio's Humdrum converter. When published, this unpub element should be removed, and the enclosing pubStmt element should be properly filled out.</unpub>
   </pubStmt>
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2024-04-17T09:54:40" version="4.2.0-dev-3d89370-dirty">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <extMeta>
   <frames xmlns="http://www.humdrum.org/ns/humxml">
    <metaFrame n="11" token="!!!system-decoration: [(s1,s2)][(s3,s4)]" xml:id="L12">
     <frameInfo>
      <startTime float="4" />
      <frameType>reference</frameType>
      <referenceKey>system-decoration</referenceKey>
      <referenceValue>[(s1,s2)][(s3,s4)]</referenceValue>
     </frameInfo>
    </metaFrame>
   </frames>
  </extMeta>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mf5dxlc">
    <score xml:id="sqstm9l">
     <scoreDef xml:id="sjivw2w" midi.bpm="400.000000">
      <staffGrp xml:id="s1vbxkrh" bar.thru="false">
       <staffGrp xml:id="s1h05qmo" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L1F4" n="1" lines="5">
         <label xml:id="label-L5F4">part 1</label>
         <clef xml:id="clef-L6F4" shape="G" line="2" />
         <meterSig xml:id="metersig-L8F4" count="4" unit="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L1F3" n="2" lines="5">
         <label xml:id="label-L5F3">part 2</label>
         <clef xml:id="clef-L6F3" shape="G" line="2" />
         <meterSig xml:id="metersig-L8F3" count="4" unit="4" />
        </staffDef>
       </staffGrp>
       <staffGrp xml:id="s1w5qdjd" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L1F2" n="3" lines="5">
         <label xml:id="label-L5F2">part 3</label>
         <clef xml:id="clef-L6F2" shape="C" line="3" />
         <meterSig xml:id="metersig-L8F2" count="4" unit="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L1F1" n="4" lines="5">
         <label xml:id="label-L5F1">part 4</label>
         <clef xml:id="clef-L6F1" shape="F" line="4" />
         <meterSig xml:id="metersig-L8F1" count="4" unit="4" />
        </staffDef>
       </staffGrp>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="staff-L1F4" n="1">
        <layer xml:id="layer-L1F4N1" n="1">
         <note xml:id="note-L9F4" dur="1" oct="5" pname="g" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L1F3" n="2">
        <layer xml:id="layer-L1F3N1" n="1">
         <note xml:id="note-L9F3" dur="1" oct="5" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L1F2" n="3">
        <layer xml:id="layer-L1F2N1" n="1">
         <note xml:id="note-L9F2" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L1F1" n="4">
        <layer xml:id="layer-L1F1N1" n="1">
         <note xml:id="note-L9F1" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <tempo xml:id="tempo-L8F4" place="above" staff="1 3" tstamp="1.000000">Allegro</tempo>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

The tempo direction:

       <tempo xml:id="tempo-L8F4" place="above" staff="1 3" tstamp="1.000000">Allegro</tempo>

The problem is that when extracting parts from a full score, there is not enough information to extract the system-level tempo or rehearsal number other than by inference, which will not always be correct (most particularly when the system-level text is attached to only the top staff, so it would be difficult to differentiate between text that needs to be extracted from the top staff when creating a part from another staff). In the short example, part 2 should be extracted as:

Screenshot 2024-04-17 at 10 13 02 AM

One possibility is to add @system="true":

       <tempo xml:id="tempo-L8F4" place="above" system="true" staff="1 3" tstamp="1.000000">Allegro</tempo>

(where @staff="1 3" would be optional, or probably best omitted in favor of @system="true" taking over its role).

Then in <scoreDef> elements such as <staffDef> and/or <staffGrp> add @system (or @systemDir, etc.) to indicate where tempo@system placements should occur:

     <scoreDef xml:id="sjivw2w" midi.bpm="400.000000">
      <staffGrp xml:id="s1vbxkrh" bar.thru="false">
       <staffGrp xml:id="s1h05qmo" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L1F4" n="1" lines="5" system="true">
         <label xml:id="label-L5F4">part 1</label>
         <clef xml:id="clef-L6F4" shape="G" line="2" />
         <meterSig xml:id="metersig-L8F4" count="4" unit="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L1F3" n="2" lines="5">
         <label xml:id="label-L5F3">part 2</label>
         <clef xml:id="clef-L6F3" shape="G" line="2" />
         <meterSig xml:id="metersig-L8F3" count="4" unit="4" />
        </staffDef>
       </staffGrp>
       <staffGrp xml:id="s1w5qdjd" bar.thru="true" symbol="bracket" system="true">
        <staffDef xml:id="staffdef-L1F2" n="3" lines="5">
         <label xml:id="label-L5F2">part 3</label>
         <clef xml:id="clef-L6F2" shape="C" line="3" />
         <meterSig xml:id="metersig-L8F2" count="4" unit="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L1F1" n="4" lines="5">
         <label xml:id="label-L5F1">part 4</label>
         <clef xml:id="clef-L6F1" shape="F" line="4" />
         <meterSig xml:id="metersig-L8F1" count="4" unit="4" />
        </staffDef>
       </staffGrp>
      </staffGrp>
     </scoreDef>

When extracting a part, the original <scoreDef> staffDef@system="true" can be applied to the extracted part (which is why tempo@staff="1 3" should best be removed, since there is no longer a staff 3 and staff 1 has changed (although this could be handled as part of the part extract process).

@rettinghaus
Copy link
Member

Already implemented with @part="all".

@craigsapp
Copy link
Member Author

craigsapp commented Apr 17, 2024

Thanks. Can you demonstrate an example (using the short example above)?

https://music-encoding.org/guidelines/v5/attribute-classes/att.partIdent.html

Screenshot 2024-04-17 at 10 56 22 AM

You mean @part="%all"? And I am presuming that it is not yet implemented in verovio?

And I don't want this:

Screenshot 2024-04-17 at 10 57 32 AM

@rettinghaus
Copy link
Member

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/5.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/5.0/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">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt>
    <unpub>This MEI file was created by Verovio's Humdrum converter. When published, this unpub element should be removed, and the enclosing pubStmt element should be properly filled out.</unpub>
   </pubStmt>
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2024-04-17T09:54:40" version="4.2.0-dev-3d89370-dirty">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <extMeta>
   <frames xmlns="http://www.humdrum.org/ns/humxml">
    <metaFrame n="11" token="!!!system-decoration: [(s1,s2)][(s3,s4)]" xml:id="L12">
     <frameInfo>
      <startTime float="4" />
      <frameType>reference</frameType>
      <referenceKey>system-decoration</referenceKey>
      <referenceValue>[(s1,s2)][(s3,s4)]</referenceValue>
     </frameInfo>
    </metaFrame>
   </frames>
  </extMeta>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mf5dxlc">
    <score xml:id="sqstm9l">
     <scoreDef xml:id="sjivw2w" midi.bpm="400.000000">
      <staffGrp xml:id="s1vbxkrh" bar.thru="false">
       <staffGrp xml:id="s1h05qmo" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L1F4" n="1" lines="5">
         <label xml:id="label-L5F4">part 1</label>
         <clef xml:id="clef-L6F4" shape="G" line="2" />
         <meterSig xml:id="metersig-L8F4" count="4" unit="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L1F3" n="2" lines="5">
         <label xml:id="label-L5F3">part 2</label>
         <clef xml:id="clef-L6F3" shape="G" line="2" />
         <meterSig xml:id="metersig-L8F3" count="4" unit="4" />
        </staffDef>
       </staffGrp>
       <staffGrp xml:id="s1w5qdjd" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L1F2" n="3" lines="5">
         <label xml:id="label-L5F2">part 3</label>
         <clef xml:id="clef-L6F2" shape="C" line="3" />
         <meterSig xml:id="metersig-L8F2" count="4" unit="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L1F1" n="4" lines="5">
         <label xml:id="label-L5F1">part 4</label>
         <clef xml:id="clef-L6F1" shape="F" line="4" />
         <meterSig xml:id="metersig-L8F1" count="4" unit="4" />
        </staffDef>
       </staffGrp>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1">
       <staff xml:id="staff-L1F4" n="1">
        <layer xml:id="layer-L1F4N1" n="1">
         <note xml:id="note-L9F4" dur="1" oct="5" pname="g" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L1F3" n="2">
        <layer xml:id="layer-L1F3N1" n="1">
         <note xml:id="note-L9F3" dur="1" oct="5" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L1F2" n="3">
        <layer xml:id="layer-L1F2N1" n="1">
         <note xml:id="note-L9F2" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L1F1" n="4">
        <layer xml:id="layer-L1F1N1" n="1">
         <note xml:id="note-L9F1" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <tempo xml:id="tempo-L8F4" place="above" staff="1 3" part="%all" tstamp="1.000000">Allegro</tempo>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

@craigsapp
Copy link
Member Author

Thanks for the example. The motivation for this feature is related to condensed scores in verovio. In this case it is not directly related to part extraction, but rather the desire to view system-level text in cases where one or more of the staves are condensed that have text (tempo, rit., accel., rehearsal marks, etc).

Example:

Screenshot 2024-04-19 at 10 23 54 AM
Click to view MEI data for above example.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/5.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/5.0/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">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title>Grave</title>
   </titleStmt>
   <pubStmt>
    <unpub>This MEI file was created by Verovio's Humdrum converter. When published, this unpub element should be removed, and the enclosing pubStmt element should be properly filled out.</unpub>
   </pubStmt>
  </fileDesc>
  <encodingDesc>
   <appInfo>
    <application isodate="2024-04-19T10:07:09" version="4.2.0-dev-3d89370-dirty">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work xml:id="work0_encoded" type="encoded">
    <title type="uniform">
     <titlePart type="movementName" analog="humdrum:OMD">Grave</titlePart>
    </title>
   </work>
  </workList>
  <extMeta>
   <frames xmlns="http://www.humdrum.org/ns/humxml">
    <metaFrame n="0" token="!!!OMD: Grave" xml:id="L1">
     <frameInfo>
      <startTime float="0" />
      <frameType>reference</frameType>
      <referenceKey>OMD</referenceKey>
      <referenceValue>Grave</referenceValue>
     </frameInfo>
    </metaFrame>
    <metaFrame n="23" token="!!!verovio: condense auto" xml:id="L24">
     <frameInfo>
      <startTime float="36" />
      <frameType>reference</frameType>
      <referenceKey>verovio</referenceKey>
      <referenceValue>condense auto</referenceValue>
     </frameInfo>
    </metaFrame>
    <metaFrame n="24" token="!!!system-decoration: [(s1,s2)][(s3,s4)]" xml:id="L25">
     <frameInfo>
      <startTime float="36" />
      <frameType>reference</frameType>
      <referenceKey>system-decoration</referenceKey>
      <referenceValue>[(s1,s2)][(s3,s4)]</referenceValue>
     </frameInfo>
    </metaFrame>
   </frames>
  </extMeta>
 </meiHead>
 <music decls="#work0_encoded">
  <body>
   <mdiv xml:id="m1iwncdw">
    <score xml:id="s1i9sp1d">
     <scoreDef xml:id="s1ohoddf" midi.bpm="40.000000">
      <staffGrp xml:id="s10tqruq" bar.thru="false">
       <staffGrp xml:id="s17z2eo8" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L2F4" n="1" lines="5">
         <clef xml:id="c1gi6ole" shape="G" line="2" />
        </staffDef>
        <staffDef xml:id="staffdef-L2F3" n="2" lines="5">
         <clef xml:id="c1ur6af8" shape="G" line="2" />
        </staffDef>
       </staffGrp>
       <staffGrp xml:id="s1alrp7w" bar.thru="true" symbol="bracket">
        <staffDef xml:id="staffdef-L2F2" n="3" lines="5">
         <clef xml:id="cx3p1gj" shape="F" line="4" />
        </staffDef>
        <staffDef xml:id="staffdef-L2F1" n="4" lines="5">
         <clef xml:id="cx9bqg2" shape="F" line="4" />
        </staffDef>
       </staffGrp>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L2F1">
      <measure xml:id="measure-L1">
       <staff xml:id="staff-L2F4" n="1">
        <layer xml:id="layer-L1F4N1" n="1">
         <note xml:id="note-L4F4" dur="1" oct="5" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L2F3" n="2">
        <layer xml:id="layer-L1F3N1" n="1">
         <note xml:id="note-L4F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L2F2" n="3">
        <layer xml:id="layer-L1F2N1" n="1">
         <note xml:id="note-L4F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L2F1" n="4">
        <layer xml:id="layer-L1F1N1" n="1">
         <note xml:id="note-L4F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <tempo xml:id="tempo-L1F1" staff="1" tstamp="1.000000">Grave</tempo>
      </measure>
      <measure xml:id="measure-L5">
       <staff xml:id="staff-L5F4N1" n="1">
        <layer xml:id="layer-L5F4N1" n="1">
         <note xml:id="note-L6F4" dur="1" oct="5" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L5F3N1" n="2">
        <layer xml:id="layer-L5F3N1" n="1">
         <note xml:id="note-L6F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L5F2N1" n="3">
        <layer xml:id="layer-L5F2N1" n="1">
         <note xml:id="note-L6F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L5F1N1" n="4">
        <layer xml:id="layer-L5F1N1" n="1">
         <note xml:id="note-L6F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L7">
       <staff xml:id="staff-L7F4N1" n="1">
        <layer xml:id="layer-L7F4N1" n="1">
         <note xml:id="note-L8F4" dur="1" oct="5" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L7F3N1" n="2">
        <layer xml:id="layer-L7F3N1" n="1">
         <note xml:id="note-L8F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L7F2N1" n="3">
        <layer xml:id="layer-L7F2N1" n="1">
         <note xml:id="note-L8F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L7F1N1" n="4">
        <layer xml:id="layer-L7F1N1" n="1">
         <note xml:id="note-L8F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L9" right="dbl">
       <staff xml:id="staff-L9F4N1" n="1">
        <layer xml:id="layer-L9F4N1" n="1">
         <rest xml:id="rest-L10F4" dur="1" />
        </layer>
       </staff>
       <staff xml:id="staff-L9F3N1" n="2">
        <layer xml:id="layer-L9F3N1" n="1">
         <note xml:id="note-L10F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L9F2N1" n="3">
        <layer xml:id="layer-L9F2N1" n="1">
         <note xml:id="note-L10F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L9F1N1" n="4">
        <layer xml:id="layer-L9F1N1" n="1">
         <note xml:id="note-L10F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L11">
       <staff xml:id="staff-L11F4N1" n="1">
        <layer xml:id="layer-L11F4N1" n="1">
         <rest xml:id="rest-L13F4" dur="1" />
        </layer>
       </staff>
       <staff xml:id="staff-L11F3N1" n="2">
        <layer xml:id="layer-L11F3N1" n="1">
         <note xml:id="note-L13F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L11F2N1" n="3">
        <layer xml:id="layer-L11F2N1" n="1">
         <note xml:id="note-L13F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L11F1N1" n="4">
        <layer xml:id="layer-L11F1N1" n="1">
         <note xml:id="note-L13F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <tempo xml:id="dir-L12F1" place="above" staff="1" tstamp="1.000000">
        Allegro
       </tempo>
      </measure>
      <measure xml:id="measure-L14">
       <staff xml:id="staff-L14F4N1" n="1">
        <layer xml:id="layer-L14F4N1" n="1">
         <rest xml:id="rest-L15F4" dur="1" />
        </layer>
       </staff>
       <staff xml:id="staff-L14F3N1" n="2">
        <layer xml:id="layer-L14F3N1" n="1">
         <note xml:id="note-L15F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L14F2N1" n="3">
        <layer xml:id="layer-L14F2N1" n="1">
         <note xml:id="note-L15F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L14F1N1" n="4">
        <layer xml:id="layer-L14F1N1" n="1">
         <note xml:id="note-L15F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L16">
       <staff xml:id="staff-L16F4N1" n="1">
        <layer xml:id="layer-L16F4N1" n="1">
         <rest xml:id="rest-L17F4" dur="1" />
        </layer>
       </staff>
       <staff xml:id="staff-L16F3N1" n="2">
        <layer xml:id="layer-L16F3N1" n="1">
         <note xml:id="note-L17F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L16F2N1" n="3">
        <layer xml:id="layer-L16F2N1" n="1">
         <note xml:id="note-L17F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L16F1N1" n="4">
        <layer xml:id="layer-L16F1N1" n="1">
         <note xml:id="note-L17F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L18">
       <staff xml:id="staff-L18F4N1" n="1">
        <layer xml:id="layer-L18F4N1" n="1">
         <rest xml:id="rest-L19F4" dur="1" />
        </layer>
       </staff>
       <staff xml:id="staff-L18F3N1" n="2">
        <layer xml:id="layer-L18F3N1" n="1">
         <note xml:id="note-L19F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L18F2N1" n="3">
        <layer xml:id="layer-L18F2N1" n="1">
         <note xml:id="note-L19F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L18F1N1" n="4">
        <layer xml:id="layer-L18F1N1" n="1">
         <note xml:id="note-L19F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
      <measure xml:id="measure-L20" right="end">
       <staff xml:id="staff-L20F4N1" n="1">
        <layer xml:id="layer-L20F4N1" n="1">
         <rest xml:id="rest-L21F4" dur="1" />
        </layer>
       </staff>
       <staff xml:id="staff-L20F3N1" n="2">
        <layer xml:id="layer-L20F3N1" n="1">
         <note xml:id="note-L21F3" dur="1" oct="4" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L20F2N1" n="3">
        <layer xml:id="layer-L20F2N1" n="1">
         <note xml:id="note-L21F2" dur="1" oct="3" pname="c" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L20F1N1" n="4">
        <layer xml:id="layer-L20F1N1" n="1">
         <note xml:id="note-L21F1" dur="1" oct="2" pname="c" accid.ges="n" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

When using --condense auto in verovio and forcing the Allegro onto a system where all of the measures for the top staff are rests, this is the rendering of the score where the Allegro text disappears:

Screenshot 2024-04-19 at 10 25 24 AM

How should the "Allegro" be made to be displayed above the second staff when the first one is removed? (and similarly if part three were condensed, the text should move to part 4).

@pe-ro
Copy link
Contributor

pe-ro commented Apr 19, 2024

@part only applies in the generation of separate parts from a complete score. It doesn't have anything to do with which staves a direction should appear. <dir> allows multiple values for @staff for this purpose.

Generally, it's best to avoid procedural mark up ("do this") in a declarative markup ("this is") system. Condensing/expanding a score is a procedural issue that should be resolved by the processing software.

However, one could use dir/@type to mark certain directives as "system level"; where this is defined as a directive that must appear above the top staff of the system, if it's not already present in that staff. Presumably, Verovio could then use this information to force the "Allegro" to appear. If relying on @type isn't portable enough, then another attribute (say, @system with Boolean values) can be added.

Alternatively, one could treat all directives as "system level" and rely on the "if it's not already present" clause above to not display directives from other staves above the top staff, if the top staff already has that directive. (That's a long sentence! Is it clear?) This behavior could be turned on/off by a parameter or built into the behavior associated with --condense auto. This option doesn't expand the number of attributes already present on <dir>.

@craigsapp
Copy link
Member Author

craigsapp commented Apr 19, 2024

dir/@type seems like a good possibility. @type is more for informal use in practice (I use it to convert to HTML class names in the SVG output of verovio), so maybe dir/@func="system" perhaps to make it more formalized?

There currently is no dir/@func but there is tempo/@func (can @func hold multiple NMTOKENs?). Either @type or @func would work for me in any case.

That's a long sentence! Is it clear?

Not really 😜 , but I like dir/@type system, which seems not too difficult to implement in verovio.

The basic algorithm for <dir type="system" staff="1 3"> when condensing would be to place the staff 1 text on staff 2 if staff 1 is condensed. If staff 1 and 2 are condensed, then there would be no extra text displayed on staff 3, since the system-level text is already displayed there. If only staff 3 is condensed, then staff 4 would be used for the text instead.

@pe-ro
Copy link
Contributor

pe-ro commented Apr 19, 2024

Not clear, but you figured it out anyway. 👍

@craigsapp
Copy link
Member Author

@lpugin is not wanting @type (see issue rism-digital/verovio#3650), typically this sort of thing is done in verovio using @func (see bracketSpan@func, for example)

dir@func does not exist, so perhaps add to MEI description?

Also there is already tempo@func and a question would be if multiple functions can be be given (separated by spaces).

@lpugin
Copy link
Member

lpugin commented Apr 22, 2024

I think @func has been discuss as a possible attribute for refining the definition of dir, and I don't think it would be really appropriate for this.

Since this the issue is essentially related to the use of --condense, what about @scope?

@lpugin lpugin reopened this Apr 22, 2024
@pe-ro
Copy link
Contributor

pe-ro commented Apr 22, 2024

I agree that @func isn't appropriate here. But I'm also not particularly fond of @scope either. @scope sounds too broad, as though one can describe a range of possibilities when what we actually want to do is record an element's use in a limited scenario -- what should happen when the score is condensed / collapsed / shortened (as in "short score").

So, I'm not at all certain what the name should be, but I think we should be looking for a name that describes the element's ability to move when the score is condensed -- or perhaps also when it's expanded. We should also consider whether there are other possible values for this yet-unnamed attribute that describe other actions that can be taken when the score is collapsed/expanded.

If there are no other possible actions other than "move", then perhaps we can get by with @condense with a value of "move". Of course, in the absence of explicit instructions, where a directive, tempo marking, pedal mark, etc. is moved to has to be renderer defined. Another possibility is to explicitly capture where the <dir> should be moved to using a position relative to the system, such as "top" or "bottom", or to a particular staff, "above" or "below" plus a staff number, or "between" and 2 adjacent staff numbers.

If we think about the possible placement values, then perhaps the name of the attribute will become more clear.

@craigsapp
Copy link
Member Author

what should happen when the score is condensed / collapsed / shortened (as in "short score").

That is related to the @staff="1 3", where the systemness of the dir will try to place on staff 1 and 3, but if staff 1 does not exist, then it will be placed on staff 2. If staff 1 and 2 are not present, then the staff 1 placement will be ignored, since staff 3 has the system text.

If you are extracting a short score, then you would alter the dir@staff of system dirs in a similar manner while at the same time you are renumbering the staves.

I don't see a problem with @func. What is that supposed to be used for?

If there were no <tempo> element, how would such things be described in <dir>? This is a fairly similar case.

@pe-ro
Copy link
Contributor

pe-ro commented Apr 22, 2024

tempo/@func has a very specific purpose -- to provide a clue to the purpose of the marking. That is, it allows only the following values:

<valList type="closed">
  <valItem ident="continuous">
    <desc xml:lang="en">Marks a gradual change of tempo, such as "accel." or "rit."</desc>
  </valItem>
  <valItem ident="instantaneous">
    <desc xml:lang="en">Represents a static tempo instruction, such as a textual term like
      "Adagio", a metronome marking like "♩=70", or a combination of text and metronome
      indication.</desc>
  </valItem>
  <valItem ident="metricmod">
    <desc xml:lang="en">Captures a change in pulse rate (tempo) and/or pulse grouping
      (subdivision) in an "equation" of the form [tempo before change] = [tempo after
      change].</desc>
  </valItem>
  <valItem ident="precedente">
    <desc xml:lang="en">Indicates a change in pulse rate (tempo) and/or pulse grouping
      (subdivision) in an "equation" of the form [tempo after change] = [tempo before
      change]. The term "precedente" often appears following the "equation" to distinguish
      this kind of historical usage from the modern metric modulation form.</desc>
  </valItem>
</valList>

There is no @func attribute on <dir>, but because <tempo> is a specialized form of <dir>, I would expect a @func attribute on <dir> to behave the same way it does on <tempo>. This is not the case if we're going to use dir/@func to only describe behavior related to collapsing a score. Also, there's a general rule in XML, which I realize we've broken in specific cases (but mostly in terms of data type), not to define attributes with the same name differently on different elements. For these reasons, I don't think "func" is a good name for the property we want to record.

@pe-ro
Copy link
Contributor

pe-ro commented Apr 23, 2024

I'd like to roll back the conversation just a bit, when @craigsapp said:

The basic algorithm for <dir type="system" staff="1 3"> when condensing would be to place the staff 1 text on staff 2 if staff 1 is condensed. If staff 1 and 2 are condensed, then there would be no extra text displayed on staff 3, since the system-level text is already displayed there. If only staff 3 is condensed, then staff 4 would be used for the text instead.

My question is, what purpose is @type serving in this case? Wouldn't the effect be the same without it? The signal to condense the score is in the --condense parameter, so it seems to me that no signal is needed in the markup itself.

@craigsapp
Copy link
Member Author

My question is, what purpose is @type serving in this case? Wouldn't the effect be the same without it? The signal to condense the score is in the --condense parameter, so it seems to me that no signal is needed in the markup itself.

There needs to be some distinction between staff-level text and system-level. Staff-level text would not be displayed if the staff is hidden due to being condensed. System-level text would switch to another staff if the staff it is attached to is hidden due to being condensed. If there is no distinction, then things get complicated with condensed scores where text that needs to be displayed at the system level is now showing. Or conversely, text that should only be shown on a particular staff should not move to another staff if the original staff is suppressed due to being removed on a particular line due to the condense option.

@craigsapp
Copy link
Member Author

Here is an example of the concept of system-level text in Humdrum:

Screenshot 2024-04-22 at 5 46 43 PM

[View in VHV]

The text on lines 6 and 9 are not associated with any specific staff, and they instead apply to the entire system. The a parameter places the text above the system and b places it below.

If I extract a subscore (or if in theory some of the staves were hidden in a condensed score):

Screenshot 2024-04-22 at 5 48 23 PM

[View in VHV]

Extracting the parts into a short score of the inner parts, keeping the system-level text still visible above and below the score even though the original staff numbers of the top/bottom staff are different:

Screenshot 2024-04-22 at 5 49 39 PM

[View in VHV]

Notice that the system text is not altered and also does not have any staff assignment, since it is calculated automatically (for orchestral scores it gets more complicated where system-level text needs to be attached within the staff such as above the string parts as well as at the top of the system)


Here is an example of staff-level text in Humdrum

Screenshot 2024-04-22 at 5 54 38 PM

[View in VHV]

Now If I extract the two internal staves, the staff-level text attached to the top and bottom staves disappear since the were attached to staves that have been removed:

Screenshot 2024-04-22 at 5 55 52 PM

[View in VHV]

Here is the compiled filter where you can see that the text instructions are now gone from the data:

Screenshot 2024-04-22 at 5 57 04 PM

[View in VHV]

MEI <dir> are encoded in the second method at the staff level (where I currenty map Humdrum system-level text into staff-level text of MEI), so it is currently difficult to do system-level text in MEI that would be required for the condense option in verovio.

@lpugin
Copy link
Member

lpugin commented Apr 23, 2024

What about @condense.scope, or @condense.level ? I don't think we will find a single-word attribute name.

See here for previous discussions on @func.

@ahankinson
Copy link
Member

What about implementing rism-digital/verovio#3280 and using that to control the rendering options, instead of adding it to the encoding?

@craigsapp
Copy link
Member Author

craigsapp commented Apr 23, 2024

This is not a rendering option per se: there needs to be some attribute for a <dir> that allows for the transformation of the element. Some <dir> need to be treated as system-level elements and other are not supposed to be processed.

@condense.scope

In my opinion that is too specific and the functionality could extend beyond the condense feature of verovio.

@ahankinson
Copy link
Member

In your example of system-level text in Humdrum, aren't they just attached to the first staff? I didn't think **kern had the concept of a "system"?

@craigsapp
Copy link
Member Author

Yes, it looks like they are attached to the first staff (which is the bottom staff in the score):

Screenshot 2024-04-22 at 5 46 43 PM

The difference is that these are "global comments":

Screenshot 2024-04-23 at 12 58 03 AM

[View in VHV]

where global comments have two (or more) !!, while local comments have a single !. Notice in the above example that global comments can start before the data (which starts at line 2 in the above example), but local comments cannot (they have to belong to a specific spine/column).

Local comments would typically be used to add a comment relevant to a particular part, while the global comment would apply in general to all parts or not to any specific part.

!LO: and !!LO are structured comments where I stick visual layout parameters. Humdrum tools treat them as comments, but the Humdrum-to-MEI converter understands what they mean.

@craigsapp
Copy link
Member Author

Here is another system-level versus staff-level demo in Humdrum:

Screenshot 2024-04-23 at 1 14 26 AM

[View in VHV]

When there is a data spine to the left of the first staff-like spine (**kern in this case in the second column), then I treat that data as "system-level" data, which in this case is **harm (Roman-numeral harmony). This harmony data applies to all **kern spines/columns to the right of it. When I convert to MEI, the data is assigned to the bottom staff of the score, but only because I cannot specify showing below the system explicitly.

In this configuration:

Screenshot 2024-04-23 at 1 21 13 AM

[View in VHV]

I treat the **harm data as attached to the first staff-like spine to its left (which is the bottom staff of the system).

When converting to MEI, both examples will be explicitly attached to the bottom staff, although preferably the first case would be attached to the bottom of the system rather than the bottom staff (visually there would be no difference).

@rettinghaus
Copy link
Member

I still don't see the need for a new attribute.

<dir tstamp="1" staff="1" part"%all">

indicates clearly that this directive applies to all parts, i.e. if the first staff is not visible, I would expect it to appear on the next visible one. Whereas

<dir tstamp="1" staff="1" part"1">

would mean, if the first staff is not shown, the directive is also hidden.

@craigsapp
Copy link
Member Author

craigsapp commented Apr 23, 2024

<dir tstamp="1" staff="1" part="%all">

That seems like it could work although it has a different intended function? i.e., it is related to part extraction according to @pe-ro. I can't think of a specific conflicting case for not having it be used by --condense but there could be subtle differences.

@pe-ro
Copy link
Contributor

pe-ro commented Apr 23, 2024

Like @craigsapp says, I can't foresee the consequences of relying on @part to indicate how <dir> is to be displayed when condensing/expanding a score. Hence the need for a new attribute.

Currently, <dir> uses @place and @staff to indicate where to position the directive text, e.g., <dir place="above" staff="1"> and <dir place="between" staff="2 3">. MuseScore (and Humdrum, too?) allows text to be attached to a staff but also to be simultaneously treated as system-level text; that is, rendering it above or below the system regardless of its staff attachment. This means that the new attribute must be independent of the @place and @staff attribute combination.

[BTW, I looked into modifying the possible values of @place and @staff in an attempt to accommodate system-level directives, but ultimately realized the need for system-level text to be independent of @place and @staff.]

I hesitate to name the new attribute @func for the reason I stated earlier -- that its use on <dir> will conflict with its use on <tempo>, and for the fact that we may want to add dir/@func later. So, I propose creating @system on <dir> (and probably on all its derivatives too, such as <tempo>, <pedal>, etc.). @system will be optional and take the values "above" and "below" (in keeping with the values of @place when referring to staves).

Examples:
<dir place="above" staff="1" system="above"> indicates that the directive is attached to staff 1, but above the system when the score is condensed/optimized.

<dir place="between" staff="2 3" system="below"> says the the directive should be displayed between staves 2 and 3 in the full score, but below the system when the score is condensed.

<dir place="below" staff="4"> means that the directive is only attached to staff 4, and will not be displayed if that staff is condensed/optimized out of existence.

I'm not wedded to the name "system", but I think it's a good place to start because it draws attention to the difference between staff-attached and system-attached text. I don't think it's needed, but if we want to emphasize the association with condensing a full score, then other possible names might be "condense.place" or "con.place" (too cryptic?).

@lpugin
Copy link
Member

lpugin commented Apr 25, 2024

I think @system is a good name. I would suggest making it a boolean since we have the place in @place already. That will avoid the discussion on what do to if we have contradictory values. Also, since this will not be a widely used attribute, I would suggest making its name a bit more explanatory. Something like @system.level="true".

@ahankinson
Copy link
Member

The concept of a system barely exists in MEI. We have <sb />, but other than that it's an under-defined concept in the MEI world.

What about something where you can say that a <dir> is attached to all staves, rather than one single staff? That would avoid the use of the "system" in MEI. Something like @staff.all="true"?

Along with this we might want the ability to address staff groups for <dir> to display a direction only for that staff group, so @staff.group="1 2". This would point to the @n on a <staffGrp> element.

@craigsapp
Copy link
Member Author

craigsapp commented Apr 25, 2024

The concept of a system barely exists in MEI. We have , but other than that it's an under-defined concept in the MEI world.

That is because there is barely any orchestral music in MEI, where system-level text is more common and more complex than small ensembles. And somehow you want to make it as easy as possible to create parts from a full score encoding (although I am specifically wanting a feature to control the condensed score behavior of system-level text with verovio for now). Part extraction of text and condensed scores' texts are fairly well connected -- but not 100% (see example below) which is the concern about using @part="%all" as the boolean trigger for condensing behavior for text.

What about something where you can say that a

is attached to all staves, rather than one single staff? That would avoid the use of the "system" in MEI. Something like @staff.all="true"?

That is good provided that people do not confuse @staff.all as a replacement for @staff, which it is not (it is semantically equivalent to @system, so either would work). This is also similar to @part="%all". And any of these work for me as long as they will always work to produce proper rendering of system-level text with the condense option in verovio.

Along with this we might want the ability to address staff groups for <dir> to display a direction only for that staff group, so @staff.group="1 2". This would point to the @n on a element.

This would get complicated, since groups are hierarchical. @staff.group is heading towards @part, which could be a list of xml IDs for the groups defined in scoreDef.

I am thinking about that in implementing system-level text in the Humdrum-to-MEI converter. But this gets complicated to deal with in large orchestral scores, but it would be somewhat more system-like than group-like. For example if an entire group is condensed out of the score, the text of the group would most likely travel to the next group below in the score (unless that group had its own group-level text).

Here is an example from Don Juan by Richard Strauss, which potentially has group-level text:

image

https://ks15.imslp.org/files/imglnks/usimg/9/93/IMSLP18774-PMLP12183-Strauss_-_Don_Juan_(orch._score).pdf
(Page 12)

I highlighted the system level texts, which include a rehearsal mark, the word "tranquillo" and "calando poco" text and line after it.

The "calando poco" text behaves as if it were a group-level <dir>. But looking into the parts, it is really system level text, because it functions as @part="%all":

Viola part: https://vmirror.imslp.org/files/imglnks/usimg/c/cd/IMSLP53620-PMLP12183-StraussR-Op20.Viola.pdf

Screenshot 2024-04-25 at 2 36 03 AM

"calando poco" becomes "poco calando" (which is very annoying and breaks using @part="%all" somewhat), and it attached to the staff rather than the system, i.e., the text was duplicated on each divisi part. The "D" rehearsal mark remains at the system level, but the "tranquillo" does not since it is now at the staff level.

Looking at the Oboe part:

Screenshot 2024-04-25 at 2 40 51 AM

https://ks15.imslp.org/files/imglnks/usimg/b/bf/IMSLP47010-PMLP12183-Strauss_-_Don_Juan,_Op._20_(oboe_parts).pdf

Notice that "poco calando" is present in the part, even though there is no "poco calando" attached to the non-strings group, so that text is really at the system level rather than the group level, and it is just displayed at the group level (so equivalent to @parts="%all" in this case).

@pe-ro
Copy link
Contributor

pe-ro commented Apr 25, 2024

@lpugin, using Boolean values for @system doesn't allow one to capture where the directive is placed relative to the system like "above" and "below" do.

@pe-ro
Copy link
Contributor

pe-ro commented Apr 25, 2024

@ahankinson said

What about something where you can say that a <dir> is attached to all staves, rather than one single staff? That would avoid the use of the "system" in MEI. Something like @staff.all="true"?

We have to avoid confusion between 2 different definitions of "all". When there are 3 staves, "all" can mean "each and every one", such as "above staff 1 and above staff 2 and above staff 3". Or it can mean above the entire group of staves. So far, "all" has been used in the first sense. For example, @part="%all" means in every one of the parts. I think it would be misleading to switch to the second sense for @staff.all.

Also, what's the difference between @staff="all" and @staff.all="true"? In other words, why not allow the first, and not introduce another attribute? Aside from the definitional confusion around "all", there's the issue of conflating attachment to a staff and attachment to a system.

In short, I don't think @staff.all="true" will be helpful.

@craigsapp, the relationship between a score and parts is complex indeed. This is why MEI provides for explicit markup of each of these things separately. In some cases, it's relatively easy to generate one from the other, but problematic in others. I'm pretty sure there can never be a simple, fool-proof solution to this conundrum.

It seems to me that conversion of system-level text in Humdrum to MEI for display in Verovio is relatively easy -- convert it to staff-level text. This will result in explicit markup -- system-level text that was above staff 1 will remain attached to staff 1. It seems to me that the inverse -- converting staff-level text in MEI to system-level text in Humdrum -- is the real focus. That's not easy to pull off, but is that really a problem for MEI to resolve? It's not if we remain committed to declarative rather than procedural markup.

It's very confusing when you say that part generation and system-level text are different (rightly so IMO) but you bring in examples of the first to illustrate the second.

BTW, @part allows one to enumerate which parts carry the mark, e.g., <dir @part="flute1 flute2 viola bassi">pesante</dir>, where those parts are a subset of the score. Where a marking, such as "poco calando" appears only in the parts and not the score, adhering to the principle of explicit markup means one would have to provide markup for those parts separate from the score. I can't call it up right now, but I think we discussed this possibility in the past. I also think we resolved the issue with the high level of redundant markup this would lead to by allowing the part markup to reference markup in the score.

In any case, I think we should try to keep part generation and system-level text separate.

@craigsapp
Copy link
Member Author

using Boolean values for @system doesn't allow one to capture where the directive is placed relative to the system like "above" and "below" do.

I am thinking that @place and @staff would be handled as currently with <dir> (and <tempo>):

<dir place="above" staff="1 3" system="true">text</dir>

If not condensing a score, @system would be ignored. When condensing, the @system="true" would allow verovio (or other generic renderer) to automatically adjust @staff contents in order for the text to be displayed (on a system-by-system basis).

If staff 1 were condensed (removed) from a particular system line, @system="true" would permit the renderer to change its assignment to @staff="2", thus keeping it visible in the score when staff 1 has been removed due to being all rests.

If staff 2 were condensed, nothing would happen and `@staff="1 3" would be used as-is.

If staff 1 and staff 2 were condensed, then nothing would happen since the next lower staff (3) has an explicit assignment for the <dir> to display.

If staff 1, 2, and 3 were condensed, then staff 4 would be assigned the <dir>, which is taken from the original assignment on staff 3 (and the staff 1 text would not be visible).


@place="below" does present a problem for boolean @system (which is what you are probably saying). Using below for system-level text in orchestral scores is not common, but I would suggest Roman-numeral harmony would fit this category, which is typically placed below the system (while pop/rock/jazz chords are typically placed above the staff).

So perhaps used three states for @system is best: none, above, and below. Where none is the default state (meaning do not reassign staff assignments when creating a condensed score).

The behavior of @system="above" would be as described above.

The behavior of @system="below" would be reversed, and reassignments from condensed staves would go to the next higher staff instead of the next lower staff.

Example: suppose you have four staves and a harm:

<harm staff="4" place="below" system="below">

If staff 4 is condensed, then the <harm> would be reassigned to staff 3. If staves 3 and 4 are condensed, then <harm> would be reassigned to staff 2, and so on.

In general @place and @system will match, but it is possible for them probably to be independent in rare cases.

@ahankinson
Copy link
Member

That is because there is barely any orchestral music in MEI

I would say it's because there is no need for a "system" in a virtual musical environment, and thus a symbolic encoding, where a "border" isn't fixed. Systems (in the sense of a 'line break' for a staff) don't really exist, unless you need a fixed width (for human readability / legibility).

In common use, "staff" and "system" can be interchangeable, but (at least in my experience of MEI), they mean very specific and different things: A MEI staff is the line of music which is integral to the encoding, whereas a system is a mechanism to limit the width of a staff in a given context (and which can be ignored if you're rendering it in a context that doesn't need systems...)


When there are 3 staves, "all" can mean "each and every one", such as "above staff 1 and above staff 2 and above staff 3". Or it can mean above the entire group of staves.

@pe-ro I was just riffing, and didn't have a fully-formed plan. @lpugin requested a boolean, so I was trying to accommodate that. @staff="all" or @staff="every" could make the distinction?

But I'm 👎 on @system, since MEI doesn't really have a concept of systems.

@craigsapp
Copy link
Member Author

the relationship between a score and parts is complex indeed. This is why MEI provides for explicit markup of each of these things separately. In some cases, it's relatively easy to generate one from the other, but problematic in others. I'm pretty sure there can never be a simple, fool-proof solution to this conundrum.

Yes, there will be no fool-proof way of converting between a part in a <score> and in a <part>, but one goal will be to allow some automatic transformer to convert one way or the other which would allow minimal manual cleanup.

The Don Juan example is particularly complex, especially the divisi viola parts.

Generating cues in parts will take time (but can be simplified by using IDREFs to automatically copy musical content for cues. Page breaks are important for parts so the performers have time to turn the page (digital displays of scores in stead of paper will help minimize that problem).

@craigsapp
Copy link
Member Author

But I'm 👎 on @system, since MEI doesn't really have a concept of systems.

Buy you already pointed out <sb>, and I don't this it is called "staff begin" 😜

I don't care what it is called, as long as the functionality for preserving condensed score text being described here is present.

In musical context, a system is a collection of staves (usually attached together with a line at least on the left side) that have the same timeline. "Staff" and "system" are very distinct in my mind. You can have a single-staff system (which is typically a single part or two parts sharing a common staff, and where the concept of staff and system would get confusing). Having a concept of "system" for <dir> in a part would be useful when constructing a score from a part. This could be used to suppress text from all parts in the score and group them above the system rather than repeating on every staff. (as an aside: when doing OMR for an orchestral score, I do OMR on the parts rather than the full score, since there are lots of staff assignments for text dynamics, etc. that get wrong with OMR on the score.) So going from part to score is also a useful data processing path.

I will note that Roman numerals did not have a concept of zero (or more specifically positional notation), which is why were are not using them very much anymore...

@pe-ro
Copy link
Contributor

pe-ro commented May 8, 2024

Returning to this, I'm now thinking @lpugin (and @craigsapp too, originally) are on a reasonable path by suggesting an attribute for <dir> and its derivatives that can take a Boolean value. Will calling this attribute "detachable" work?

A little explanation of the term "detachable" -- the positional attributes (@staff, @place, etc.) are to be applied in the absence of the @detachable attribute or when its value is "false". @detachable="true" indicates that the positional attributes are "malleable" -- they can be adapted as necessary -- in certain circumstances, like when condensing a full score.

I haven't thought this through completely. I haven't considered what constitutes a complete list of the circumstances in which an indication can be moved. I'm inclined not to create such a list, though, the same way we don't specify exactly how/when a note can be moved (for collision avoidance, for example). I think @detachable will be renderer dependent in the same way.

@rettinghaus
Copy link
Member

Thinking of possibility that system text may appear on different levels of a score, i.e. above all staves, above every instrument group, below every staff etc. why not use the structural information we have in the scoreDef?

Let's take the following as example:

<scoreDef>
   <staffGrp label="system" xml:id="system">
      <staffGrp xml:id="grp01">
         <staffDef n="1" xml:id="stf01" />
         <staffDef n="2" xml:id="stf02" />
      </staffGrp>
      <staffGrp xml:id="grp02">
         <staffDef n="3" xml:id="stf03" />
         <staffDef n="4" xml:id="stf04" />
         <staffDef n="5" xml:id="stf05" />
         <staffDef n="6" xml:id="stf06" />
      </staffGrp>
   </staffGrp>
</scoreDef>

If we have a tempo that applies to all parts but just appears on top of every staff group, we could point to the IDs in the definition:

<tempo place="above" score.level="#grp01 #grp02">Adagio</tempo>

This is an alternative to the more simple staff attribute and can still be combined with part="%all".
Similarly for a directive that applies to every staff in the second group.

<dir place="below" score.level="#stf03 #stf04 #stf05 #stf06">calando</dir>

This would be the same as with the current staff attribute:

<dir place="below" staff="3 4 5 6">calando</dir>

This would bring the advantage that it wouldn't matter which staves would actually be visible, because the group structure would still be intact.

The more precise staff attribute could overrule the connection in score.level. Let's say we have a tempo that applies to the whole system, but is written only between the first two staves:

<tempo place="between" staff="1 2" score.level="#system">Presto</tempo>

@craigsapp
Copy link
Member Author

That seems to be a good method, probably the best proposed so far (along the lines I was thinking of at the bottom of the original post :-). And it would be possible to integrate with part extraction, as you note (i.e, still be useful in relation to working with @part="%all"), unlike a dedicated condense attribute.

For this full-score example:

image

The system has two groups at the top level, which is common for orchestral scores:

(1) Everything other than the strings
(2) The strings

The next level down in (1) is:

(1a) Woodwinds
(1b) Brass
(1c) Timpani

The <scoreDef> system will work as long as groups (1) and (2) are be defined in the digital score. Is that possible (having a group of groups, but no visible bracketing for (1) level)?

Adding this invisible outer grouping to the score would allow the tempo marking to be displayed in all cases where staves are hidden with the condense option in verovio. If the strings are tacet, then their group text would be suppressed; if the woodwinds are tacet (1a), then the group (1) text would still be visible above the brass group (1b).

When extracting a score only containing the brass parts, group (1b), the group (1) tempo marking should easily be extractable from the <scoreDef> hierarchy, and for a single part (staff), the same tempo marking should be extractable along with the part.

@rettinghaus
Copy link
Member

Sure. You can nest as many staffGrp elements as you like.

<scoreDef>
   <staffGrp xml:id="score">
       <staffGrp label="Everything other than the strings" xml:id="nonStrings">
          <staffGrp xml:id="woodwinds">
             <staffDef n="1" xml:id="stf01" />
             <staffDef n="2" xml:id="stf02" />
             <staffDef n="3" xml:id="stf03" />
             <staffDef n="4" xml:id="stf04" />
          </staffGrp>
          <staffGrp xml:id="brass">
             <staffDef n="5" xml:id="stf05" />
             <staffDef n="6" xml:id="stf06" />
          </staffGrp>
         <staffDef n="7" xml:id="stf07" label="timpani" />
      </staffGrp>
      <staffGrp xml:id="strings">
         <staffDef n="8" xml:id="stf08" />
         <staffDef n="9" xml:id="stf09" />
         <staffDef n="10" xml:id="stf10" />
         <staffDef n="11" xml:id="stf11" />
      </staffGrp>
   </staffGrp>
</scoreDef>

This is also allowed:

<scoreDef>
   <staffGrp>
      <staffGrp>
         <staffGrp>
            <staffGrp>
               <staffGrp>
                  <staffDef n="1" lines="5" meter.count="4" meter.unit="4">
                     <clef shape="G" line="2" />
                  </staffDef>
                  <staffDef n="2" lines="5" meter.count="4" meter.unit="4">
                     <clef shape="F" line="4" />
                  </staffDef>
               </staffGrp>
            </staffGrp>
         </staffGrp>
      </staffGrp>
   </staffGrp>
</scoreDef>

@ahankinson
Copy link
Member

The term score doesn’t really appear much in MEI. Could we modify @staff to accept these ID values, and include staff groups as a valid target? The older method would still be available on @staff

@pe-ro
Copy link
Contributor

pe-ro commented May 9, 2024

@staff expects one or more staff numbers; i.e., positive integers. I'm not sure of the side effects mixing datatypes within @staff might have on other elements that use @staff besides <dir>. It would be better to use a different attribute.

@staffGrp perhaps? Then @staffGrp could use xml:ids.

@craigsapp
Copy link
Member Author

craigsapp commented May 10, 2024

Yes @staffGrp would be useful to keeps backwards compatibility with attribute data types. Currently @staff is required for most elements such as <dir> and <tempo>. The new rule could be that @staffGrp can be used as a substitution or override for @staff.

It may also be useful to allow redundancy:

<dir staff="1 8" staffGrp="#nonstrings #strings">some text</dir>

Then some text will be displayed on staves 1 and 8. If either staff 1 or staff 8 is missing for some reason (such as a short score of only the strings so staves 1-7 are removed, then the @staffGrp would instead be used to determine a remapping of the staff number(s) to display the text on. For example in the case of a strings short score, @staff="1 8" would be missing staff 1, so a renderer would search for @staffGrp and if found, would calculate the staves that the text should be attached to (in this example only staff 8, and no reassignment of the staff 1 text. For condensing, if the flute staff is removed, then the algorithm would calculate that the adjusted staff assignment should change from @staff="1 8" to @staff="2 8"`.

This method would be computationally efficient: only if the renderer cannot find the staff numbers in @staff would it fall back to @staffGrp to lookup new staff assignments. So this is another reason why keeping @staff as integers and @staffGrp as IDREFs would be good.

When extracting an oboe part from the full score, the same processing would happen, where there is no @staff="2" but then the extracting software could notice a @staffGrp, and then calculate that the text should be extracted for @staff=2 (and probably the oboe part would then also be reassigning staff 2 to become staff 1 in another step).

@ahankinson
Copy link
Member

ahankinson commented May 10, 2024

The new rule could be that @staffGrp can be used as a substitution or override for @staff.

That’s actually why I suggested @staff — the two seem to be functionally the same, while being almost mutually exclusive. It’s also easy to differentiate: if it starts with # then it’s an IDREF. It seems like you would use them in almost the same way.

I'm not sure of the side effects mixing datatypes within @staff might have on other elements that use @staff besides <dir>.

Worth checking, but we provide mixed data types on other attributes don’t we? And as much as @lpugin dislikes them, we can define a local override on <dir> if we need to…

It may also be useful to allow redundancy… etc.

Clever as it is, I suspect clearly communicating this expected behaviour in a complete manner will be difficult at best.

@lpugin
Copy link
Member

lpugin commented May 10, 2024

Using @staffGrp makes perfect sense. Mixing data types in @staff would be very weird. However, using @n for staff and @xml:id for staffGrp is equally weird. Since staffGrp@n exist, why not use the same approach and use it for referencing from @staffgrp? So we could have:

<dir staff="1" staffgrp="1"/>

(Personally I still think that just:

<dir staff="1" staffgrp="true"/>

would be sufficient, but I am fine with references to @n)

@rettinghaus
Copy link
Member

I took @score.level because it represents a level within the scoreDef. But I think @staffgrp would also make sense because it fits into the current scheme with @staff and @layer.

@craigsapp
Copy link
Member Author

Is there any current use of staffGrp@n? And would nested <staffGrp> need to be numbered in a particular order?

Two basic possibilities:

<scoreDef>
   <staffGrp n="1" label="system" xml:id="system">
      <staffGrp n="2" xml:id="grp01">
         <staffDef n="1" xml:id="stf01" />
         <staffDef n="2" xml:id="stf02" />
      </staffGrp>
      <staffGrp n="3" xml:id="grp02">
         <staffDef n="3" xml:id="stf03" />
         <staffDef n="4" xml:id="stf04" />
         <staffDef n="5" xml:id="stf05" />
         <staffDef n="6" xml:id="stf06" />
      </staffGrp>
   </staffGrp>
   <staffGrp n="4">
         <staffDef n="7" xml:id="stf07" />
         <staffDef n="8" xml:id="stf08" />
   <staffGrp/>
</scoreDef>

Or:

<scoreDef>
   <staffGrp n="1" label="system" xml:id="system">
      <staffGrp n="3" xml:id="grp01">
         <staffDef n="1" xml:id="stf01" />
         <staffDef n="2" xml:id="stf02" />
      </staffGrp>
      <staffGrp n="4" xml:id="grp02">
         <staffDef n="3" xml:id="stf03" />
         <staffDef n="4" xml:id="stf04" />
         <staffDef n="5" xml:id="stf05" />
         <staffDef n="6" xml:id="stf06" />
      </staffGrp>
   </staffGrp>
   <staffGrp n="2">
         <staffDef n="7" xml:id="stf07" />
         <staffDef n="8" xml:id="stf08" />
   <staffGrp/>
</scoreDef>

I.e., does it matter of the staffGrp@n are numbered by sibling or descendent first? Or would either work? The second one would be more complicated since the numbering of the children would depend on the previous sibling's descendents.

In other words, the enumeration of staffGrp seems basically arbitrary (which would tend to indicate that xml:id references for dir@staffGrp seems better).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants