Skip to content

Add metweight tool - #119

Open
WolfgangDrescher wants to merge 12 commits into
craigsapp:masterfrom
WolfgangDrescher:metweight
Open

Add metweight tool#119
WolfgangDrescher wants to merge 12 commits into
craigsapp:masterfrom
WolfgangDrescher:metweight

Conversation

@WolfgangDrescher

Copy link
Copy Markdown
Collaborator

I added a metweight tool that analyzes kern files with Tool_meter and creates a new spine for each selected voice (-k or -s) that outputs the meter weight of every token.

Generated data tokens are as follows:

Weight class Abbreviation Full word Number
strong "s" "strong" "1"
half-strong "hs" "half-strong" "2"
weak "w" "weak" "3"
unclassified "u" "unclassified" "4"

These options are available:

define("f|full=b",         "print full text labels (strong/half-strong/weak) instead of abbreviations");
define("i|integer=b",      "print integer rank labels (1/2/3) instead of abbreviations");
define("x|cdata=b",        "label the spine **cdata-metweight instead of **metweight");
define("k|kern-tracks=s",  "process only the specified kern spines");
define("s|spine|spines=s", "process only the specified spines");
define("n|null=b",         "always use the null token . for unclassified positions");

Example usage:

Command:

metweight -nx -k1,$ ./bach-370-chorales/kern/chor029.krn | myank -m 1-4 | ridxx -LG

Output:

**kern	**cdata-metweight	**kern	**kern	**kern	**cdata-metweight
*clefF4	*	*clefGv2	*clefG2	*clefG2	*
*k[f#]	*	*k[f#]	*k[f#]	*k[f#]	*
*G:	*	*G:	*G:	*G:	*
*M4/4	*	*M4/4	*M4/4	*M4/4	*
*met(c)	*	*met(c)	*met(c)	*met(c)	*
*MM100	*	*MM100	*MM100	*MM100	*
=1-	=1-	=1-	=1-	=1-	=1-
4G	s	4B	4d	4g	s
4F#	w	4A	4d	4a	w
4G	hs	[4G	4d	4b	hs
4D	w	8GL]	4d	4a	w
.	.	8F#J	.	.	.
=2	=2	=2	=2	=2	=2
4E	s	4G	8dL	4g	s
.	.	.	8c#J	.	.
8F#L	w	4A	4d	4f#	w
8GJ	.	.	.	.	.
4A	hs	8AL	4c#	4e	hs
.	.	8GJ	.	.	.
4D;	w	4F#;	4A;	4d;	w
=3	=3	=3	=3	=3	=3
4E	s	4B	4e	4g	s
4F#	w	4A	4d	4a	w
4G	hs	8GL	4d	4b	hs
.	.	8F#J	.	.	.
4AA	w	8EL	4a	4cc	w
.	.	8F#J	.	.	.
=4	=4	=4	=4	=4	=4
8BBL	s	4.G	4d	4b	s
8CJ	.	.	.	.	.
4D	w	.	4d	4a	w
.	.	8F#	.	.	.
2GG;	hs	2B;	2d;	2g;	hs
=	=	=	=	=	=
*-	*-	*-	*-	*-	*-

@craigsapp

craigsapp commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Metweight is a bit long, I have usd metpos (Metrical position) in the paste (humdrum extras).

Why are there two analysis spines? Ideally the analytic output:

Screenshot 2026-07-24 at 8 17 56 PM

Better is one, in the first spine. (displayed below the system).

Also it would be useful add a -c or --color option to color code the analyisis as demonstrated above.

Also it would be useful to add a -n or --numeric option to convert the categories to numbers: 0 would be the beat level, -1 is the half note -2 is the whole note, +1 is the eighth note.and so on (it is log_2(rhythm / 3), such as eigthth note: log_2(8/4) = log_2(2) = +1. whole note is (log_2(1/4) = -2.

for ternerary probably take the floor log_2. 12 → 8 = log_2(8/2) = +1. or log_2(12/4) = log_2(3) = +1.58 = floor(1.58) = 1.

Also it would be good to add a -b option to highlight only the beat level and higher of the music. (0 numeric and negative values).

Here is adding composite rhythm analysis:

Screenshot 2026-07-24 at 8 32 07 PM

Composite only:

Screenshot 2026-07-24 at 8 34 11 PM

@WolfgangDrescher

Copy link
Copy Markdown
Collaborator Author

Metweight is a bit long

Personally I don't mind the long name. But is this a good terminology? I am not a native speaker. metlev does something a bit different than my implementation (plus, its currently not running see #117)

I have usd metpos (Metrical position) in the paste (humdrum extras).

I could not get `metpos` running (I think it's AWK and not humextra). Click here to see bash stdout.

Command:

metpos ./bach-370-chorales/kern/chor029.krn

stdout:

!!!!SEGMENT: chor029.krn
!!!COM: Bach, Johann Sebastian
!!!CDT: 1685/02/21/-1750/07/28/
!!!OTL@@DE: Freu dich sehr, o meine Seele
!!!SCT: BWV 32/6
!!!PC#: 29
!!!AGN: chorale
**kern	**kern	**kern	**kern	**metpos
*ICvox	*ICvox	*ICvox	*ICvox	*
*Ibass	*Itenor	*Ialto	*Isoprn	*
*I"Bass	*I"Tenor	*I"Alto	*I"Soprano	*
*>[A,A,B]	*>[A,A,B]	*>[A,A,B]	*>[A,A,B]	*
*>norep[A,B]	*>norep[A,B]	*>norep[A,B]	*>norep[A,B]	*
*>A	*>A	*>A	*>A	*
*clefF4	*clefGv2	*clefG2	*clefG2	*
*k[f#]	*k[f#]	*k[f#]	*k[f#]	*
*G:	*G:	*G:	*G:	*
*M4/4	*M4/4	*M4/4	*M4/4	*M4/4
*M4/4	*M4/4	*M4/4	*M4/4	*M4/4
*M4/4	*M4/4	*M4/4	*M4/4	*M4/4
*M4/4	*M4/4	*M4/4	*M4/4	*M4/4
*met(c)	*met(c)	*met(c)	*met(c)	*
!!xywh-#24:169,0,2736,477
=1-	=1-	=1-	=1-	=1-
metpos: ERROR: Data record encountered prior to timebase definition at line 23.

Why are there two analysis spines?

This comes from the -k1,$ arg. I just used a random "complicated" metweight command to show some of the options available. The command produces a **metweight spine for each **kern spine. In my use case I need to be able to scan each voice for strong and weak beats to provide detailed search options for the Bach chorales corpus.

The output I actually need and would prefer looks like this:

metweight ./bach-370-chorales/kern/chor029.krn | myank -m 1-4 | ridxx -LG
**kern	**metweight	**kern	**metweight	**kern	**metweight	**kern	**metweight
*clefF4	*	*clefGv2	*	*clefG2	*	*clefG2	*
*k[f#]	*	*k[f#]	*	*k[f#]	*	*k[f#]	*
*G:	*	*G:	*	*G:	*	*G:	*
*M4/4	*	*M4/4	*	*M4/4	*	*M4/4	*
*met(c)	*	*met(c)	*	*met(c)	*	*met(c)	*
*MM100	*	*MM100	*	*MM100	*	*MM100	*
=1-	=1-	=1-	=1-	=1-	=1-	=1-	=1-
4G	s	4B	s	4d	s	4g	s
4F#	w	4A	w	4d	w	4a	w
4G	hs	[4G	hs	4d	hs	4b	hs
4D	w	8GL]	.	4d	w	4a	w
.	.	8F#J	u	.	.	.	.
=2	=2	=2	=2	=2	=2	=2	=2
4E	s	4G	s	8dL	s	4g	s
.	.	.	.	8c#J	u	.	.
8F#L	w	4A	w	4d	w	4f#	w
8GJ	u	.	.	.	.	.	.
4A	hs	8AL	hs	4c#	hs	4e	hs
.	.	8GJ	u	.	.	.	.
4D;	w	4F#;	w	4A;	w	4d;	w
=3	=3	=3	=3	=3	=3	=3	=3
4E	s	4B	s	4e	s	4g	s
4F#	w	4A	w	4d	w	4a	w
4G	hs	8GL	hs	4d	hs	4b	hs
.	.	8F#J	u	.	.	.	.
4AA	w	8EL	w	4a	w	4cc	w
.	.	8F#J	u	.	.	.	.
=4	=4	=4	=4	=4	=4	=4	=4
8BBL	s	4.G	s	4d	s	4b	s
8CJ	u	.	.	.	.	.	.
4D	w	.	.	4d	w	4a	w
.	.	8F#	u	.	.	.	.
2GG;	hs	2B;	hs	2d;	hs	2g;	hs
=:|!	=:|!	=:|!	=:|!	=:|!	=:|!	=:|!	=:|!
*-	*-	*-	*-	*-	*-	*-	*-

Better is one, in the first spine. (displayed below the system).

You can already do this with -k1/-s1.

Also it would be useful add a -c or --color option to color code the analyisis as demonstrated above.

This is a nice idea I have implemented it in 48a9216.

I have also implemented --composite in 8db83b4. Maybe I should remove it again and allow usage of metweight in combination with composite without having Tool_composite inside of Tool_metweight.

Also it would be useful to add a -n or --numeric option to convert the categories to numbers: 0 would be the beat level, -1 is the half note -2 is the whole note, +1 is the eighth note.and so on (it is log_2(rhythm / 3), such as eigthth note: log_2(8/4) = log_2(2) = +1. whole note is (log_2(1/4) = -2.

for ternerary probably take the floor log_2. 12 → 8 = log_2(8/2) = +1. or log_2(12/4) = log_2(3) = +1.58 = floor(1.58) = 1.

Also it would be good to add a -b option to highlight only the beat level and higher of the music. (0 numeric and negative values).

I will have to think about this in a bit more detail. For now I think the logic I need is slightly different, but I need to check out this approach.

Here is my kern file that I am using for debugging:
**kern
*M4/2
=
8gL
8g
8g
8gJ
8gL
8g
8g
8gJ
8gL
8g
8g
8gJ
8gL
8g
8g
8gJ
=||
*M3/2
8gL
8g
8g
8gJ
8gL
8g
8g
8gJ
8gL
8g
8g
8gJ
=||
*M2/2
8gL
8g
8g
8gJ
8gL
8g
8g
8gJ
=||
*M6/4
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
=||
*M4/4
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
=||
*M3/4
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
=||
*M2/4
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
=||
*M5/4
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
16gL
16g
16g
16gJ
=||
*M12/8
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
=||
*M9/8
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
=||
*M6/8
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
16gLL
16gJ
16gL
16gJ
16gL
16gJJ
=||
*M3/8
32gL
32g
32g
32gJ
32gL
32g
32g
32gJ
32gL
32g
32g
32gJ
==
*-

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants