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

@n for <harm> #388

Closed craigsapp closed 6 years ago

craigsapp commented 7 years ago

Is there a way to have multiple harmony lines similar to mutiple verses?

Here is an example where I have two analyses being display via <harm>, but they overstrike each other:

screen shot 2016-12-18 at 20 39 55

In this case they cannot be displayed as <verse>s since the data is attached to timestamps rather than notes. (see for example above the whole-measure rests).

I have tried @y, @x, @n, and @vo, none of which are currently implemented. Perhaps the most convenient method would be @n, working in a similar manner to lyrics, with verovio deciding on the layout adjustments to alter vertical positioning of <harm> elements.

MEI test data:

!!!filter: recip -cxaemxhm|metlev -caxemxhm
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://music-encoding.org/schema/3.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="3.0.0">
    <meiHead>
        <fileDesc>
            <titleStmt>
                <title />
            </titleStmt>
            <pubStmt>
                <date>2016-12-18 20:53:57</date>
            </pubStmt>
        </fileDesc>
        <encodingDesc>
            <projectDesc>
                <p>Transcoded from Humdrum with Verovio version 0.9.13-dev-2a282ac-dirty</p>
            </projectDesc>
        </encodingDesc>
        <extMeta>
            <frames xmlns:humxml="http://www.humdrum.org/ns/humxml">
                <metaFrame n="0" token="!!!filter: recip -cxaemxhm|metlev -caxemxhm" xml:id="loc0">
                    <frameInfo>
                        <startTime float="0" />
                        <frameType>reference</frameType>
                        <referenceKey>filter</referenceKey>
                        <referenceValue>recip -cxaemxhm|metlev -caxemxhm</referenceValue>
                    </frameInfo>
                </metaFrame>
                <metaFrame n="1" token="!!!voices: 3" xml:id="loc1">
                    <frameInfo>
                        <startTime float="0" />
                        <frameType>reference</frameType>
                        <referenceKey>voices</referenceKey>
                        <referenceValue>3</referenceValue>
                    </frameInfo>
                </metaFrame>
            </frames>
        </extMeta>
    </meiHead>
    <music>
        <body>
            <mdiv>
                <score>
                    <scoreDef xml:id="scoredef-000000199460590">
                        <staffGrp xml:id="m-000000101126834" symbol="bracket">
                            <staffDef xml:id="staffdef-000000002182961" clef.shape="G" clef.line="2" key.sig="0" meter.count="2" meter.unit="1" meter.sym="cut" n="1" label="Superius" label.abbr="S" lines="5" />
                            <staffDef xml:id="staffdef-000000048101113" clef.shape="G" clef.line="2" clef.dis="8" clef.dis.place="below" key.sig="0" meter.count="2" meter.unit="1" meter.sym="cut" n="2" label="Tenor" label.abbr="T" lines="5" />
                            <staffDef xml:id="staffdef-000000091919075" clef.shape="G" clef.line="2" clef.dis="8" clef.dis.place="below" key.sig="0" meter.count="2" meter.unit="1" meter.sym="cut" n="3" label="Contra" label.abbr="C" lines="5" />
                        </staffGrp>
                    </scoreDef>
                    <section xml:id="section-000000093141442">
                        <measure xml:id="measure-L13" n="1">
                            <staff xml:id="staff-L13F3" n="1">
                                <layer xml:id="layer-L13F3" n="1">
                                    <mRest xml:id="mrest-000000088119035" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L13F2" n="2">
                                <layer xml:id="layer-L13F2" n="1">
                                    <mRest xml:id="mrest-000000044837993" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L13F1" n="3">
                                <layer xml:id="layer-L13F1" n="1">
                                    <note xml:id="note-L14F1" dur="4" oct="3" pname="c" accid.ges="n" />
                                    <note xml:id="note-L15F1" dur="4" oct="3" pname="d" accid.ges="n" />
                                    <note xml:id="note-L16F1" dur="4" oct="3" pname="e" accid.ges="n" />
                                    <note xml:id="note-L17F1" dur="4" oct="3" pname="f" accid.ges="n" />
                                    <note xml:id="note-L18F1" dur="2" oct="3" pname="g" accid.ges="n" />
                                    <note xml:id="note-L19F1" dur="2" oct="3" pname="a" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-L14F4" staff="1" tstamp="1.000000">4</harm>
                            <harm xml:id="harm-L14F5" staff="1" tstamp="1.000000">0</harm>
                            <harm xml:id="harm-L15F4" staff="1" tstamp="1.250000">4</harm>
                            <harm xml:id="harm-L15F5" staff="1" tstamp="1.250000">2</harm>
                            <harm xml:id="harm-L16F4" staff="1" tstamp="1.500000">4</harm>
                            <harm xml:id="harm-L16F5" staff="1" tstamp="1.500000">1</harm>
                            <harm xml:id="harm-L17F4" staff="1" tstamp="1.750000">4</harm>
                            <harm xml:id="harm-L17F5" staff="1" tstamp="1.750000">2</harm>
                            <harm xml:id="harm-L18F4" staff="1" tstamp="2.000000">2</harm>
                            <harm xml:id="harm-L18F5" staff="1" tstamp="2.000000">0</harm>
                            <harm xml:id="harm-L19F4" staff="1" tstamp="2.500000">2</harm>
                            <harm xml:id="harm-L19F5" staff="1" tstamp="2.500000">1</harm>
                            <tie xml:id="tie-000000097174124" startid="#note-L19F1" endid="#note-L21F1" />
                        </measure>
                        <measure xml:id="measure-L20" n="2">
                            <staff xml:id="staff-L20F3" n="1">
                                <layer xml:id="layer-L20F3" n="1">
                                    <mRest xml:id="mrest-000000100615103" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L20F2" n="2">
                                <layer xml:id="layer-L20F2" n="1">
                                    <mRest xml:id="mrest-000000189426791" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L20F1" n="3">
                                <layer xml:id="layer-L20F1" n="1">
                                    <note xml:id="note-L21F1" dur="4" oct="3" pname="a" accid.ges="n" />
                                    <note xml:id="note-L22F1" dur="4" oct="3" pname="g" accid.ges="n" />
                                    <note xml:id="note-L23F1" dur="1" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L24F1" dur="2" oct="3" pname="b" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-L21F4" staff="1" tstamp="1.000000">4</harm>
                            <harm xml:id="harm-L22F4" staff="1" tstamp="1.250000">4</harm>
                            <harm xml:id="harm-L22F5" staff="1" tstamp="1.250000">2</harm>
                            <harm xml:id="harm-L23F4" staff="1" tstamp="1.500000">1</harm>
                            <harm xml:id="harm-L23F5" staff="1" tstamp="1.500000">1</harm>
                            <harm xml:id="harm-L24F4" staff="1" tstamp="2.500000">2</harm>
                            <harm xml:id="harm-L24F5" staff="1" tstamp="2.500000">1</harm>
                        </measure>
                        <measure xml:id="measure-L25" n="3">
                            <staff xml:id="staff-L25F3" n="1">
                                <layer xml:id="layer-L25F3" n="1">
                                    <mRest xml:id="mrest-000000112486666" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L25F2" n="2">
                                <layer xml:id="layer-L25F2" n="1">
                                    <note xml:id="note-L26F2" dur="4" oct="3" pname="c" accid.ges="n" />
                                    <note xml:id="note-L27F2" dur="4" oct="3" pname="d" accid.ges="n" />
                                    <note xml:id="note-L28F2" dur="4" oct="3" pname="e" accid.ges="n" />
                                    <note xml:id="note-L29F2" dur="4" oct="3" pname="f" accid.ges="n" />
                                    <note xml:id="note-L30F2" dur="2" oct="3" pname="g" accid.ges="n" />
                                    <note xml:id="note-L31F2" dur="2" oct="3" pname="a" accid.ges="n" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L25F1" n="3">
                                <layer xml:id="layer-L25F1" n="1">
                                    <note xml:id="note-L26F1" dur="1" oct="4" pname="c" accid.ges="n" />
                                    <rest xml:id="rest-L30F1" dur="2" />
                                    <note xml:id="note-L31F1" dur="2" oct="3" pname="f" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-L26F4" staff="1" tstamp="1.000000">4</harm>
                            <harm xml:id="harm-L26F5" staff="1" tstamp="1.000000">0</harm>
                            <harm xml:id="harm-L27F4" staff="1" tstamp="1.250000">4</harm>
                            <harm xml:id="harm-L27F5" staff="1" tstamp="1.250000">2</harm>
                            <harm xml:id="harm-L28F4" staff="1" tstamp="1.500000">4</harm>
                            <harm xml:id="harm-L28F5" staff="1" tstamp="1.500000">1</harm>
                            <harm xml:id="harm-L29F4" staff="1" tstamp="1.750000">4</harm>
                            <harm xml:id="harm-L29F5" staff="1" tstamp="1.750000">2</harm>
                            <harm xml:id="harm-L30F4" staff="1" tstamp="2.000000">2</harm>
                            <harm xml:id="harm-L30F5" staff="1" tstamp="2.000000">0</harm>
                            <harm xml:id="harm-L31F4" staff="1" tstamp="2.500000">2</harm>
                            <harm xml:id="harm-L31F5" staff="1" tstamp="2.500000">1</harm>
                            <tie xml:id="tie-000000042866793" startid="#note-L31F2" endid="#note-L33F2" />
                            <tie xml:id="tie-000000082856367" startid="#note-L31F1" endid="#note-L33F1" />
                        </measure>
                        <measure xml:id="measure-L32" n="4">
                            <staff xml:id="staff-L32F3" n="1">
                                <layer xml:id="layer-L32F3" n="1">
                                    <mRest xml:id="mrest-000000126322598" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L32F2" n="2">
                                <layer xml:id="layer-L32F2" n="1">
                                    <note xml:id="note-L33F2" dur="4" oct="3" pname="a" accid.ges="n" />
                                    <note xml:id="note-L34F2" dur="4" oct="3" pname="g" accid.ges="n" />
                                    <note xml:id="note-L35F2" dur="1" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L37F2" dur="2" oct="3" pname="b" accid.ges="n" />
                                </layer>
                            </staff>
                            <staff xml:id="staff-L32F1" n="3">
                                <layer xml:id="layer-L32F1" n="1">
                                    <note xml:id="note-L33F1" dur="2" oct="3" pname="f" accid.ges="n" />
                                    <note xml:id="note-L35F1" dur="2" oct="3" pname="e" accid.ges="n" />
                                    <note xml:id="note-L36F1" dur="1" oct="3" pname="d" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-L33F4" staff="1" tstamp="1.000000">4</harm>
                            <harm xml:id="harm-L34F4" staff="1" tstamp="1.250000">4</harm>
                            <harm xml:id="harm-L34F5" staff="1" tstamp="1.250000">2</harm>
                            <harm xml:id="harm-L35F4" staff="1" tstamp="1.500000">2</harm>
                            <harm xml:id="harm-L35F5" staff="1" tstamp="1.500000">1</harm>
                            <harm xml:id="harm-L36F4" staff="1" tstamp="2.000000">2</harm>
                            <harm xml:id="harm-L36F5" staff="1" tstamp="2.000000">0</harm>
                            <harm xml:id="harm-L37F4" staff="1" tstamp="2.500000">2</harm>
                            <harm xml:id="harm-L37F5" staff="1" tstamp="2.500000">1</harm>
                        </measure>
                    </section>
                </score>
            </mdiv>
        </body>
    </music>
</mei>
lpugin commented 7 years ago

Maybe you can use <choice> and display only one at the time?

pe-ro commented 7 years ago

Using <choice> is an expedient, but not long-term solution. That being said, putting anything other than harmonic labels inside <harm> just to get a desired behavior is abuse. @n is allowed on <harm> and Verovio could use it to determine vertical placement/order. Another approach is to add <harm> to the list of items that can carry @valign described at https://github.com/music-encoding/music-encoding/issues/332.

craigsapp commented 7 years ago

In the general case <choice> is not great since the analyses could be for independent features, and I would want to see both at the same time.

That being said, putting anything other than harmonic labels inside just to get a desired behavior is abuse.

The ends justify the means :-)

The problem is that to get the analytic data to display properly the way I want, I cannot use <harm> or <verse>. There can be only one <harm> (otherwise overstriking occurs), and <verse> cannot be attached to rests or given floating @tstamps.

Semantically the analysis data would not typically be a property of the musical content, so it could be moved to a separate location in the MEI hierarchy, similar to a performance time mapping using <when> or @tstamp or an @xml:id to indicate how it links to the score. Then this data could be rendered in the score with the similar behavior to the current treatment of <harm>, but allow for multiple streams of analytic text.

At least initially, I would like to see the analysis data as text. In the future I might want to display the analysis data graphically, such as in a bar chart or function line (which we can later think about if it should be rendered by via verovio or by external post-processing). The graphical display I am thinking of is similar to how analysis data for audio data is shown in Sonic Visualiser (http://www.sonic-visualiser.org). Here is an example:

screen shot 2016-12-19 at 11 31 34

In this example, the waveform is shown in orange (this is analogous to the graphical score in music notation). The red line underneath it is an analysis of the waveform that shows the likelhood of a note attack in the audio at that point in time (you can mouse over the red line to read the numeric value, or read the numeric value from the horizontal tick lines).

This is also along the lines of analytic markup which can be done in PWGL with the ENP notation front-end: http://www2.siba.fi/PWGL/enp.html ENP can draw boxes around notes and connect notes with lines, etc. (I don't see an example online). This would be another way of visualizing the analytic data that would be good to think about at some time in the future.

Lilypond (http://www.lilypond.org) also has some capability for analytic markup: http://lsr.di.unimi.it/LSR/Item?id=1000 How to represent this sort of functionality in MEI would be good; otherwise music theorists are stuck with their standard method of doing the markup by hand in photoshop or acrobat after rendering the music notation with a notation editor.

And this also relates to displaying search results as I do on the JRP webste (http://josquin.stanford.edu). Here is an example of searching for the melodic sequence "C E G F E":

screen shot 2016-12-19 at 12 20 32

With the search-results highlighted in orange in the music notation:

screen shot 2016-12-19 at 12 23 25

How should this be represented (if at all) in MEI? This is also analytic information which is not a property of the score, so placing the list of matches in another section of the MEI structure other than the area representing the graphic music might be good. (I would want that data in this case mapped to @class in the SVG so that I can use CSS to choose a color to highlight the notes).

pe-ro commented 7 years ago

First, the ends never just the means. That just leads to chaos.

Second, Verovio doesn't implement it yet, but I think what you're looking for is <annot>. It can live in lots of places in the document, can be associated with another element (via @plist) or a time point (via @tstamp), allows textual and/or graphical content, etc.

The problem with <annot> right now is that it's a bin into which lots of trash (uh, I mean stuff) can be placed. In other words, it doesn't support any particular structure, making it somewhat difficult to implement. I've always hoped to return to it and tighten it up, either by revising its content model or splitting it into multiple, more-specialized elements.

craigsapp commented 7 years ago

Second, Verovio doesn't implement it yet, but I think what you're looking for is <annot>.

That should be good.

First, the ends never just the means. That just leads to chaos

For my case it would be controlled chaos, since I am converting from Humdrum to MEI (with a desire to see it rendered in verovio). Humdrum is primarily about adding automatic or manual annotations to the score, so having a formalized system to translate into MEI would be good. I'll use the hacky system until a formalized system is working within verovio. Then I can adjust the translation program to map annotations into the more proper method.

Here is an example Humdrum score:

**kern      **kern      **kern
*clefGv2    *clefGv2    *clefG2
*k[]        *k[]        *k[]
*C:         *C:         *C:
*M2/1       *M2/1       *M2/1
*met(C|)    *met(C|)    *met(C|)
=1-         =1-         =1-
4C          0r          0r
4D          .           .
4E          .           .
4F          .           .
2G          .           .
[2A         .           .
=2          =2          =2
4A]         0r          0r
4G          .           .
1c          .           .
2B          .           .
=3          =3          =3
1c          4C          0r
.           4D          .
.           4E          .
.           4F          .
2r          2G          .
[2F         [2A         .
=4          =4          =4
2F]         4A]         0r
.           4G          .
2E          1c          .
1D          .           .
.           2B          .
=5          =5          =5
2.C         [0c         4c
.           .           4d
.           .           4e
4D          .           4f
2E          .           2g
[2F         .           [2a
=6          =6          =6
4F]         1c]         4a]
4E          .           4g
2A          .           1cc
1G          1d          .
.           .           2b
=7          =7          =7
1.C         1.e         1.cc
==          ==          ==
*-          *-          *-

I can then add annotations to the score, in this case integer beat levels (0=beat, 1=halfbeat offbeats, 2=quarterbeat offbeats).

      metlev jrp://Jos2721 | metlev -cp

(the first case analyzes the beat levels of each part individually, and the second case analyzes the composite rhythm of all parts).

Here is the resulting annotated score, where **blev spines are added for the analytic content. The first spine is the analysis for the entire system of music, and the individual analyses are found to the right of each **kern spine.

**blev      **kern      **blev      **kern      **blev      **kern      **blev
*           *clefGv2    *           *clefGv2    *           *clefG2     *
*           *k[]        *           *k[]        *           *k[]        *
*           *C:         *           *C:         *           *C:         *
*           *M2/1       *           *M2/1       *           *M2/1       *
*           *met(C|)    *           *met(C|)    *           *met(C|)    *
=1-         =1-         =1-         =1-         =1-         =1-         =1-
0           4C          0           0r          0           0r          0
2           4D          2           .           .           .           .
1           4E          1           .           .           .           .
2           4F          2           .           .           .           .
0           2G          0           .           .           .           .
1           [2A         1           .           .           .           .
=2          =2          =2          =2          =2          =2          =2
0           4A]         0           0r          0           0r          0
2           4G          2           .           .           .           .
1           1c          1           .           .           .           .
1           2B          1           .           .           .           .
=3          =3          =3          =3          =3          =3          =3
0           1c          0           4C          0           0r          0
2           .           .           4D          2           .           .
1           .           .           4E          1           .           .
2           .           .           4F          2           .           .
0           2r          0           2G          0           .           .
1           [2F         1           [2A         1           .           .
=4          =4          =4          =4          =4          =4          =4
0           2F]         0           4A]         0           0r          0
2           .           .           4G          2           .           .
1           2E          1           1c          1           .           .
0           1D          0           .           .           .           .
1           .           .           2B          1           .           .
=5          =5          =5          =5          =5          =5          =5
0           2.C         0           [0c         0           4c          0
2           .           .           .           .           4d          2
1           .           .           .           .           4e          1
2           4D          2           .           .           4f          2
0           2E          0           .           .           2g          0
1           [2F         1           .           .           [2a         1
=6          =6          =6          =6          =6          =6          =6
0           4F]         0           1c]         0           4a]         0
2           4E          2           .           .           4g          2
1           2A          1           .           .           1cc         1
0           1G          0           1d          0           .           .
1           .           .           .           .           2b          1
=7          =7          =7          =7          =7          =7          =7
0           1.C         0           1.e         0           1.cc        0
==          ==          ==          ==          ==          ==          ==
*-          *-          *-          *-          *-          *-          *-

To display this data in verovio, I map **blev to either **text to convert to <verse> or to **mxhm to convert to <harm> (**mxhm being a currently informal conversion of MusicXML <harmony> into Humdrum and for conversion to MEI <harm>).

So to display this score in verovio, I have options to rename the data type to one of the categories of text that I convert into MEI to display in verovio:

     metlev -etext jrp://Jos2721 | metlev -caemxhm

which results in the Humdrum score which is semantically incorrect, but only because I want to see the **blev data shown in the score via <verse> and <harm>:

**kern      **text      **kern      **text      **kern      **text      **mxhm
*clefGv2    *           *clefGv2    *           *clefG2     *           *
*k[]        *           *k[]        *           *k[]        *           *
*C:         *           *C:         *           *C:         *           *
*M2/1       *           *M2/1       *           *M2/1       *           *
*met(C|)    *           *met(C|)    *           *met(C|)    *           *
=1-         =1-         =1-         =1-         =1-         =1-         =1-
4C          0           0r          0           0r          0           0
4D          2           .           .           .           .           2
4E          1           .           .           .           .           1
4F          2           .           .           .           .           2
2G          0           .           .           .           .           0
[2A         1           .           .           .           .           1
=2          =2          =2          =2          =2          =2          =2
4A]         0           0r          0           0r          0           0
4G          2           .           .           .           .           2
1c          1           .           .           .           .           1
2B          1           .           .           .           .           1
=3          =3          =3          =3          =3          =3          =3
1c          0           4C          0           0r          0           0
.           .           4D          2           .           .           2
.           .           4E          1           .           .           1
.           .           4F          2           .           .           2
2r          0           2G          0           .           .           0
[2F         1           [2A         1           .           .           1
=4          =4          =4          =4          =4          =4          =4
2F]         0           4A]         0           0r          0           0
.           .           4G          2           .           .           2
2E          1           1c          1           .           .           1
1D          0           .           .           .           .           0
.           .           2B          1           .           .           1
=5          =5          =5          =5          =5          =5          =5
2.C         0           [0c         0           4c          0           0
.           .           .           .           4d          2           2
.           .           .           .           4e          1           1
4D          2           .           .           4f          2           2
2E          0           .           .           2g          0           0
[2F         1           .           .           [2a         1           1
=6          =6          =6          =6          =6          =6          =6
4F]         0           1c]         0           4a]         0           0
4E          2           .           .           4g          2           2
2A          1           .           .           1cc         1           1
1G          0           1d          0           .           .           0
.           .           .           .           2b          1           1
=7          =7          =7          =7          =7          =7          =7
1.C         0           1.e         0           1.cc        0           0
==          ==          ==          ==          ==          ==          ==
*-          *-          *-          *-          *-          *-          *-

and which is then converted to MEI and rendered in verovio:

screen shot 2016-12-19 at 14 01 36

I am now generating such annotations inside the verovio toolkit (Humdrum develop branch), but I do not have a good placed to store them in MEI yet. Here is the above analysis done via a filter given in the url:

http://verovio.humdrum.org/?file=jrp:Jos2721&filter=metlev%20-etext|metlev%20-caemxhm

%20 is a URL escape sequence for a space character %7c is a URL escape sequence for a pipe character

The analysis is done dynamically, and shown in notation along with the input data before the annotations are inserted:

screen shot 2016-12-19 at 14 14 53

The "filter" that does the analysis is persistent, so for example here are a set of Bach chorales which all display the same annotations which are generated at the last moment before converting the data into MEI to display with verovio:

http://verovio.humdrum.org/?file=chorales&filter=metlev%20-etext%7cmetlev%20-caemxhm

Clicking on any titles of the works in that list will display the music with the metlev "annotations" generated by the Humdrum filter directive in the URL:

screen shot 2016-12-19 at 14 18 17

If I wanted to display the metric analysis for the chorales in grand-staff layout:

http://verovio.humdrum.org/?file=chorales&filter=satb2gs%7cmetlev%20-caemxhm

(but I cannot show the individual voice metric analysis, only the composite analysis due to the mentioned limitations of <verse> and <harm> rendering in verovio).

Example score with that filter applied:

screen shot 2016-12-19 at 14 30 09
pe-ro commented 7 years ago

Your **blev** tokens are a good fit for <annot>:

<annot label="beat level analysis" tstamp="1">0</annot>
<annot label="beat level analysis" tstamp="2">2</annot>
<annot label="beat level analysis" tstamp="3">1</annot>
<annot label="beat level analysis" tstamp="4">2</annot>
<annot label="beat level analysis" tstamp="5">0</annot>
<annot label="beat level analysis" tstamp="7">1</annot>

if the annotations are in the same measure as the beats to which they're attached.

When the annotations are located elsewhere, then @startid can be used to attach them to a features to which they apply (in this case, to the notes), for example --

<annot label="beat level analysis" startid="#note1">0</annot>

The best approach, however, may be to use <recording> to create a time line, then attach the annotations to time points, for example --

<performance label="Sounds Good!" xmlns="http://www.music-encoding.org/ns/mei"
  xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <recording begin="0" end="500" betype="time">
    <when xml:id="when1" absolute="100"/>
    <when xml:id="when2" absolute="200"/>
    <when xml:id="when4" interval="6" since="#when2"/>
  </recording>
</performance>
...
<annot when="#when1">0</annot>
<annot when="#when2">2</annot>

The fly in this ointment, however, is that @betype currently allows values that are attuned to timed media. It doesn't permit values of a more musical nature, like "beats" or "quarter notes" or any of your other favorite methods of measuring time. :-) Of course, that can be fixed.

craigsapp commented 7 years ago
<performance label="Sounds Good!" xmlns="http://www.music-encoding.org/ns/mei"
  xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <recording begin="0" end="500" betype="time">
    <when xml:id="when1" absolute="100"/>
    <when xml:id="when2" absolute="200"/>
    <when xml:id="when4" interval="6" since="#when2"/>
  </recording>
</performance>
...
<annot when="#when1">0</annot>
<annot when="#when2">2</annot>

How does this link to the score? You are not going to make me label each note with a <when> reference, are you?

I can imagine three categories of recording alignment data:

(1) give an independent real-timestamp to every note (onset). This would involve giving a when reference to each note. This might be necessary when aligning to arpeggiated notes. In general it is difficult to extract individual timings for notes in a chord, so I don't do this often.

(2) give a real-timestamp to every "event" in the score, where an "event" is a set of notes. This would ideally involve a directive, such as annot with a specific @tstamp. since the when would apply to any notes at the given timestamp.

(3) give a real-timestamp to an occasional "even", such as once per beat, once per measure, etc. In this case the intervening @tstamps would be linearly interpolated between two real-timestamps present in the timeline (i.e., assuming a constant tempo between the two explicit time alignment points).

It would be useful for the when data to differentiate between these three cases, depending on where actual alignment points are measured. For example, here is a Humdrum score related to case number 3, where the alignment points are once each beat:

http://www.mazurka.org.uk/info/revcond/pid9060b-10/pid9060b-10.btime

**time        **kern        **kern
*             *staff2       *staff1
*             *clefF4       *clefG2
*             *k[f#c#g#d#]  *k[f#c#g#d#]
*             *c#:          *c#:
*             *M3/4         *M3/4
*             *MM108.8      *MM108.8
498           4r            (8e/L
.             .             8a/J
=1           =1            =1
868           4C#/          4g#/)
1578          4G#\ 4c#\ 4e\ (4.cc#\
2318          4G#\ 4c#\ 4e\ .
.             .             8dd#\
=             =             =

The first spine is the time in milliseconds from the start of the recording where the notes on the same line start in the recording. Notice that there are "." entries in the column where the time alignment was not measures. Ideally the MEI content would not contain estimated data which would be mixed in with the actual measured alignment points, and that would be the responsibility of the alignment-rendering software.

Here is the simulated version of case number 2 for the same score as a demonstration of case 3:

http://www.mazurka.org.uk/info/revcond/pid9060b-10/pid9060b-10.time

**time  **kern  **kern  **dynam
*   *staff2 *staff1 *staff1/2
*   *clefF4 *clefG2 *clefG2
*   *k[f#c#g#d#]    *k[f#c#g#d#]    *k[f#c#g#d#]
*   *c#:    *c#:    *c#:
*   *M3/4   *M3/4   *M3/4
*   *MM108.8    *MM108.8    *MM108.8
498 4r  (8e/L   p
683 .   8a/J    .
=1  =1  =1  =1
868 4C#/    4g#/)   .
1578    4G#\ 4c#\ 4e\   (4.cc#\ .
2318    4G#\ 4c#\ 4e\   .   .
2513    .   8dd#\   .
=2  =2  =2  =2

This case adds "683" and "2513" timestamps by assuming that the tempo during the beat is constant.

I have a tool which extracts "qstamps" from the score:

beat -cp file.krn
!!!performance-id:      pid9060b-10
!!!title:               Mazurka in C-sharp minor, Op. 63, No. 3
!!!trials:               1
!!!date:                2007/03/30/
!!!reverse-conductor:   Craig Stuart Sapp
!!!performer:           Alexander Brailowsky
!!!performance-date:    1960
!!!label:               Sony SB2K 63237
!!!label-title:         Chopin Mazurkas (Complete) & Polonaises: Alexander Brailowsky
!!!offset:      0
!!!COM: Chopin, Frederic
!!!CDT: 1810///-1849///
!!!OTL: Mazurka in C-sharp Minor, Op. 63, No. 3
!!!OPS: Op. 63
!!!ONM: No. 3
!!!ODT: 1846///
!!!PDT: 1847///-1848///
!!!PPP: Leipzig and London (1847); Paris (1848) and London
!!!ODE: Countess Laura Czosnowska
!!!AIN: piano
**absq  **time  **kern  **kern  **dynam
*   *   *staff2 *staff1 *staff1/2
*   *   *clefF4 *clefG2 *clefG2
*   *   *k[f#c#g#d#]    *k[f#c#g#d#]    *k[f#c#g#d#]
*   *   *c#:    *c#:    *c#:
*   *   *M3/4   *M3/4   *M3/4
*   *   *MM108.8    *MM108.8    *MM108.8
0   498 4r  (8e/L   p
0.5 683 .   8a/J    .
=2  =2  =1  =1  =1
1   868 4C#/    4g#/)   .
2   1578    4G#\ 4c#\ 4e\   (4.cc#\ .
3   2318    4G#\ 4c#\ 4e\   .   .
3.5 2513    .   8dd#\   .
=3  =3  =2  =2  =2
4   2708    4D#\    8cc#\L  .
4.5 2893    .   8b#\J   .
5   3078    4G#\ 4B#\ 4f#\  4dd#\)  .
6   3678    4G#\ 4B#\ 4f#\  4r  .
=4  =4  =3  =3  =3
7   4058    4BB#/   4r  .
8   4508    4G#\ 4d#\ 4f#\  (4.dd#\ .
9   5098    4G#\ 4d#\ 4f#\  .   .
9.5 5298    .   8ee\    .
=5  =5  =4  =4  =4
10  5498    4C#/    8dd#\L  .
10.5    5678    .   8cc#\J  .
11  5858    4G#\ 4c#\ 4e\   4ee\)   .
12  6368    4G#\ 4c#\ 4e\   4r  .
=6  =6  =5  =5  =5
13  6688    4E\ 4r  .
14  7138    4G#\ 4c#\ 4g#\  (4.gg#\ .
15  7708    4G#\ 4c#\ 4g#\  .   .
15.5    7938    .   8aa\    .
=7  =7  =6  =6  =6
16  8168    4D#\    8gg#\L  .
16.5    8363    .   8ff##\J .
17  8558    4A#\ 4c#\ 4f##\ 4.dd#\  .
18  9158    4A#\ 4c#\ 4f##\ .   .
18.5    9363    .   8ee\    .
=8  =8  =7  =7  =7
19  9568    4GG#/   4ff#\   .
20  10008   4G#\ 4B#\ 4f#\  4.gg#\  .
21  10558   4G#\ 4B#\ 4f#\  .   .
21.5    10753   .   8ff#\   .
=9  =9  =8  =8  =8
22  10948   4C#/    8ee\L   .
22.5    11118   .   8dd#\J  .
23  11288   4G#\ 4c#\ 4e\   4cc#\   .
24  11718   4F##\ 4c#\ 4e\  8b/L    .
24.5    11898   .   8a/J    .
=10 =10 =9  =9  =9
25  12078   4C#/    4g#/)   .
26  12698   4G#\ 4c#\ 4e\   (4.cc#\ .
27  13258   4G#\ 4c#\ 4e\   .   .
27.5    13468   .   8dd#\   .
=11 =11 =10 =10 =10
28  13678   4D#\    8cc#\L  .
28.5    13868   .   8b#\J   .
29  14058   4G#\ 4B#\ 4f#\  4dd#\)  .
30  14648   4G#\ 4B#\ 4f#\  4r  .
=12 =12 =11 =11 =11
31  15018   4BB#/   4r  .
32  15458   4G#\ 4d#\ 4f#\  (4.dd#\ .
33  15978   4G#\ 4d#\ 4f#\  .   .
33.5    16193   .   8ee\    .
=13 =13 =12 =12 =12
34  16408   4C#/    8dd#\L  .
34.5    16583   .   8cc#\J  .
35  16758   4G#\ 4e\    2ee\    .
36  17298   4F#\ 4A#\ 4e\   .   .
=14 =14 =13 =13 =13
37  17678   4BB/    4b'\)   .
38  18416   4G#\ 4B\ 4e\    (4.bb\  .
39  18968   4G#\ 4B\ 4e\    .   .
39.5    19193   .   8ccc#\  .
=15 =15 =14 =14 =14
40  19418   4BB/    8bb\L   .
40.5    19603   .   8aa#\J  .
41  19788   4F#\ 4c#\ 4e\   4.ff#\  .
42  20248   4F#\ 4c#\ 4e\   .   .
42.5    20433   .   8gg#\   .
=16 =16 =15 =15 =15
43  20618   4BBB/   4aan\   .
44  21148   4F#\ 4B\ 4d#\   4.bb\   .
45  21668   4F#\ 4B\ 4d#\   .   .
45.5    21883   .   8aa\    .
=17 =17 =16 =16 =16
46  22098   4EE/    8gg#\L  >
46.5    22353   .   8dd#\   .
47  22608   4G#\ 4B\ 4e\    8ee\    .
47.5    22818   .   8dd#\   .
48  23028   4r  8ee\    .
48.5    23308   .   8ff#\J  .
=18 =18 =17 =17 =17
49  23588   4BB#/   [4gg#\) >
50  24268   4G#\ 4d#\ 4f#\  8gg#\L] .
50.5    24543   .   8dd#\   .
51  24818   4r  8gg#\   .
51.5    24998   .   8ff#\J  .
=19 =19 =18 =18 =18
52  25178   4C#/    4ee'\   .
53  25694   4G#\ 4c#\ 4e\   (8b#\L  .
53.5    25876   .   8dd#\   .
54  26058   4r  8cc#\   .
54.5    26218   .   8bn\J   .
=20 =20 =19 =19 =19
55  26378   4CC#/   8a'/L)  .
55.5    26603   .   16r .
55.75   26716   .   16a/Jk  .
56  26828   4F##\ 4c#\ 4e\  4a'/    .
57  27488   4F##^\ 4c#^\ 4e^\   4a^/    .
=21 =21 =20 =20 =20
58  27958   4C#/    (8g#\L  .
58.5    28148   .   8cc#\   <
59  28338   4G#\ 4c#\ 4e\   8dd#\   .
59.5    28518   .   8ee\    .
60  28698   4r  8gg#\   .
60.5    28878   .   8ccc#\J)    .
=22 =22 =21 =21 =21
61  29058   4BB#/   [4gg#\  .
62  29490   4G#\ 4d#\   (8gg#\L]    .
62.5    29670   .   8dd#\   .
63  29849   4r  8gg#\   .
63.5    30019   .   8ff#\J  .
=23 =23 =22 =22 =22
64  30188   4CC#/   (4ee'\) .
65  30638   4G#\ 4e\    8b#\L   .
65.5    30852   .   8dd#\   .
66  31065   4G#\ 4A#\ 4e\   8cc#\   .
66.5    31316   .   8a#\J)  .
=24 =24 =23 =23 =23
67  31567   4DD#/   (8d#/L  f
67.5    31951   .   8e/ .
68  32335   4D#\ 4B\    8d#/    .
68.5    32587   .   8c##/   .
69  32838   4D#\ 4F##\ 4c#\ 8d#/    .
69.5    33018   .   8b/J    .
=25 =25 =24 =24 =24
*   *   *^  *   *
70  33198   4r  (4GG#\  8g#/L   .
70.5    33463   .   .   8G#/J   .
71  33728   4B/ 8C##\L  2g#^/)  .
71.5    33958   .   8E\ .   .
72  34188   4r  8D#\    .   .
72.5    34488   .   8BB\J   .   .
*   *   *v  *v  *   *
=26 =26 =25 =25 =25
73  34788   4GG#'/) [4gg#\  >
74  35558   4D#\ 4B#\ 4f#\  8gg#\L] .
74.5    35838   .   8dd#\   .
75  36118   4r  8gg#\   .
75.5    36313   .   8ff#\J  .
=27 =27 =26 =26 =26
76  36508   4C#/    &(4ee\&)    .
77  37098   4G#\ 4c#\ 4e\   (8b#\L  .
77.5    37313   .   8dd#\   .
78  37528   4r  8cc#\   .
78.5    37703   .   8bn\J   .
=28 =28 =27 =27 =27
79  37878   4CC#/   8a/L)   .
79.5    38088   .   16r .
79.75   38193   .   16a'/Jk .
80  38298   4F##\ 4e\   4a'/    .
81  38908   4F##\ 4e\   4a^/    .
=29 =29 =28 =28 =28
82  39368   4C#/    (8g#\L  <
82.5    39563   .   8cc#\   .
83  39758   4G#\ 4e\    8dd#\   .
83.5    39938   .   8ee\    .
84  40118   4C#/    8gg#\   .
84.5    40308   .   8ccc#\J)    .
=30 =30 =29 =29 =29
85  40498   4BB#/   [4gg#\  .
86  41028   4D#\ 4G#\ 4d#\  8gg#\L] .
86.5    41303   .   8dd#\   .
87  41578   4BBn/   8gg#\   .
87.5    41803   .   8ggn\J  .
=31 =31 =30 =30 =30
88  42028   4AA#/   8ff#\L  .
88.5    42228   .   8ee\    .
89  42428   4E\ 4c#\    8b#\    .
89.5    42633   .   8dd#\   .
90  42838   4AAn/   8cc#\   .
90.5    43129   .   8f##\J  .
=32 =32 =31 =31 =31
91  43420   4GG#/   8g#\L   .
91.5    43841   .   8a\ .
92  44261   4G#\ 4e\    8g#\    .
92.5    44610   .   8f##\   .
93  44958   4G#\ 4B#\ 4f#\  8g#\    .
93.5    45178   .   8ee\J   .
=33 =33 =32 =32 =32
*   *   *   *^  *
94  45398   4C#/    8cc#/L  8r  .
94.5    45598   .   8c#/J   [8c#\   .
95  45798   (4G#\ 4e\   2cc#/   2c#\]   .
96  46448   8B\L    .   .   .
96.5    46738   8A\J    .   .   .
*   *   *   *v  *v  *
=34 =34 =33 =33 =33
*   *   *k[b-e-a-d-g-]  *k[b-e-a-d-g-]  *k[b-e-a-d-g-]
*   *   *^  *^  *
97  47028   4r  8A-\L   8.e-/L  4r  .
97.5    47396   .   8Gn\J   .   .   .
97.75   47579   .   .   16e-/Jk .   .
98  47763   4r  4G-\    4e-/    4c\ .
99  48428   4A-/)   4F\ 4f/ 4d-\    .
=35 =35 =34 =34 =34 =34 =34
100 48918   2E-/ 2A-/   4r  8c/L    2c\ .
100.5   49098   .   .   8a-/J   .   .
101 49278   .   4AA-\   4g-/    .   .
102 49878   4r  4D-\ [4A-\  4f/ 4d-\    .
=36 =36 =35 =35 =35 =35 =35
103 50358   4A-/]   2GG-\   8.e-/L  2B-\    .
103.75  50726   .   .   16e-/Jk .   .
104 50848   2G-/    .   4e-/    .   .
105 51418   .   4AA-\   4c/ 4f/ 4r  .
*   *   *   *   *v  *v  *
=37 =37 =36 =36 =36 =36
106 51828   4G-/    4BB-\   8.e-/L  .
106.75  52166   .   .   16dn/Jk .
107 52278   4A-/    4C\ 4e-/    .
108 52858   4F/ 4D-\    [4d-/   .
=38 =38 =37 =37 =37 =37
*   *   *   *   *^  *
109 53278   4E-'\ 4A-'\ 4AAA-/ 4AA-/    8.e-/L  4d-\]   .
109.75  53616   .   .   16e-/Jk .   .
110 53728   4G-\ 4A-\   4r  4e-/    4c\ .
111 54288   4F\ 4A-\    4r  4f/ 4d-\    .
=39 =39 =38 =38 =38 =38 =38
112 54778   2A-/    4E-\    8a-/L   2c\ .
112.5   54973   .   .   8b-/J   .   .
113 55168   .   4AA-\   4g-/    .   .
114 55718   ([4A-/  4D-\    4f/ 4d-\    .
=40 =40 =39 =39 =39 =39 =39
115 56108   4A-/]   2GG-\   8.e-/L  2B-\    .
115.75  56513   .   .   16dd-/Jk    .   .
116 56648   4G-/    .   4e-/    .   .
117 57218   4r  4AA-\ 4F\)  4c/ 4f/ 4r  .
*   *   *   *   *v  *v  *
=41 =41 =40 =40 =40 =40
118 57648   4G-/    4BB-\   8.G-/ 8.d-/L    .
118.75  57978   .   .   16dn/Jk .
119 58088   4A-/    4C\ 4A-/ 4e-/   .
120 58678   4F/ 4D-\    4F/ 4d-/    .
*   *   *v  *v  *   *
=42 =42 =41 =41 =41
121 59088   4DD-/   &(8a-/L&)   .
121.5   59313   .   16r .
121.75  59426   .   16a-/Jk .
122 59538   4c-\ 4e-\   4f/ (4a-/   .
123 60098   4B-\ 4d-\   4g-/ 4b-/   .
=43 =43 =42 =42 =42
*   *   *   *^  *
124 60538   2.D-\   8.dd-/L 4r  .
124.75  60838   .   16cc-/Jk    .   .
125 60938   .   4f/ 4cc-/   4A-\ 4e-\   .
126 61528   .   4g-/ 4b-/   4B-\ 4d-\   .
=44 =44 =43 =43 =43 =43
127 61938   [2.D-\  8.a-/L  4g-\)   .
127.75  62253   .   16ee-/Jk    .   .
128 62358   .   4f/ 4a-/    4c-\ 4e-\   .
129 62888   .   4g-/ 4b-/   4B-\ 4d-\   .
*   *   *   *v  *v  *
=45 =45 =44 =44 =44
130 63288   4D-\] 4G-\ 4c-\ 4e-\    .
131 63828   4D-\ 4F\    8.a-/L  .
131.75  64278   .   16gn/Jk .
132 64428   4GG-/ 4G-/  4c-/ 4d-/ 4a-/  .
=46 =46 =45 =45 =45
133 64838   4DD-/   8r  .
133.5   65088   .   16r .
133.75  65213   .   16a-/   .
134 65338   4c-\ 4e-\   4f/ (4a-/   .
135 65878   4B-\ 4d-\   4g-/ 4b-/   .
=47 =47 =46 =46 =46
136 66278   4D-\    8.dd-/L <
136.75  66601   .   16cc-/Jk    .
137 66708   4A-\ 4d-\   4f/ 4cc-/   .
138 67248   4G-\    [4g-/ 4b-/) .
=48 =48 =47 =47 =47
*   *   *   *^  *
139 67628   4E-\    8.ee-/L 4g-\]   .
139.75  67951   .   16dd-/Jk    .   .
140 68058   4B-\ 4e-\   4dd-/   4gn'\   .
141 68608   4A-\    4cc-/   (4a-\   .
=49 =49 =48 =48 =48 =48
*   *   *^  *   *   *
142 69028   4r  2.En\   8.ee-/L 4g#\)   .
142.75  69506   .   .   16ddn/Jk    .   .
143 69665   4Bn\ 4en\   .   [2dd/   4g#\    .
144 70528   4B\ 4e\ .   .   4g#\    .
*   *   *v  *v  *   *   *
*   *   *   *v  *v  *
=50 =50 =49 =49 =49
*   *   *k[f#c#g#d#]    *k[f#c#g#d#]    *k[f#c#g#d#]
*   *   *   *^  *
145 70988   4AA/    4dd/]   4gn\    .
146 71458   4A\ 4.cc#/  4e\ 4g\ .
147 72178   4A\ .   4d#\ 4g\    .
147.5   72408   .   8dd#/   .   .
*   *   *   *v  *v  *
=51 =51 =50 =50 =50
148 72638   4GG#/   8.cc#\L .
148.75  73130   .   16b#\Jk .
149 73294   4G#\ 4d#\ 4f#\  4dd#\   .
150 73938   4G#\ 4c#\ 4f#\  8bn/L   .
150.5   74138   .   (8a/J   .
=52 =52 =51 =51 =51
151 74338   4r  4g#/)   .
152 74768   4G#\ 4B#\ 4f#\  (4.dd#\ .
153 75338   4G#\ 4B#\ 4f#\  .   .
153.5   75518   .   8ee\    .
=53 =53 =52 =52 =52
154 75698   4C#/    8.dd#\L .
154.75  75998   .   16cc#\Jk    .
155 76098   4G#\ 4c#\ 4e\   4ee\)   .
156 76588   4r  (8bn/L  .
156.5   76768   .   8a/J    .
=54 =54 =53 =53 =53
157 76948   4EE/    4g#/)   .
158 77398   4C#\ 4G#\ 4c#\  (4.gg#\ .
159 78028   4C#\ 4G#\ 4c#\  .   .
159.5   78258   .   8aa\    .
=55 =55 =54 =54 =54
160 78488   4DD#/   8gg#\L  .
160.5   78668   .   8ff##\J .
161 78848   4D#\ 4A#\ 4c#\  4.dd#\  .
162 79348   4D#\ 4F##\ 4c#\ .   .
162.5   79533   .   8ee\    .
=56 =56 =55 =55 =55
163 79718   4GG#/   4ff#\   .
164 80118   4D#\ 4G#\ 4B#\  4.gg#\  .
165 80588   4G#\ 4B#\ 4f#\  .   .
165.5   80778   .   8ff#\   .
=57 =57 =56 =56 =56
166 80968   4CC#/   8ee\L   .
166.5   81153   .   8dd#\J  .
167 81338   4G#\ 4c#\ 4e\   4cc#\   .
168 81788   4F##\ 4c#\ 4e\  8b/L    .
168.5   81973   .   8a/J    .
=58 =58 =57 =57 =57
169 82158   4C#/    4g#/)   .
170 82788   4G#\ 4c#\ 4e\   (4.cc#\ .
171 83468   4G#\ 4c#\ 4e\   .   .
171.5   83728   .   8dd#\   .
=59 =59 =58 =58 =58
172 83988   4D#\    8cc#\L  .
172.5   84168   .   8b#\J   .
173 84348   4G#\ 4B#\ 4f#\  (4dd#\) .
174 84928   4G#\ 4B#\ 4f#\  8bn/L   .
174.5   85108   .   8a/J    .
=60 =60 =59 =59 =59
175 85288   4BB#/   4g#/)   .
176 85718   4G#\ 4d#\ 4f#\  (4.dd#\ .
177 86178   4G#\ 4d#\ 4f#\  .   .
177.5   86368   .   8ee\    .
=61 =61 =60 =60 =60
178 86558   4BBn/   8.dd#\L <
178.75  87006   .   16cc#\Jk    .
179 87155   4G#\ 4c#\ 4g#\  2ee#\)  .
180 87618   4G#\ 4c#\   .   .
=62 =62 =61 =61 =61
181 88028   4AA#/   (8dd#\L .
181.5   88248   .   8cc#\J  .
182 88468   4F#\ 4c#\ 4f#\  4ff#\)  .
183 88868   4AAn/   (8dd#\L .
183.5   89140   .   8cc#\J  .
=63 =63 =62 =62 =62
184 89412   4E\ 4A\ 4c#\ 4f##\  4ff##\) .
185 90008   4r  (8dd#\L .
185.5   90438   .   8cc#\J  .
186 90868   4r; 8ccc#\) .
186.5   91932   .   8r; .
=64 =64 =63 =63 =63
187 92996   4GG#/   8g#/L   .
187.5   93429   .   8a/ .
188 93861   4G#\ 4c#\ 4e\   8g#/    .
188.5   94125   .   8f##/   .
189 94388   4F#\ 4G#\ 4B#\  8g#/    .
189.5   94588   .   8ee/J   .
=65 =65 =64 =64 =64
190 94788   4CC#/   8cc#/L  .
190.5   95013   .   8c#/J   .
191 95238   4G#\ 4e\    2cc#\   .
192 95958   4G#\ 4e\    .   .
=66 =66 =65 =65 =65
193 96388   4E\ 4r  .
194 97008   4G#\ 4c#\ 4g#\  (4.gg#\ p
195 97718   4G#\ 4c#\ 4g#\  .   .
195.5   97938   .   8aa\    .
=67 =67 =66 =66 =66
*   *   *   *^  *
196 98158   4D#\    8gg#/L  4r  .
196.5   98368   .   8ff##/J .   .
197 98578   4A#\ 4c#\   2dd#/)  8g#\L   .
197.5   98908   .   .   8f##\J  .
198 99238   4A#\ 4c#\   .   &(4d#\&)    .
=68 =68 =67 =67 =67 =67
199 99788   4GG#/   (4ff#/  4r  .
200 100318  4D#\ 4G#\ 4B#\  4.gg#/  4f#\    .
201 100928  4D#\ 4G#\ 4B#\  .   [4g#\   .
201.5   101163  .   8ff#/   .   .
=69 =69 =68 =68 =68 =68
202 101398  4C#/    8ee/L   8g#\L]  .
202.5   101603  .   8dd#/J  8f#\J   .
203 101808  4G#\    4cc#/   8e\L    .
203.5   102013  .   .   8d#\J   .
204 102218  4F##\ 4e\   8b/L    4c#\    .
204.5   102428  .   8a/J    .   .
=70 =70 =69 =69 =69 =69
205 102638  4CC#/   4g#/)   8B\L    .
205.5   102873  .   .   8A\J    .
206 103108  4e\ (4.cc#/ &(4G#\&)    .
207 103808  4G#\ 4e\    .   [4c#\   .
207.5   104048  .   8dd#/   .   .
=71 =71 =70 =70 =70 =70
208 104288  4D#\    8cc#/L  8c#\L]  .
208.5   104498  .   8b#/J   8d#\J   .
209 104708  4G#\ 4f#\   4dd#/   8c#\L   .
209.5   104918  .   .   8B#\J   .
210 105128  4G#\ 4f#\   8bn/L   4d#\    .
210.5   105338  .   8a/J    .   .
=72 =72 =71 =71 =71 =71
211 105548  4BB#/   4g#/)   8Bn\L   .
211.5   105778  .   .   8A\J    .
212 106008  4G#\ 4f#\   (4.dd#/ 4G#\    .
213 106528  4G#\ 4f#\   .   4r  .
213.5   106748  .   8ee/    .   .
=73 =73 =72 =72 =72 =72
214 106968  4BBn/   4r  8dd#\L  <
214.5   107188  .   .   8cc#\J) .
215 107408  4G#\ 4c#\ 4g#\  (8ddd#/L    2ee#\   .
215.5   107638  .   8ccc#/J .   .
216 107868  4r  4eee#/) .   .
=74 =74 =73 =73 =73 =73
217 108288  4AAA#/ 4AA#/    4r  (8dd#\L .
217.5   108518  .   .   8cc#\J  .
218 108748  4F#\ 4c#\ 4f#\  8ddd#/L 4ff#\)  .
218.5   108968  .   8ccc#/J .   .
219 109188  4AAAn/ 4AAn/    &(4fff#/&)  (8dd#\L .
219.5   109448  .   .   8cc#\J  .
=75 =75 =74 =74 =74 =74
220 109708  4A\ 4c#\ 4f##\  8ddd#/L 4ff##\) .
220.5   109958  .   8ccc#/J .   .
221 110208  4r  &(4fff##/&) (8dd#\L .
221.5   110543  .   .   8cc#\J  .
222 110878  4r; 4r  8cccc#'\)   f
222.5   111798  .   .   8r; .
*   *   *   *v  *v  *
=76 =76 =75 =75 =75
*   *   *^  *   *
223 112718  8G#/L   4GGG#'\ 4GG#'\  2.r .
223.5   113186  8A/ .   .   .
224 113653  8G#/    4E\ 4c#\    .   .
224.5   113946  8F##/   .   .   .
225 114238  8G#/    4F#\ 4B#\   .   .
225.5   114578  8e/J    .   .   .
=77 =77 =76 =76 =76 =76
226 114918  8.c#/L  4CC#\   4r  .
226.75  115691  16C#/Jk .   .   .
*   *   *v  *v  *   *
*   *   *clefG2 *   *
*   *   *^  *   *
227 115948  4r  4e'\ 4cc#'\ 2c#/    .
228 116976  4r  4r  .   .
*   *   *v  *v  *   *
=78 =78 ==  ==  ==
*-  *-  *-  *-  *-
!!!ENC: Craig Stuart Sapp
!!!END: 2005/03/21/

With the first two columns I create a timemap, such as the demo I use with verovio:

http://www.humdrum.org/vhv-demos/recordings

With the timestamp mappings and alignment is done outside of verovio.

Doing score-based annotations events in a similar manner, but the @tsamp method should work for me for now.

If you have read this far: How would more than one recording be encoded, with multiple recordings sharing the same time alignment points in the score. In other words, in the demo alignment link above, I have 5 recordings aligned to the same score. It would be wasteful to give each <when> a separate id, since they share a common set of <when> points in the score.

pe-ro commented 7 years ago

How does this link to the score? You are not going to make me label each note with a reference, are you?

Not necessarily. Of course, when linking events to time points, every event has to point from itself to the right <when> --

<note xml:id="n1" when="#w1"/>
<note xml:id="n3" when="#w1"/>
<chord xml:id="c7" when="#w1"/>

But when done the other way around, the @data attribute on <when> can be used to point from a time point to any number of events --

<when xml:id="w1" data="#n1 #n3 #c7"/>

I can imagine three categories of recording alignment data:

(1) give an independent real-timestamp to every note (onset). This would involve giving a when reference to each note. This might be necessary when aligning to arpeggiated notes. In general it is difficult to extract individual timings for notes in a chord, so I don't do this often.

One way to give every event an independent timestamp (by which I think you mean one that is not based on musical time) is to use @when. Another way is to use @tstamp.real --

<note xml:id="n45" tstamp.real="blah"/>

Unfortunately, right now @tstamp.real only allows values in terms of ISO time. So, to accommodate qstamps and such, the kinds of values it supports should be extended or additional attributes (one for qstamps, one for MIDI ticks,etc.) should be added. Ultimately, the goal (I think) would be support the same set of values as those provided for in @betype on <recording>.

(2) give a real-timestamp to every "event" in the score, where an "event" is a set of notes. This would ideally involve a directive, such as annot with a specific @tstamp. since the when would apply to any notes at the given timestamp.

This is more "round-about", but easily accomplished --

<note xml:id="n1"/>
<note xml:id="n2"/>
...
<annot plist="#n1 #n2" when="#w1"/>

The notes are "gathered" by the annotation, which is linked to a time point. As you say, the assumption is that the events referenced in @plist all occur at the same time; that is, at "w1".

(3) give a real-timestamp to an occasional "event", such as once per beat, once per measure, etc. In this case the intervening @tstamps would be linearly interpolated between two real-timestamps present in the timeline (i.e., assuming a constant tempo between the two explicit time alignment points).

Here, we have to go back to <recording> and <when> elements. I didn't intend to give the impression with my previous examples that every event requires a corresponding <when> or vice versa. There's nothing wrong with a little interpolation every now and then. In the following example, only some notes are assigned to a time point. The timing of the others can be inferred from the preceding time point plus the duration of intervening events. So, n1 occurs at w1 and n4 at w2. The "location" of n2 is w1 + duration (n1) in the same units as the time line.

<performance label="Sounds Good!" xmlns="http://www.music-encoding.org/ns/mei"
  xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <recording begin="0" end="500" betype="time">
    <when xml:id="when1" absolute="100"/>
    <when xml:id="when2" absolute="200"/>
    <when xml:id="when4" interval="6" since="#when2"/>
  </recording>
</performance>
...
<note xml:id="n1" when="#when1"/>
<note xml:id="n2"/>
<note xml:id="n3"/>
<note xml:id="n4" when="#when2"/>

If you have read this far: How would more than one recording be encoded, with multiple recordings sharing the same time alignment points in the score. In other words, in the demo alignment link above, I have 5 recordings aligned to the same score. It would be wasteful to give each a separate id, since they share a common set of points in the score.

One could either use 5 recording elements, each with its own independent timeline--

<recording>
  <when xml:id="r1w1"/>
  <when xml:id="r1w2"/>
 ...
</recording>
<recording>
  <when xml:id="r2w1"/>
  <when xml:id="r2w2"/>
 ...
</recording>

What you call "wasteful", I can call "explicit", since it doesn't mix the data from one timeline with another. But, one could use a single <recording> with a single timeline to represent all 5 recordings --

<recording>
  <when xml:id="r1w1"/>
  <when xml:id="r1w2"/>
  <when xml:id="r2w1"/>
  <when xml:id="r2w2"/>
  <when xml:id="r1r2w1"/>
 ...
</recording>

Note that the last <when> identifies a point in both recordings. Of course, the value of its @absolute attribute has to be valid for both recordings. In other words, the recordings have to share the same "time base".

craigsapp commented 7 years ago

Several people requested this feature last week at the ME(I) conference.

rettinghaus commented 7 years ago

Please, feel free to implement it.

craigsapp commented 7 years ago

I could care less.

pe-ro commented 7 years ago

You mean you could care less than you do now? Perhaps you mean you couldn't (possibly) care less. 😀

craigsapp commented 7 years ago

:-)

craigsapp commented 7 years ago

I can already hack the feature by hijacking the new figured-bass system: using a list of <f> to function as harm@n.

Applied to first example in this thread:

screen shot 2017-05-21 at 9 07 05 pm
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://music-encoding.org/schema/3.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="3.0.0">
 <meiHead>
  <fileDesc>
   <titleStmt>
    <title />
   </titleStmt>
   <pubStmt>
    <date>2016-12-18 20:53:57</date>
   </pubStmt>
  </fileDesc>
  <encodingDesc>
   <projectDesc>
    <p>Transcoded from Humdrum with Verovio version 0.9.13-dev-2a282ac-dirty</p>
   </projectDesc>
  </encodingDesc>
  <extMeta>
   <frames xmlns:humxml="http://www.humdrum.org/ns/humxml">
    <metaFrame n="0" token="!!!filter: recip -cxaemxhm|metlev -caxemxhm" xml:id="loc0">
     <frameInfo>
      <startTime float="0" />
      <frameType>reference</frameType>
      <referenceKey>filter</referenceKey>
      <referenceValue>recip -cxaemxhm|metlev -caxemxhm</referenceValue>
     </frameInfo>
    </metaFrame>
    <metaFrame n="1" token="!!!voices: 3" xml:id="loc1">
     <frameInfo>
      <startTime float="0" />
      <frameType>reference</frameType>
      <referenceKey>voices</referenceKey>
      <referenceValue>3</referenceValue>
     </frameInfo>
    </metaFrame>
   </frames>
  </extMeta>
 </meiHead>
 <music>
  <body>
   <mdiv>
    <score>
     <scoreDef xml:id="scoredef-000000199460590">
      <staffGrp xml:id="m-000000101126834" symbol="bracket">
       <staffDef xml:id="staffdef-000000002182961" clef.shape="G" clef.line="2" key.sig="0" meter.count="2" meter.unit="1" meter.sym="cut" n="1" label="Superius" label.abbr="S" lines="5" />
       <staffDef xml:id="staffdef-000000048101113" clef.shape="G" clef.line="2" clef.dis="8" clef.dis.place="below" key.sig="0" meter.count="2" meter.unit="1" meter.sym="cut" n="2" label="Tenor" label.abbr="T" lines="5" />
       <staffDef xml:id="staffdef-000000091919075" clef.shape="G" clef.line="2" clef.dis="8" clef.dis.place="below" key.sig="0" meter.count="2" meter.unit="1" meter.sym="cut" n="3" label="Contra" label.abbr="C" lines="5" />
      </staffGrp>
     </scoreDef>
     <section xml:id="section-000000093141442">
      <measure xml:id="measure-L13" n="1">
       <staff xml:id="staff-L13F3" n="1">
        <layer xml:id="layer-L13F3" n="1">
         <mRest xml:id="mrest-000000088119035" />
        </layer>
       </staff>
       <staff xml:id="staff-L13F2" n="2">
        <layer xml:id="layer-L13F2" n="1">
         <mRest xml:id="mrest-000000044837993" />
        </layer>
       </staff>
       <staff xml:id="staff-L13F1" n="3">
        <layer xml:id="layer-L13F1" n="1">
         <note xml:id="note-L14F1" dur="4" oct="3" pname="c" accid.ges="n" />
         <note xml:id="note-L15F1" dur="4" oct="3" pname="d" accid.ges="n" />
         <note xml:id="note-L16F1" dur="4" oct="3" pname="e" accid.ges="n" />
         <note xml:id="note-L17F1" dur="4" oct="3" pname="f" accid.ges="n" />
         <note xml:id="note-L18F1" dur="2" oct="3" pname="g" accid.ges="n" />
         <note xml:id="note-L19F1" dur="2" oct="3" pname="a" accid.ges="n" />
        </layer>
       </staff>
       <harm xml:id="harm-L14F4" staff="1" tstamp="1.000000" place="above">
        <fb>
         <f>4</f>
         <f>0</f>
        </fb>
       </harm>
       <harm xml:id="harm-L15F4" staff="1" tstamp="1.250000" place="above">
        <fb>
         <f>4</f>
         <f>2</f>
        </fb>
       </harm>
       <harm xml:id="harm-L16F4" staff="1" tstamp="1.500000" place="above">
        <fb>
         <f>4</f>
         <f>1</f>
        </fb>
       </harm>
       <harm xml:id="harm-L17F4" staff="1" tstamp="1.750000" place="above">
        <fb>
         <f>4</f>
         <f>2</f>
        </fb>
       </harm>
       <harm xml:id="harm-L18F4" staff="1" tstamp="2.000000" place="above">
        <fb>
         <f>2</f>
         <f>0</f>
        </fb>
       </harm>
       <harm xml:id="harm-L19F4" staff="1" tstamp="2.500000" place="above">
        <fb>
         <f>2</f>
         <f>1</f>
        </fb>
       </harm>
       <tie xml:id="tie-000000097174124" startid="#note-L19F1" endid="#note-L21F1" />
      </measure>
      <measure xml:id="measure-L20" n="2">
       <staff xml:id="staff-L20F3" n="1">
        <layer xml:id="layer-L20F3" n="1">
         <mRest xml:id="mrest-000000100615103" />
        </layer>
       </staff>
       <staff xml:id="staff-L20F2" n="2">
        <layer xml:id="layer-L20F2" n="1">
         <mRest xml:id="mrest-000000189426791" />
        </layer>
       </staff>
       <staff xml:id="staff-L20F1" n="3">
        <layer xml:id="layer-L20F1" n="1">
         <note xml:id="note-L21F1" dur="4" oct="3" pname="a" accid.ges="n" />
         <note xml:id="note-L22F1" dur="4" oct="3" pname="g" accid.ges="n" />
         <note xml:id="note-L23F1" dur="1" oct="4" pname="c" accid.ges="n" />
         <note xml:id="note-L24F1" dur="2" oct="3" pname="b" accid.ges="n" />
        </layer>
       </staff>
       <harm xml:id="harm-L21F4" staff="1" tstamp="1.000000" place="above">
        <fb>
         <f>4</f>
         <f></f>
        </fb>
       </harm>
       <harm xml:id="harm-L22F4" staff="1" tstamp="1.250000" place="above">
        <fb>
         <f>4</f>
         <f>2</f>
        </fb>
       </harm>
       <harm xml:id="harm-L23F4" staff="1" tstamp="1.500000" place="above">
        <fb>
         <f>1</f>
         <f>1</f>
        </fb>
       </harm>
       <harm xml:id="harm-L24F4" staff="1" tstamp="2.500000" place="above">
        <fb>
         <f>2</f>
         <f>1</f>
        </fb>
       </harm>
      </measure>
      <measure xml:id="measure-L25" n="3">
       <staff xml:id="staff-L25F3" n="1">
        <layer xml:id="layer-L25F3" n="1">
         <mRest xml:id="mrest-000000112486666" />
        </layer>
       </staff>
       <staff xml:id="staff-L25F2" n="2">
        <layer xml:id="layer-L25F2" n="1">
         <note xml:id="note-L26F2" dur="4" oct="3" pname="c" accid.ges="n" />
         <note xml:id="note-L27F2" dur="4" oct="3" pname="d" accid.ges="n" />
         <note xml:id="note-L28F2" dur="4" oct="3" pname="e" accid.ges="n" />
         <note xml:id="note-L29F2" dur="4" oct="3" pname="f" accid.ges="n" />
         <note xml:id="note-L30F2" dur="2" oct="3" pname="g" accid.ges="n" />
         <note xml:id="note-L31F2" dur="2" oct="3" pname="a" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L25F1" n="3">
        <layer xml:id="layer-L25F1" n="1">
         <note xml:id="note-L26F1" dur="1" oct="4" pname="c" accid.ges="n" />
         <rest xml:id="rest-L30F1" dur="2" />
         <note xml:id="note-L31F1" dur="2" oct="3" pname="f" accid.ges="n" />
        </layer>
       </staff>
       <harm xml:id="harm-L26F4" staff="1" tstamp="1.000000" place="above">
        <fb>
         <f>4</f>
         <f>0</f>
        </fb>
       </harm>
       <harm xml:id="harm-L27F4" staff="1" tstamp="1.250000" place="above">
        <fb>
         <f>4</f>
         <f>2</f>
        </fb>
       </harm>
       <harm xml:id="harm-L28F4" staff="1" tstamp="1.500000" place="above">
        <fb>
         <f>4</f>
         <f>1</f>
        </fb>
       </harm>
       <harm xml:id="harm-L29F4" staff="1" tstamp="1.750000" place="above">
        <fb>
         <f>4</f>
         <f>2</f>
        </fb>
       </harm>
       <harm xml:id="harm-L30F4" staff="1" tstamp="2.000000" place="above">
        <fb>
         <f>2</f>
         <f>0</f>
        </fb>
       </harm>
       <harm xml:id="harm-L31F4" staff="1" tstamp="2.500000" place="above">
        <fb>
         <f>2</f>
         <f>1</f>
        </fb>
       </harm>
       <tie xml:id="tie-000000042866793" startid="#note-L31F2" endid="#note-L33F2" />
       <tie xml:id="tie-000000082856367" startid="#note-L31F1" endid="#note-L33F1" />
      </measure>
      <measure xml:id="measure-L32" n="4">
       <staff xml:id="staff-L32F3" n="1">
        <layer xml:id="layer-L32F3" n="1">
         <mRest xml:id="mrest-000000126322598" />
        </layer>
       </staff>
       <staff xml:id="staff-L32F2" n="2">
        <layer xml:id="layer-L32F2" n="1">
         <note xml:id="note-L33F2" dur="4" oct="3" pname="a" accid.ges="n" />
         <note xml:id="note-L34F2" dur="4" oct="3" pname="g" accid.ges="n" />
         <note xml:id="note-L35F2" dur="1" oct="4" pname="c" accid.ges="n" />
         <note xml:id="note-L37F2" dur="2" oct="3" pname="b" accid.ges="n" />
        </layer>
       </staff>
       <staff xml:id="staff-L32F1" n="3">
        <layer xml:id="layer-L32F1" n="1">
         <note xml:id="note-L33F1" dur="2" oct="3" pname="f" accid.ges="n" />
         <note xml:id="note-L35F1" dur="2" oct="3" pname="e" accid.ges="n" />
         <note xml:id="note-L36F1" dur="1" oct="3" pname="d" accid.ges="n" />
        </layer>
       </staff>
       <harm xml:id="harm-L33F4" staff="1" tstamp="1.000000" place="above">
        <fb>
         <f>4</f>
         <f></f>
        </fb>
       </harm>
       <harm xml:id="harm-L34F4" staff="1" tstamp="1.250000" place="above">
        <fb>
         <f>4</f>
         <f>2</f>
        </fb>
       </harm>
       <harm xml:id="harm-L35F4" staff="1" tstamp="1.500000" place="above">
        <fb>
         <f>2</f>
         <f>1</f>
        </fb>
       </harm>
       <harm xml:id="harm-L36F4" staff="1" tstamp="2.000000" place="above">
        <fb>
         <f>2</f>
         <f>0</f>
        </fb>
       </harm>
       <harm xml:id="harm-L37F4" staff="1" tstamp="2.500000" place="above">
        <fb>
         <f>2</f>
         <f>1</f>
        </fb>
       </harm>
      </measure>
     </section>
    </score>
   </mdiv>
  </body>
 </music>
</mei>
ahankinson commented 7 years ago

Why?

craigsapp commented 7 years ago

Why?

To which comment?

ahankinson commented 7 years ago

Why would you hack the figured bass system to encode harmonic analysis?

craigsapp commented 7 years ago

So I can have multiple <harm> elements displayed correctly until harm@n is implemented in verovio.

craigsapp commented 7 years ago

Another possibility other than using aharm@n="2" system would be to use the <stack> element in <harm> to encode multiple analytic descriptors:

<harm>
      <stack>
           <something type="data1">x</something>
           <something type="data2">y</something>
           <something type="data3">z</something>
     </stack>
</harm>

Which would render something like this:

screen shot 2017-06-26 at 12 06 32 pm

The element <something> would be something to allow an element such as <text> inside of <stack> which is not currently allowed (<abbr> can currently be used).

pe-ro commented 7 years ago

@craigsapp, "hacking" of any sort (<harm> or <stack>) should be avoided.

craigsapp commented 7 years ago

@craigsapp, "hacking" of any sort ( or ) should be avoided.

Don't shoot the messenger: I was passing along a suggestion that someone else made. So you are advocating the initial harm@n method I suggested for avoiding collisions between more than one <harm> item occurring at the same tstamp?

Giving a "stack" of harm items might be easier to implement for verovio, although the harm@n could somehow borrow similar code of verse@n for vertical layout control.

pe-ro commented 7 years ago

Yes, I think harm/@n is a move in the right direction, although Verovio should also be able to avoid collision even when @n isn't present. In that case, the encoding order could be assumed to be the same as the display order. Likewise on verse with/without @n.

craigsapp commented 7 years ago

That sounds good to me.

There might be a question about the ordering relative to the staff position. Would the multiple harm elements be stacked in order of @n from high-to-low or nearest-to-farthest from the staff (so a mirror image ordering when moved above/below the staff). Verses clearly would be high-to-low (not mirror imaged), and harms should probably do the same, of course.

Automatic avoidance when there is no @n on harm and verse would be useful. In that case there would be a complication of vertical alignment. Probably verses and harms would be packed closest to the staff. If there are simultaneous verse/harm elements without @n, but with different counts at each @tstamp, then the edge of the multiple verse/harm text would be jagged furthest from the staff (the top-to-bottom order of the harm/verse elements would be preserved above/below the staff but the horizontal alignment of harm/verse at different tstamps would be different).

In case that last paragraph is not intelligible, here is an example:

screen shot 2017-06-26 at 8 13 03 pm

The the first column of harm data contains @n attributes, but notice that the order of @n is from top to bottom regardless of the position above/below the staff.

When there are gaps in the @n sequence, there would be vertical gaps in the harm stack as illustrated in the second column, where @n="1" and @n="3" are omitted.

The third column shows how the harm would be stacked four deep without @n, and the fourth column shows how two harm without @n would be stacked. In the case where @n is not given, the harm elements are placed close to the staff without gaps, or justifying to align the furthest harm rather than the closest harms.


There is also a complication in that the current <harm> horizontal layout has semi-collision avoidance by vertical offsets (they collide, but there is some code which is attempting to avoid collision with vertical offsets) in issue https://github.com/rism-ch/verovio/issues/358

It would be most useful if harm also behaved like verse in this respect. Harm collision with surrounding harm elements would be resolved by widening the horizontal spacing between them rather than trying to use a vertical offset to avoid collisions.

lpugin commented 6 years ago

harm@n is not taken into account 911b518c7e5b2f1c6323003c4995d105b81480a6

craigsapp commented 6 years ago

Looks great!:

screen shot 2018-02-22 at 6 41 25 am

Although it would make sense if <harm> above the staff were ordered by @n from high-to-low rather than low-to-high.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/4.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://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="2018-02-22T06:39:38" version="2.0.0-dev-3707aab">
                    <name>Verovio</name>
                    <p>Transcoded from Humdrum</p>
                </application>
            </appInfo>
        </encodingDesc>
        <workDesc>
            <work>
                <titleStmt>
                    <title />
                </titleStmt>
            </work>
        </workDesc>
    </meiHead>
    <music>
        <body>
            <mdiv xml:id="mdiv-0000001844041116">
                <score xml:id="score-0000000315043108">
                    <scoreDef xml:id="scoredef-0000000649325189" midi.bpm="400">
                        <staffGrp xml:id="staffgrp-0000002035805134">
                            <staffDef xml:id="staffdef-0000001280047661" clef.shape="G" clef.line="2" meter.count="4" meter.unit="4" n="1" lines="5">
                                <label xml:id="label-0000000229520698">    </label>
                            </staffDef>
                        </staffGrp>
                    </scoreDef>
                    <section xml:id="section-0000001382326301">
                        <measure xml:id="measure-L3" right="end" n="1">
                            <staff xml:id="staff-L3F1N1" n="1">
                                <layer xml:id="layer-L3F1N1" n="1">
                                    <note xml:id="note-L4F1" dur="1" oct="4" pname="c" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm n="1" xml:id="harm-L4F2" place="below" staff="1" tstamp="1.000000">label1</harm>
                            <harm n="2" xml:id="harm-L4F3" place="below" staff="1" tstamp="1.000000">label2</harm>
                            <harm n="3" xml:id="harm-L4F4" place="above" staff="1" tstamp="1.000000">label3</harm>
                            <harm n="4" xml:id="harm-L4F5" place="above" staff="1" tstamp="1.000000">label4</harm>
                        </measure>
                    </section>
                </score>
            </mdiv>
        </body>
    </music>
</mei>
craigsapp commented 6 years ago

It would be nice if <harm> did collision checks:

screen shot 2018-02-22 at 6 52 27 am

Related to issue https://github.com/rism-ch/verovio/issues/318

Also notice issue https://github.com/rism-ch/verovio/issues/358 showing in this example.

Test data:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/4.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://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="2018-02-22T06:49:55" version="2.0.0-dev-3707aab">
                    <name>Verovio</name>
                    <p>Transcoded from Humdrum</p>
                </application>
            </appInfo>
        </encodingDesc>
        <workDesc>
            <work>
                <titleStmt>
                    <title />
                </titleStmt>
            </work>
        </workDesc>
    </meiHead>
    <music>
        <body>
            <mdiv xml:id="mdiv-0000001237131063">
                <score xml:id="score-0000000525105587">
                    <scoreDef xml:id="scoredef-0000000621690074">
                        <staffGrp xml:id="staffgrp-0000002005372762">
                            <staffDef xml:id="staffdef-0000000978391294" clef.shape="G" clef.line="2" meter.count="4" meter.unit="4" n="1" lines="5">
                                <label xml:id="label-0000001744824998">    </label>
                            </staffDef>
                        </staffGrp>
                    </scoreDef>
                    <section xml:id="section-0000001439295186">
                        <measure xml:id="measure-L3" right="end" n="1">
                            <staff xml:id="staff-L3F1N1" n="1">
                                <layer xml:id="layer-L3F1N1" n="1">
                                    <note xml:id="note-L4F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L5F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L6F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L7F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm n="1" xml:id="harm-L4F2" place="above" staff="1" tstamp="1.000000">label1</harm>
                            <harm n="2" xml:id="harm-L4F3" place="above" staff="1" tstamp="1.000000">labelA</harm>
                            <harm n="1" xml:id="harm-L5F2" place="above" staff="1" tstamp="2.000000">label2</harm>
                            <harm n="2" xml:id="harm-L5F3" place="above" staff="1" tstamp="2.000000">labelB</harm>
                            <harm n="1" xml:id="harm-L6F2" place="above" staff="1" tstamp="3.000000">label3</harm>
                            <harm n="2" xml:id="harm-L6F3" place="above" staff="1" tstamp="3.000000">labelC</harm>
                            <harm n="1" xml:id="harm-L7F2" place="above" staff="1" tstamp="4.000000">label4</harm>
                            <harm n="2" xml:id="harm-L7F3" place="above" staff="1" tstamp="4.000000">labelD</harm>
                        </measure>
                    </section>
                </score>
            </mdiv>
        </body>
    </music>
</mei>
craigsapp commented 6 years ago

I like a lot that @n preserves the height across the system:

screen shot 2018-02-22 at 7 00 47 am

Test data:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/4.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://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="2018-02-22T06:49:55" version="2.0.0-dev-3707aab">
                    <name>Verovio</name>
                    <p>Transcoded from Humdrum</p>
                </application>
            </appInfo>
        </encodingDesc>
        <workDesc>
            <work>
                <titleStmt>
                    <title />
                </titleStmt>
            </work>
        </workDesc>
    </meiHead>
    <music>
        <body>
            <mdiv xml:id="mdiv-0000001237131063">
                <score xml:id="score-0000000525105587">
                    <scoreDef xml:id="scoredef-0000000621690074">
                        <staffGrp xml:id="staffgrp-0000002005372762">
                            <staffDef xml:id="staffdef-0000000978391294" clef.shape="G" clef.line="2" meter.count="4" meter.unit="4" n="1" lines="5">
                                <label xml:id="label-0000001744824998">    </label>
                            </staffDef>
                        </staffGrp>
                    </scoreDef>
                    <section xml:id="section-0000001439295186">
                        <measure xml:id="measure-L3" right="end" n="1">
                            <staff xml:id="staff-L3F1N1" n="1">
                                <layer xml:id="layer-L3F1N1" n="1">
                                    <note xml:id="note-L4F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L5F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L6F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                    <note xml:id="note-L7F1" dur="4" oct="4" pname="c" accid.ges="n" />
                                </layer>
                            </staff>
                            <harm n="1" xml:id="harm-L4F2" place="above" staff="1" tstamp="1.000000">1</harm>
                            <harm n="2" xml:id="harm-L4F3" place="above" staff="1" tstamp="1.000000">A</harm>
                            <harm n="2" xml:id="harm-L5F3" place="above" staff="1" tstamp="2.000000">B</harm>
                            <harm n="1" xml:id="harm-L6F2" place="above" staff="1" tstamp="3.000000">3</harm>
                            <harm n="1" xml:id="harm-L7F2" place="above" staff="1" tstamp="4.000000">4</harm>
                            <harm n="2" xml:id="harm-L7F3" place="above" staff="1" tstamp="4.000000">D</harm>
                        </measure>
                    </section>
                </score>
            </mdiv>
        </body>
    </music>
</mei>
lpugin commented 6 years ago

Although it would make sense if above the staff were ordered by @n from high-to-low rather than low-to-high.

The order if is the order of appearance of the elements, placed then from the staff to the outside. I would not try to rely on @n, because it is an att.nNumberLike, which means basically a string. So this would yield other issues with >9 lines. (As it is now, having the order of the elements not being consistent will also not work.)

I like a lot that @n preserves the height across the system:

Yes, although not completely. For example, if you have a system with no occurrence of a line, its space will not be preserved

pe-ro commented 6 years ago

It seems it's not currently available on <harm>, but is there a reason not to use @vgrp there instead of @n?

@n should be reserved for user-defined semantics; that is, it can be used to number a set of elements that belong to a user-defined collection. Forcing one to use it to obtain proper vertical alignment will cause problems.

craigsapp commented 6 years ago

How would harm@n be different from verse@n? For lyric text, @n currently controls the vertical position of the lyric verse.

For @vgrp this causes disparate elements to align vertically, but what happens if there are multiple @vgrps active at the same time? What would define the vertical ordering of such groups?

pe-ro commented 6 years ago

The current members of att.verticalGroup are:

How about making the following members of this class too?

I'm not 100% confident about the following items, but they could be members of att.verticalGroup under certain circumstances:

Increasing the membership in att.verticalGroup would make it possible to actively control the vertical positioning/alignment of more items and eliminate the reliance on @n, or more precisely, allow @n to be used for its intended purpose.

rettinghaus commented 6 years ago

verse@n should't control the vertical position of the lyric verse. verse@n should mark the (logical) number of the verse. What if I want to present verses 3 and 21? Or the frist verse in five different languages?

craigsapp commented 6 years ago

What if a verse is to be sung as the first verse and the third verse? How would you encode that? On the score the verse@n="1" would be labelled as "1., 3." in some other parameter and this is the logical assignment, not the @n (at least as currently implemented in verovio).

If you have a verse@n="3" and a verse@n="21", there is not (or should not be) a gap for positions 4-21. Soverse@nis not controlling the vertical position, but rather then vertical ordering of the verses. Such behavior should also be similar forharm@n`.

rettinghaus commented 6 years ago

Just because the words are identical the first verse must not be the third verse. This is what Verovio does with verse@n="3" and verse@n="21": min

pe-ro commented 6 years ago

I believe @craigsapp is correct when he says that "verse/@n is not controlling the vertical position, but rather then vertical ordering of the verses."

It doesn't necessarily follow, however, that "such behavior should also be similar for harm/@n. The major difference between these things is verses don't cross any hierarchy while control events, like dir, dynam, hairpin, etc. do.

Given the difference, I would say that it's verse that's the special case; that is, it uses it's @n attribute to control vertical ordering, while items with @vgrp do not.

pe-ro commented 6 years ago

I don't believe the Verovio example just given by @rettinghaus exhibits desirable behavior. To render the verses appropriately, one can rely on encoding order or sorted values of @n. There shouldn't be gaps.

craigsapp commented 6 years ago

Given the difference, I would say that it's verse that's the special case; that is, it uses it's @n attribute to control vertical ordering, while items with @vgrp do not.

I want a specific vertical order for harm, so the current implementation using @n is great for me (even though the ordering is upside down for me when the harm is upsidedown, but that is not a problem for me). If @vgrp does not imply vertical ordering then I would not want it implemented it for harm (unless @n remains implemented as well).

lpugin commented 6 years ago

As always it is difficult to draw a line between what relates to semantic and what relates to appearance, and I do not think we will ever agree on what @n is there for. I personally understand @vgrp as being purely visual as illustrated in the example I gave with the dynamics / hairpin (https://github.com/rism-ch/verovio/issues/251#issuecomment-367722132, the use of @vgpp. It is used only to modify the alignment of some elements, and presumably locally - the local aspect of it seems important to me.

With multiple lines of <harms>, I can see a semantic distinction between them and it is not just a local visual alignment question. As an example, I could expect them to represent different types of harmonic annotation, and somebody could want to extract one particular type of <harm>. Having to rely on @vgrp for this does not sound right to me. So in my opinion, if @n is maybe not the right attribute for this, so is not @vgrp.

What is absolutely clear for me is that Verovio should not rely on @n to order the lines but instead on the order of the elements in the encoding. (There should certainly not be gaps in the lyrics.)

pe-ro commented 6 years ago

@lpugin, well-said. It's what I should've said. :grinning:

Different types of harmonic labels can be marked using @type or @class. So, I think we're really talking about how to encode the order of harmonic indications.

My thinking was that this could be expressed through @vgrp; for example, given 3 <harm> elements on beat 1 that would otherwise collide, assigning them different values of @vgrp would avert the collision by rendering them at different distances from the staff. This assumes, however, the values of @vgrp determine the distance from the staff, say '1' closest, '2' next, '3' farthest away.

Since @vgrp was originally intended to make certain that members of the same group (that is, elements with the same value for @vgrp) would end up on the same horizontal plane, this should also work for <harm>. So, if there were 3 <harm> elements on beat 1, but only 2 on beat 2, those on beat 2 would be rendered at the same height as their brethren on beat 1, for example --

harm/vgrp='3'     harm/vgrp='3'
harm/vgrp='2'
harm/vgrp='1'     harm/vgrp='1'

The main question for me is whether @vgrp values determine order or if they're just a convenient grouping mechanism. As an example of the latter, the values '1', '2', and '3' could be replaced with '111', '0', and '23' without any change in the rendering.

If the answer to the question is that the values themselves don't convey any order information (as was the original intent), then either @n or a new attribute has to be employed for this. Looking carefully at the description of @n -- "Provides a numeric designation that indicates an element's position in a sequence of similar elements. Its value must be a non-negative integer." -- the question is, what is meant by the word "similar"? If "similar" means "a collection of <harm> elements, then using @n to order these elements is fine. On the other hand, if "similar" is more open-ended; that is, defined by the encoder, then we might have a problem.

Since harm/@n is already implemented in a particular way in Verovio, I'm now inclined to leave it and justify it by defining "similar" as "elements of the same name at the same logical time (e.g., at the same time stamp)". I believe this would also apply in the case of verse/@n, minus the gaps. It may not be applicable however to events, such as <note>, <chord>, <rest>, etc., or to other structural or textual elements, like <mdiv> or <composer>. But different definitions of @n for control events as opposed to other elements isn't a huge problem if clearly documented.

User-defined groups (and order within them) can be handled better using some other mechanism, say <annot>.