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
657 stars 181 forks source link

Automatic exotic circle-of-fifth key signatures #1230

Open craigsapp opened 4 years ago

craigsapp commented 4 years ago

For keySig@sig="8s" to keySig@sig"14s" and keySig@sig="8f" to keySig@sig"14f", it would be useful to automatically generate the correct exotic key signature. Currently verovio clips such key signatures to the non-exotic key signatures of up to 7s/7f, but this will be an incorrect key signature. This would allow the correct display of strange transpositions with the new --transpose option. Not overly useful for practical purposes, but will be nice to display correctly without having to manually set each pitch class accidental.

Here is example data in C major:

Screen Shot 2019-12-11 at 5 26 50 PM

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="2019-12-11T15:25:23" version="2.4.0-dev-84bfd07">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mdiv-0000001459122862">
    <score xml:id="score-0000001362176541">
     <scoreDef xml:id="scoredef-0000000922098002">
      <staffGrp xml:id="staffgrp-0000001911152024">
       <staffDef xml:id="staffdef-0000000566181926" n="1" lines="5">
        <clef xml:id="clef-0000001262121720" shape="G" line="2" />
        <keySig xml:id="keysig-L3F1" pname="c" mode="major" />
        <meterSig xml:id="metersig-L2F1" count="4" unit="4" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1" right="end" n="0">
       <staff xml:id="staff-0000001923574323" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <note xml:id="note-L6F1" dur="4" oct="4" pname="c" accid.ges="n" />
         <note xml:id="note-L7F1" dur="4" oct="4" pname="d" accid.ges="n" />
         <note xml:id="note-L8F1" dur="4" oct="4" pname="e" accid.ges="n" />
         <note xml:id="note-L9F1" dur="4" oct="4" pname="f" accid.ges="n" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

Transposing up an augmented fifth:

./verovio --transpose a5 test.mei -o test2
./verovio --transpose a5 test.mei -o test2 -atmei

The pitches will be correct, but the key signature needs an F-double-sharp, since 8s means that there are 7 sharps, but then go back to the first sharp and raise it again to a double sharp.

Screen Shot 2019-12-11 at 5 29 06 PM

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="2019-12-11T15:25:23" version="2.4.0-dev-84bfd07">
     <name>Verovio</name>
     <p>Transcoded from Humdrum</p>
    </application>
   </appInfo>
  </encodingDesc>
  <workList>
   <work>
    <title />
   </work>
  </workList>
 </meiHead>
 <music>
  <body>
   <mdiv xml:id="mdiv-0000001459122862">
    <score xml:id="score-0000001362176541">
     <scoreDef xml:id="scoredef-0000000922098002">
      <staffGrp xml:id="staffgrp-0000001911152024">
       <staffDef xml:id="staffdef-0000000566181926" n="1" lines="5">
        <clef xml:id="clef-0000001262121720" shape="G" line="2" />
        <keySig xml:id="keysig-L3F1" pname="g" accid="s" mode="major" sig="8s" />
        <meterSig xml:id="metersig-L2F1" count="4" unit="4" />
       </staffDef>
      </staffGrp>
     </scoreDef>
     <section xml:id="section-L1F1">
      <measure xml:id="measure-L1" right="end" n="0">
       <staff xml:id="staff-0000001923574323" n="1">
        <layer xml:id="layer-L1F1N1" n="1">
         <note xml:id="note-L6F1" dur="4" oct="4" pname="g" accid.ges="s" />
         <note xml:id="note-L7F1" dur="4" oct="4" pname="a" accid.ges="s" />
         <note xml:id="note-L8F1" dur="4" oct="4" pname="b" accid.ges="s" />
         <note xml:id="note-L9F1" dur="4" oct="5" pname="c" accid.ges="s" />
        </layer>
       </staff>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>

Triple sharps/flats could also be implemented at the same time (15s to 21s and 15f to 21f)...

Note that the use of triple sharps/flats will require setting Transposer::setBase600() after it is initialized and before the transposition interval is set.

lpugin commented 4 years ago

We can look at this but this would yield invalid MEI. It seems that the data type (currently erroneously name KEYFIFTHS would allow only values up to 12. https://music-encoding.org/guidelines/v4/data-types/data.keyfifths.html.

In terms of display: do you expect the double sharp (e.g., F) to be display in replacement of the first sharp, or additionally at the end of the key sig?

craigsapp commented 4 years ago

Not very important to implement, but since I saw "8s" as a key signature I was wanting the correct key signature in the music notation. The double sharps/flats would replace the sharps/flats as the circle-of-fifths number increases/decreases. In other words for keys of 7s and higher, there will always be seven accidentals, and the sharps will gradually be replaced by double sharps. For 8s the F-position will be double sharp and all of the others will be sharp. For 9s the F and C positions will be double sharp, for 10s the F, C and G positions will be double sharp, and so on.

This relates to what should happen when someone transposes up a perfect fifth from C-sharp major. The new key will be G-sharp major, which is only theoretical and never used in real music. Instead, G-sharp major would be converted into the enharmonic equivalent of A-flat major.

This enharmonic change could be added to the --transpose process; however, the transposition would then be a lossy process: transposing C-sharp major up a perfect fifth would produce A-flat major, but transposing A-flat major down a fifth would produce D-flat major and not C-sharp major. A complication is that only music in G-sharp major should be enharmonically changed, so the transposition interval would change dependent on the key, and iterating through the notes would have to be done in a time-sorted manner.

The other option is to not do the enharmonic transposition (which is easier to do for now). This would lead to the theoretical key signatures being displayed.

In any case the data remains correct at the moment, so transposing up and down a fifth from C-sharp major will return correctly to C-sharp major, because verovio is allowing an 8s key signature. I would advise allowing invalid MEI data like this in any case, since the other option would be to make the @accid/@accid.ges parameter incorrect by clipping the data to 7s. But since the key signature should not be clipped to 7s, then it would be nice for the notation to not show a clipped key signature (and hence the motivation for this request).

earboxer commented 4 years ago

I would advise allowing invalid MEI data like this in any case, since the other option would be to make the @accid/@accid.ges parameter incorrect by clipping the data to 7s. But since the key signature should not be clipped to 7s, then it would be nice for the notation to not show a clipped key signature (and hence the motivation for this request).

So we should go up to 12f/12s?

craigsapp commented 4 years ago

So we should go up to 12f/12s?

14f/14s would handle all cases of double sharps/flats in the key signature, so that would be a good target. Or if you want to be excessive, then 21f/21s would allow up to triple sharps/flats for each accidental in the key signature.