WolfgangDrescher / lassus-geistliche-psalmen

Digital edition of «Geistliche Psalmen mit dreyen Stimmen» by Orlandus and Rudolphus Lassus. Encoded in Humdrum (Kern).
https://lassus.mh-freiburg.de
3 stars 1 forks source link

MIDI tempo and mode notes #6

Open craigsapp opened 2 years ago

craigsapp commented 2 years ago

If you want to have nicer playback tempos, you can add tempos to the score like this:

**kern  **text  **kern  **text  **kern  **text
*staff3 *staff3 *staff2 *staff2 *staff1 *staff1
*Ivox   *   *Ivox   *   *Ivox   *
*I"Bassus   *   *I"Tenor    *   *I"Cantus   *
*clefC3 *   *clefC2 *   *clefG2 *
*M2/1   *   *M2/1   *   *M2/1   *
*k[]    *   *k[]    *   *k[]    *
*met(C|)    *   *met(C|)    *   *met(C|)    *
*MM280  *   *MM280  *   *MM280  *
=1  =1  =1  =1  =1  =1
1r  .   00r .   1dd Se-
1g  Se- .   .   2dd -lig
.   .   .   .   2dd zu
=2  =2  =2  =2  =2  =2

Where *MM280 is the tempo marking, meaning 280 quarter notes per minute (units are always quarter notes).

Also for elegance, I would place the time signature, meter sign and tempo adjacent to each other in that order (I moved the key signature before the time signature):

**kern  **text  **kern  **text  **kern  **text
*staff3 *staff3 *staff2 *staff2 *staff1 *staff1
*Ivox   *   *Ivox   *   *Ivox   *
*I"Bassus   *   *I"Tenor    *   *I"Cantus   *
*clefC3 *   *clefC2 *   *clefG2 *
*k[]    *   *k[]    *   *k[]    *
*M2/1   *   *M2/1   *   *M2/1   *
*met(C|)    *   *met(C|)    *   *met(C|)    *
*MM280  *   *MM280  *   *MM280  *
=1  =1  =1  =1  =1  =1
1r  .   00r .   1dd Se-
1g  Se- .   .   2dd -lig
.   .   .   .   2dd zu
=2  =2  =2  =2  =2  =2

Somewhat related, if you want to assign modalities to the pieces you can add modal qualifiers to the key designation:

*C:        == C major
*c:        == C minor

*c:dor    == C dorian
*c:phr    == C phrygian
*C:lyd    == C lydian
*C:mix   == C mixolydian

*c:aeo    == C aeolean (modal version of C minor)
*c:loc     == C locrian
*C:ion    == C ionian (modal version of C major)

Notice that the third scale degree of the mode matches the capitalization of the tonic (c implies E-flat is in the scale, and C implies E-natural). This allows using the nearest of major/minor scales when the exact mode is not needed.

So in this example piece, I would say that it is in G mixolydian, and I place the key assignment just under the key signature:

**kern  **text  **kern  **text  **kern  **text
*staff3 *staff3 *staff2 *staff2 *staff1 *staff1
*Ivox   *   *Ivox   *   *Ivox   *
*I"Bassus   *   *I"Tenor    *   *I"Cantus   *
*clefC3 *   *clefC2 *   *clefG2 *
*k[]    *   *k[]    *   *k[]    *
*G:mix  *   *G:mix  *   *G:mix  *
*M2/1   *   *M2/1   *   *M2/1   *
*met(C|)    *   *met(C|)    *   *met(C|)    *
*MM280  *   *MM280  *   *MM280  *
=1  =1  =1  =1  =1  =1
1r  .   00r .   1dd Se-
1g  Se- .   .   2dd -lig
.   .   .   .   2dd zu
=2  =2  =2  =2  =2  =2
WolfgangDrescher commented 2 years ago

What is currently the best way to implement a MIDI player for Verovio? I tried some but they were not satisfying (synth-js, timidity, midi-player-js, Midi.js). So I guess https://github.com/rism-digital/midi-player still is the way to go with https://github.com/zz85/wild-web-midi as WebAssembly module. I would like to use another frontend for the player since I don't want to use jQuery. But as I understood it wild-web-midi would give me back a sound file, AudioBuffer or Blob that can be handled by any other player?

So in this example piece, I would say that it is in G mixolydian, and I place the key assignment just under the key signature:

I'm not so sure about the mode here since it (beatus vir) ends in c and thus looks to C ionian to me with a atypical beginning that seems to be in G mixolydian. Never the less: is there a way to mark spines with a distinction between let's say dorian and the plagal mode hypodorian to store some additional informations about the ambitus? It would be interesting to compare the expected range of the abitus with the effective max. and min. notes (from prange) within a voice. This could even be interesting for prange --score to display expected ambitus of the mode and effective ambitus of the voice somehow in the SVG.

Otherwise I would just use https://github.com/WolfgangDrescher/lassus-geistliche-psalmen/blob/master/meta/01-beatus-vir.yaml to store this information and parse it later on.

Btw. I found the Perl script to convert PMX files into SVG on https://wiki.ccarh.org/wiki/Music_253_Humdrum_homework. Is the code of the converter itself open sourced? I am thinking about a different (and maybe even interactive) way to display this graph since im not interested in average or median notes but more in the comparison to the ambitus of the mode and the range of the voice.

What can Humdrum do with the mode annotated like e.g. d:dor? Is there any command that can be useful for this or does it just have informational purpose?

craigsapp commented 2 years ago

What is currently the best way to implement a MIDI player for Verovio? I tried some but they were not satisfying (synth-js, timidity, midi-player-js, Midi.js). So I guess https://github.com/rism-digital/midi-player still is the way to go with https://github.com/zz85/wild-web-midi as WebAssembly module. I would like to use another frontend for the player since I don't want to use jQuery. But as I understood it wild-web-midi would give me back a sound file, AudioBuffer or Blob that can be handled by any other player?

I looked around and there was nothing better than Wild Web MIDI adjusted by @lpugin for compiling with emscripten about 6 years ago. Since then I have look around every once in a while, but not noticed anything better (there probably is, but I have not come across it). The MIDI player used in the Piano Roll Project at Stanford looks promising:

 https://pianolatron.stanford.edu

 https://github.com/sul-cidr/pianolatron

but it is wrapped up in a lot of scripting languages, and I have not had time to see if it can be distilled into pure Javascript (I also would like to avoid using jQuery and other nonsense).

But as I understood it wild-web-midi would give me back a sound file, AudioBuffer or Blob that can be handled by any other player?

The front end should be independent of WWM, I played around with making my own last year, but it was too much of a bother, so I didn't bother much trying to remove jQuery from the interface.

If you are not planning on having a lot of files (such as less than a few thousand), and you have lots of storage on your web server, you can consider converting the MIDI to MP3 offline (I use timidity for this on JRP), and then use the MP3s for playback. This is what I do on the JRP and Tasso websites (WWM is not used and only the HTML 5 <audio> interface). For JRP there is about 4GB of MP3 files (for about 60 hours of performance time). For VHV where there is dynamically generated content, WWM is necessary since I do not want to run a web service to convert to MP3 on my server in realtime.

craigsapp commented 2 years ago

I'm not so sure about the mode here since it (beatus vir) ends in c and thus looks to C ionian to me with a atypical beginning that seems to be in G mixolydian.

Yes, I must have been reading the C clefs wrong. The piece ends in a C major triad. Here is the keyscape for it:

Screen Shot 2022-03-06 at 8 53 51 AM

It matches most strongly to C major throughout its entirety. So categorizing at C ionian is best.

craigsapp commented 2 years ago

What can Humdrum do with the mode annotated like e.g. d:dor? Is there any command that can be useful for this or does it just have informational purpose?

I don't do anything much with the modal refinement (keyscapes only look at major/minor and I have problems getting good results when trying to deal with modal assignments).

But they would be useful for some types of analysis. Cadences in dorian and phrygian are quite different due to the 6th scale degree being a minor second above the 5th.

I do use the tonic for calculating relative versus absolute keyscapes. In absolute mode green is C major, light blue is G, and yellow is F. For a relative view (functional harmony view), I transpose to C major/minor and then green means tonic, light blue means dominant and yellow means subdominant. But this does not consider the modal refinement since I color keys with a major third in a bright color and those with a minor third in a darker color.

craigsapp commented 2 years ago

Btw. I found the Perl script to convert PMX files into SVG on https://wiki.ccarh.org/wiki/Music_253_Humdrum_homework. Is the code of the converter itself open sourced? I am thinking about a different (and maybe even interactive) way to display this graph since im not interested in average or median notes but more in the comparison to the ambitus of the mode and the range of the voice.

That specific method is private. There is a Javascript/Angular implementation for purely on the web, but I cannot find the link to it at the moment. The converter from Humdrum to SCORE PMX data is the Humdrum Extras tool called "prange" using the --score option:

http://extras.humdrum.org/man/prange

https://github.com/craigsapp/humextra/blob/master/cli/prange.cpp

craigsapp commented 2 years ago

Otherwise I would just use https://github.com/WolfgangDrescher/lassus-geistliche-psalmen/blob/master/meta/01-beatus-vir.yaml to store this information and parse it later on.

prange also has textual output that can be used for this purpose:

[craig@agviq ~/git-cloud/verovio/tools] $ prange beatus_vir.krn
**keyno **kern  **count
53  F   1
55  G   4
57  A   11
59  B   9
60  c   22
62  d   11
64  e   30
65  f   16
66  f#  2
67  g   36
69  a   18
71  b   22
72  cc  26
74  dd  15
76  ee  14
77  ff  3
79  gg  7
*-  *-  *-
!!tessitura:    26 semitones
!!mean: 67.0891 (g)
!!median:   67 (g)

Just the bassus:

$ extractx -s 1 /tmp/ss | prange 
**keyno **kern  **count
53  F   1
55  G   4
57  A   11
59  B   9
60  c   15
62  d   5
64  e   13
65  f   6
66  f#  1
67  g   13
69  a   3
*-  *-  *-
!!tessitura:    16 semitones
!!mean: 61.8148 (d)
!!median:   62 (d)

The ambitus:

$ extractx -s 1 beatus_vir.krn | prange  | extractx -s 2| ridx -H | fmt | sed 's/ .* / /'
F a

(F3 to A4 for the Bassus part)

craigsapp commented 2 years ago

Never the less: is there a way to mark spines with a distinction between let's say dorian and the plagal mode hypodorian to store some additional informations about the ambitus?

I am in discussion with several people on how to encode something like hypodorian in a key such as *d:dor. Best ideas at the moment are using the numeric system for church modes: *d:2t or prefixing the three-letter mode with an h: *d:hdor.

There is no formal system, but you could make one up such as *plagal or *hypo interpretations. With polyphonic music, it is hard to fit into these categories. Where are the melodies from in these psalm settings? The tenor part is from c to cc so it is in authentic, while the Bassus is close in form to the plagal/hypo. The cantus is from G4 to G5 is somewhat plagal as well.

craigsapp commented 2 years ago

That specific method is private.

But I just tried the script and it is working (the converter from PMX to SVG is private, but the conversion itself is publicly accessible). From the command line:

prange --score input.krn | pmx2svg > output.svg

In theory it could be done directly on a website, but I would cache the plots before hand to avoid delays related to talking across web sites. A lazy way would be to hack the PMX data to add an option to prange to remove the median note (it is one of the lines. Prange has a -q option to show the quartile note in the plot (which is optional since I usually don't want to see it). The median and ambitus notes are in the form:

1 2 97.5 1 0 0 4 0 0 -2
1 2 97.5 8 0 0 4 0 0 -2
1 2 97.5 104 0 1 4 0 0 -1.66

Where the median one has the fourth number on the line greater than 100. Here is an example of removing the median notes by hand from the PMX data before converting to SVG:

Screen Shot 2022-03-06 at 9 58 54 AM
WolfgangDrescher commented 2 years ago

The MIDI player used in the Piano Roll Project at Stanford looks promising

I checked how they have done the playback. They are using midi-player-js (https://github.com/sul-cidr/pianolatron/blob/main/src/components/SamplePlayer.svelte#L342-L361) to generate real time JS events from the MIDI that then uses a custom "Piano" class (https://github.com/sul-cidr/pianolatron/blob/main/src/lib/tonejs-piano.js#L553-L570) in combination with the tone npm package. So it's not a single rendered audio file that just gets played, but multiple sound files (https://github.com/sul-cidr/pianolatron/tree/main/public/samples) that get played in a loop for each MIDI event.

If you are not planning on having a lot of files (such as less than a few thousand), and you have lots of storage on your web server, you can consider converting the MIDI to MP3 offline (I use timidity for this on JRP), and then use the MP3s for playback.

Yes I was also thinking about this, but I'm confident to somehow get the audio running directly in the browser.

$ extractx -s 1 beatus_vir.krn | prange | extractx -s 2| ridx -H | fmt | sed 's/ .* / /'

That is a nice command. Thank you!

I am in discussion with several people on how to encode something like hypodorian in a key such as d:dor. Best ideas at the moment are using the numeric system for church modes: d:2t or prefixing the three-letter mode with an h: *d:hdor.

This sound promising. Both variants look fine for me. Please give me a notice then it's implemented and ready to use or when you need someone to test the implementation (I'm not so deep into C++ yet to help with the implementation itself).

There is no formal system, but you could make one up such as plagal or hypo interpretations.

If *plagel get introduced a corresponding *authentic would also be needed.

With polyphonic music, it is hard to fit into these categories. Where are the melodies from in these psalm settings?

Ulenberg, Kaspar: Die Psalmen Davids: https://www.digitale-sammlungen.de/de/view/bsb11116252?page=53

How would you encode this considering the problematic of the needed bar lines in Verovio? Bars by printed staffs from the source or by lyrics? Since I don't have a GitHub repository yet for this my WIP draft is:

!!!COM: Caspar Ulenberg
!!!OTL: Beatus vir
!!!filter: kern2mens -NI
**kern  **text
*clefC3 *
*k[b-]  *
*M2/1   *
*met(C|)    *
=-  =-
1c  Se-
2c  -lig
2c  zu
2A  prei-
2B- -sen
1A  ist
1G  der
1F  mann/
2r  .
=-  =-
1F  Der
2A  sich
2B- ent-
2c  -helt
2c  von
2d  den
2c  got-
1B- -lo-
1A  -sen/
2r  .
=-  =-
1G  Und
2A  wan-
2B- -delt
2c  nicht
2A  im
2B- rat
2c  der
1d  bö-
1c  -sen/
2r  .
=-  =-
1c  Trit
1f  auch
1e  nicht
2d  auff
2c  der
2c  sün-
2B- -der
1c  ban/
2r  .
=-  =-
1c  Noch
2d  sitzt
2d  bey
2A  giff-
2d  -tig-
2c  -bö-
2A  -sen
1B- rot
1A  ten/
2r  .
=-  =-
1c  Da
2A  man
2G  hon-
2F  -schimpf-
2A  -lich
2B- weiß
2A  zu
1G  spot-
0Fl;    -ten.
==  ==
*-  *-
WolfgangDrescher commented 2 years ago

Is there a documentation on how to read PMX? I can't figure out how to interpret it. E.g.:

1 2 97.5 1 0 0 4 0 0 -2
1 2 97.5 8 0 0 4 0 0 -2
1 2 97.5 104 0 1 4 0 0 -1.66

Or

#define SVG t 1 1 \n_99%svg%
t 2 10 14 1 1 0 0 0 0 -1.35
_00
8 1 0 0 0 200
8 2 0 -6 0 200
14 1 0 2
14 1 200 2
14 1 0 2 8
3 2 2
3 1 2 0 1
1 2 25 5 0 -1 4 0 0 0 99 0 0 6.5573
1 2 25 6 0 -1 4 0 0 0 99 0 0 8.6693
1 2 25 7 0 -1 4 0 0 0 99 0 0 17.1173
1 2 25 8 0 -1 4 0 0 0 99 0 0 19.9333
1 2 25 9 0 -1 4 0 0 0 99 0 0 12.8933
1 2 25 10 0 -1 4 0 0 0 99 0 0 12.1893
1 2 25 11 0 -1 4 0 0 0 99 0 0 4.4453
1 2 25 12 0 -1 4 0 0 0 99 0 0 7.2613
t 1 25 -3 1 1 0 0 0 0 -2
_00Cantus
1 2 25 5 0 0 4 0 0 -2
1 2 25 12 0 0 4 0 0 -2
1 2 25 108 0 1 4 0 0 -1.66
1 2 97.5 1 0 -1 4 0 0 0 99 0 0 9.58036
1 2 97.5 2 0 -1 4 0 0 0 99 0 0 8.54506
1 2 97.5 3 0 -1 4 0 0 0 99 0 0 19.9333
1 2 97.5 4 0 -1 4 0 0 0 99 0 0 12.6862
1 2 97.5 4 0 -1 4 0 0 0 99 0 0 3.36859
1 2 97.5 5 0 -1 4 0 0 0 99 0 0 19.9333
1 2 97.5 6 0 -1 4 0 0 0 99 0 0 8.54506
1 2 97.5 7 0 -1 4 0 0 0 99 0 0 3.36859
1 2 97.5 8 0 -1 4 0 0 0 99 0 0 3.36859
t 1 97.5 -3 1 1 0 0 0 0 -2
_00Tenor
1 2 97.5 1 0 0 4 0 0 -2
1 2 97.5 8 0 0 4 0 0 -2
1 2 97.5 104 0 1 4 0 0 -1.66
1 1 170 9 0 -1 4 0 0 0 99 0 0 3.50663
1 1 170 10 0 -1 4 0 0 0 99 0 0 7.02663
1 1 170 11 0 -1 4 0 0 0 99 0 0 15.24
1 1 170 12 0 -1 4 0 0 0 99 0 0 12.8933
1 2 170 1 0 -1 4 0 0 0 99 0 0 19.9333
1 2 170 2 0 -1 4 0 0 0 99 0 0 8.19997
1 2 170 3 0 -1 4 0 0 0 99 0 0 17.5866
1 2 170 4 0 -1 4 0 0 0 99 0 0 9.3733
1 2 170 4 0 -1 4 0 0 0 99 0 0 3.50663
1 2 170 5 0 -1 4 0 0 0 99 0 0 17.5866
1 2 170 6 0 -1 4 0 0 0 99 0 0 5.8533
t 1 170 -3 1 1 0 0 0 0 -2
_00Bassus
1 1 170 9 0 0 4 0 0 -2
1 2 170 6 0 0 4 0 0 -2
1 2 170 102 0 1 4 0 0 -1.66
craigsapp commented 2 years ago

Send me your email to craigsapp at gmail.com and I will email some documentation.

The PMX is the data format for the SCORE notation editor (SCORE files are binary but there is a command in SCORE called PMX which outputs the data to an ASCII file). PMX means "Parameter MatriX", since it is like a 2D array of numbers (although the second dimension does not have a fixed length). Each line represents a particular object type, with the first number on the line indicating the object type. 1 means a note:

1 2 97.5 1 0 0 4 0 0 -2

I teach SCORE for two weeks each year in my class at Stanford, so there is some more detailed information about SCORE and PMX data: https://wiki.ccarh.org/wiki/Music_253/CS_275a_Winter_2022_Syllabus#week5

Here is a cheat sheet for the meaning of note parameters: https://wiki.ccarh.org/wiki/SCORE_note_parameters PDF version: https://wiki.ccarh.org/images/f/fa/Code1.pdf

I have a C++ SCORE data parser: https://github.com/craigsapp/scorelib

And here is an example score + audio alignment that was created from PMX data: https://www.ccarh.org/beethoven/op131/mvmt4