Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation about spine operator *v #7

Open
davidrizo opened this issue Apr 15, 2020 · 3 comments
Open

Documentation about spine operator *v #7

davidrizo opened this issue Apr 15, 2020 · 3 comments
Labels

Comments

@davidrizo
Copy link
Collaborator

In Partial voices/layers, when two spines are to be merged into one spine the *v operator is used on both spines:

**kern
*M4/4
=1
*^
2cc	4a
.	4g
*v	*v
4f
4e
=2
*^
2cc	4a
.	4g
2ryy	4f
.	4e
*v	*v
=
*-

image

In Multiple staves, the top staff spines are merged into just one using the same method, while the bottom staff is maintained without being split or merged. This is perfect.

**kern	**kern
*M4/4	*M4/4
=1	=1
*	*^
1E	2cc	4a
.	.	4g
*	*v	*v
.	4f
.	4e
=2	=2
*	*^
1E	2cc	4a
.	.	4g
.	2ryy	4f
.	.	4e
*	*v	*v
=	=
*-	*-

image

However, for getting the example below the encoding is a bit different.
image

Given the examples in the documentation, when two splines must be merged into one, the *v operator must be used at the end of both spines. Then, the expected encoding should be:

**kern	**kern
*staff2	*staff1
*clefF4	*clefG2
*k[f#c#]	*k[f#c#]
*D:	*D:
*M2/4	*M2/4
*^	*^
G2	BB2	g8L	d4
.	.	a8J	.
.	.	b8L	e4
.	.	cc#8J	.
=	=	=	=
D2	AA2	dd2	f#2
*v	*v	*v	*v
=	=
*-	*-

However, VHV complains because the number of tokens in the last bar line record do not match.
To make it work, I've had to remove the left spine merge operator :

....
D2	AA2	dd2	f#2
*	*v	*v	*v
=	=
*-	*-
@craigsapp
Copy link
Member

Given the examples in the documentation, when two splines must be merged into one, the *v operator must be used at the end of both spines. Then, the expected encoding should be:

Yes, that is close. But the problem with this line:

*v	*v	*v	*v
*

is that it means to merge all spines into a single one. When you do this:

....
D2	AA2	dd2	f#2
*	*v	*v	*v
=	=
*-	*-

the right three are merged into the second spine below. The problem is that the original spines were not restored (2:2 goes to 1:3). Technically this allowed in Humdrum, although I avoid this since it is difficult to distinguish from a bug in the data.

The current solution to this is to do each merge on a separate line:

**kern	**kern
*staff2	*staff1
*clefF4	*clefG2
*k[f#c#]	*k[f#c#]
*D:	*D:
*M2/4	*M2/4
*^	*^
G2	BB2	g8L	d4
.	.	a8J	.
.	.	b8L	e4
.	.	cc#8J	.
=	=	=	=
D2	AA2	dd2	f#2
*	*	*v	*v
*v	*v	*
=	=
*-	*-

Screen Shot 2020-04-15 at 08 32 23

Either merge can happen before the other, although collapsing the right-most subspine group first make the visual display of the data a little more complex:

*v      *v      *       *
*       *v      *v   
*       *

I do not like this, and I would like to implement a new spine manipulator *V that would allow merging adjacent spines groups on a single line, where the capitalization indicate a new merge group is starting:

*v	*v	*V	*v
*       *

But I have not yet implemented this system (and it would not be backward compatible with the original Humdrum Toolkit). This would improve readability and data processing in certain cases, but would also cause complications when adding/removing spines from a score (where the v/V states may need to change).

In my parser, I could also disallow merging across original spines, then the original case would be as you expected:

*v	*v	*v	*v
*       *

Coming from above in the data, I keep track of which primary spine a token belongs two. If I see such a merger where two adjacent tokens are from a different primary spine (which I call a track to avoid confusion between spine/subspine terms), then I could implicitly segment the merges into two separate groups. However, this would make the data incompatible with the original Humdrum Toolkit tools, so I have avoided doing that.


I changed the documentation example to include more complex spining:

Screen Shot 2020-04-15 at 09 24 21

**kern	**kern
*M4/4	*M4/4
=1	=1
*	*^
1E	1cc	4a
.	.	4g
*	*	*^
.	.	4f/	2c\
.	.	4e/	.
*	*v	*v	*v
=2	=2
*^	*^
*	*	*	*^
1E	4r	4r	2gg	4d/
.	2EE	2.ccc	.	4g
.	.	.	2ryy	4f
.	8FFL	.	.	4e
.	8GGJ	.	.	.
*	*	*v	*v	*v
*v	*v	*
=2	=2
1AA;	1f;
==	==
*-	*-

And added a paragraph describing the complications:

Note that when the subspines for adjacent staves merge at the same
time (at the end of measure 2), then the merges must be staggered
for grouping clarity. Also when a spine needs to expand from one
to three voices, there must be two *^ expansions (the first to
go from one to two subspines, and the second to go from two to three
spines). Also note the use of 2ryy, which is used to delay merging
of the spines until the end of the measure (otherwise the two right
subspines could merge together before merging with the first subspine
for the staff at the end of the measure). Also note that subspines
should not be ended before the full duration of the last note in
the subspine (so the first two subspines in the top staff in measure
2 can not merge half-way through the measure since the note in
the first subspine has not yet finished sounding).


You are writing the duration after pitch in **kern tokens, such as D2 for a half note on the D below middle C. This is allowed in **kern data, so there is not real problem, but it makes the data a little more difficult to read, because scientific pitch will use a number after the pitch to indicate the octave. For example C4 in scientific pitch notation means middle C. If you put the rhythm first, such as 2D, then there is less confusion when viewing the notes out of context. Also, this would allow rhythm and scientific pitch to be mixed easily, such as 2C4 which might mean a half note middle C.

So you can keep putting the rhythm after the pitch without any problems, but there is a "canonical ordering" for **kern data in the documentation somewhere that says that rhythm-pitch is preferred over pitch-rhythm.

craigsapp added a commit that referenced this issue Apr 15, 2020
@davidrizo
Copy link
Collaborator Author

Hi,
the following case is just a lab experiment, but can be a good example to check the correct collapsing of spines.

In this case there are two main spines that are splitted. VHV just works when all the spines join into one spine..
Shouldn't be at least the three main spines maintained?

**kern	**kern	**kern
*	*^	*
1r	1A	1AA	1a
*	*	*^	*
2r	2A	2AA	2AA#	2a
*^	*^	*^	*^	*^
4r	4r	4A	4A	4AA	4AA	4AA#	4AA#	4a	4a
*v	*v	*v	*v	*v	*v	*v	*v	*v	*v
8r
*-

I was expecting the last row to have three spines instead the 8r alone.
Thanks!!

@davidrizo davidrizo reopened this May 21, 2024
@craigsapp
Copy link
Member

craigsapp commented May 21, 2024

In the original Humdrum Toolkit, all adjacent *v merge into a single spine. The proper way is to place merges on separate lines when adjacent *v merge into separate spines:

**kern	**kern	**kern
*	*^	*
1r	1A	1AA	1a
*	*	*^	*
2r	2A	2AA	2AA#	2a
*^	*^	*^	*^	*^
4r	4r	4A	4A	4AA	4AA	4AA#	4AA#	4a	4a
*	*	*	*	*	*	*	*	*v	*v
*	*	*v	*v	*v	*v	*v	*v	*
*v	*v	*	*
8r	8r	8r
*-	*-	*-

And the following is probably legal with the original Humdrum Toolkit tools since the *v of spines 1 and 3 are not adjacent:

**kern	**kern	**kern
*	*^	*
1r	1A	1AA	1a
*	*	*^	*
2r	2A	2AA	2AA#	2a
*^	*^	*^	*^	*^
4r	4r	4A	4A	4AA	4AA	4AA#	4AA#	4a	4a
*	*	*v	*v	*v	*v	*v	*v	*	*
*v	*v	*	*v	*v
8r	8r	8r
*-	*-	*-

This requirement is probably due to the original Humdrum Toolkit tools not having a centralized parser and thus a low complexity method of requiring separate merge lines. In Humdrum Extras and humlib, there is a single parser thanks to object oriented programming. 😉

I don't particularly like this and agree with your expectation. I have been thinking of implementing in humlib (which are used to create filters in VHV) what you expect: prevent subspines from merging with other subspines unless they have the same originating spine:

**kern	**kern	**kern
*	*^	*
1r	1A	1AA	1a
*	*	*^	*
2r	2A	2AA	2AA#	2a
*^	*^	*^	*^	*^
4r	4r	4A	4A	4AA	4AA	4AA#	4AA#	4a	4a
*v	*v	*v	*v	*v	*v	*v	*v	*v	*v
8r	8r	8r
*-	*-	*-

An alternate idea would be to create *V for separating subspines from separate origins:

**kern	**kern	**kern
*	*^	*
1r	1A	1AA	1a
*	*	*^	*
2r	2A	2AA	2AA#	2a
*^	*^	*^	*^	*^
4r	4r	4A	4A	4AA	4AA	4AA#	4AA#	4a	4a
*v	*v	*V	*v	*v	*v	*v	*v	*V	*v
8r	8r	8r
*-	*-	*-

where *V prevents merging with any *v to its left.

Both would be incompatible with the original Humdrum Tools, so I have not done it yet. But there could be a converter between the two (or three) systems (the first method is probably better than the *V method).


I have a tool in Humdrum Extras to examine the spine pathes, called spinetrace:

spinetrace file.krn

Results with your example:

**kern	**kern	**kern
*	*^	*
1	(2)a	(2)b	3
*	*	*^	*
1	(2)a	((2)b)a	((2)b)b	3
*^	*^	*^	*^	*^
(1)a	(1)b	((2)a)a	((2)a)b	(((2)b)a)a	(((2)b)a)b	(((2)b)b)a	(((2)b)b)b	(3)a	(3)b
*v	*v	*v	*v	*v	*v	*v	*v	*v	*v
3
*-

(The Humdrum Extras parser gets confused with the mass merge and assigns the last token to originate from spine 3 (rather than 1 and 2 and 3).

In humlib, there is a tool called spinetrace2 which behaves slightly different (it uses a different Humdrum parser), but it also loses spine information if the primary spines are merged, with the last token assigned to primary spine 1.

**spine	**spine	**spine
*	*^	*
1	(2)a	(2)b	3
*	*	*^	*
1	(2)a	((2)b)a	((2)b)b	3
*^	*^	*^	*^	*^
(1)a	(1)b	((2)a)a	((2)a)b	(((2)b)a)a	(((2)b)a)b	(((2)b)b)a	(((2)b)b)b	(3)a	(3)b
*v	*v	*v	*v	*v	*v	*v	*v	*v	*v
1
*-

Also in humlib, the last token would ideally have a spinetrace of 1 2 3 rather than 1, although I avoid merging subspines from different originating spines, so I have not bothered to refine the spine tracing analysis so far. (I use spinetrace to track down spine split/merge problems.)

Notice that I keep track of the originating spine, so parsing as

*v	*v	*v	*v	*v	*v	*v	*v	*v	*v
1	2	3

would be fairly easy to implement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants