Closed craigsapp closed 6 years ago
Maybe you can use <choice>
and display only one at the time?
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.
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:
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":
With the search-results highlighted in orange in the music notation:
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).
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.
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:
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:
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:
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:
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.
<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 @tstamp
s 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.
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".
Several people requested this feature last week at the ME(I) conference.
Please, feel free to implement it.
I could care less.
You mean you could care less than you do now? Perhaps you mean you couldn't (possibly) care less. 😀
:-)
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:
<?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>
Why?
Why?
To which comment?
Why would you hack the figured bass system to encode harmonic analysis?
So I can have multiple <harm>
elements displayed correctly until harm@n
is implemented in verovio.
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:
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).
@craigsapp, "hacking" of any sort (<harm>
or <stack>
) should be avoided.
@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.
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
.
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:
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.
harm@n
is not taken into account 911b518c7e5b2f1c6323003c4995d105b81480a6
Looks great!:
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>
It would be nice if <harm>
did collision checks:
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>
I like a lot that @n
preserves the height across the system:
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>
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
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.
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 @vgrp
s active at the same time? What would define the vertical ordering of such groups?
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.
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?
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. So
verse@nis not controlling the vertical position, but rather then vertical ordering of the verses. Such behavior should also be similar for
harm@n`.
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"
:
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.
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.
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).
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.)
@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>
.
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: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: