Hairpin attached to note other than in voice 1 in score appears on wrong part

• Nov 21, 2019 - 18:17
Reported version
P1 - High
S2 - Critical
  1. Create a score with multiple instruments
  2. Enter notes in voice 2 in one staff. (It doesn't matter if voice 1 has notes or rests)
  3. Select a note or range of notes in voice 2 only (use the selection filter to ensure only voice 2 notes are selected).
  4. Add a hairpin using the "<" shortcut.
  5. Create parts.

Result: The hairpin is shown in the same measure but on the part associated with the stave below the stave where the hairpin was entered. If the hairpin is entered in the bottom stave it is missing completely.

See attached example and compare the location of the hairpins in the score and in the parts.

Hairpin placement differs in score and parts.mscz

a) the problem does not occur if the hairpin is entered by double clicking the palette item.
b) the problem also occurs with a grand staff. A hairpin attached to voice 2 in the top stave appears beneath the bottom stave when a part is generated. A hairpin attached to voice 2 on the bottom stave is missing if the grand staff is the only or last instrument in the score.


Title Hairpin attached to note in voice 2 in score appears on wrong part Hairpin attached to note other than in voice 1 in score appears on wrong part

Further experimentation shows that this problem occurs if the hairpin is attached to voice 3 or 4 as well as voice 2.

Also, the problem only occurs during part generation. A hairpin added to a score when parts already exist shows up in the correct place.

Priority P1 - High

I hadn't noticed this when submitted, but it's extremely serious. A hairpin on one instrument appears in the part for another instrument entirely! My guess form the description of the symptoms is that we aren't managing the track of the hairpin itself versus its segments in the case when added by keyboard shortcut.

I note that attaching hairpins to dynamics in voices other than 1 is mentioned in this How To This will fall foul of the bug described here which is still live in 3.5.0.

Perhaps the priority can be bumped to pre-empt the likely increase in users who encounter it when following the How To.

The How to could be clarified. You can enter the example hairpins on the whole note in voice 1, then use shift+arrows to shorten them to the duration indicated by the invisible notes and they would remain in voice 1 in this example.

In reply to by mike320

In that case the whole note would need to go in voice 2, 3, or 4 in the example.

But rather than tweaking the How To to avoid the bug, it would be much better if the bug wasn't there.

I note (not complaining, just noting) that the bug has been given a priority of p1-High which, according to "How to write a good bug report", should mean "The issue should be fixed/implemented in the next release. These issues stop the release." and yet here we are after 3.4 release and 3.5 release and the bug still is there.

Workaround No Yes

Regarding prioritization, indeed, in theory it would work as advertised, but that's more a general goal to shot for than a strct rules. In practice, bug fixes in open source projects depend on what gets the most attention in the forums and what bothers any individual developer the most.

Regarding the voices-to-parts feature - this shouldn't be relevant, but it could well be that the bug is because somehow that code is being triggered inappropriately.

In reply to by Marc Sabatella

"In practice, bug fixes in open source projects depend on what gets the most attention in the forums and what bothers any individual developer the most."

Understood. Not (yet) being a developer myself, I do what I can to keep what bugs me in view in the hope that it attracts the attention of a similar minded active developer. Still waiting - patiently.

I'm investigating. It appears you are correct that the bug has to do with the voice-to-parts feature. The errant code was introduced in 2016 as part of that feature, and the comment on particular lines in question reads "always export these spanners to first voice of the destination staff". But the code is not doing this correctly. It should be a trivial fix to make the code match that comment.

But, I'm pretty sure that's not what we really want either. This means in the basic case of a staff with two voices (but not using voices-to-parts) and a hairpin in voice 2, it will end up in voice 1 in the part, and probably this will lead the start/end points to not be maintained properly.

I assume the goal here was to make sure that if a staff is using voices-to-parts, that a hairpin in voice 2 ends up in both parts. I'm not sure that actually makes sense. Would be good to get some feedback on that. It seems if the hairpin in voice 2, it may have been specifically meant not to apply to both. So maybe only hairpins in voice 1 should apply to both parts. Even then, it will probably not work if the parts have different rhythms and so the start/end points don't actually exist in the other voice.

Anyhow, it's easy enough to see what the problem is, and should be straightforward to change the code to do whatever we want instead, but defining what we want in this voices-to-parts is maybe trickier.

This is my general idea of hairpins and dynamics in specific voices.

If it's attached to other than voice 1 it belongs to that voice.

If it's in voice 1 and below the staff, it belongs to all voices.

If it's in voice 1 above the staff it belongs only to voice 1.

Interesting, I wouldn't have considered placement to be relevant, but I can see why it might be. The code handling dynamics and the code handling hairpins are totally separate (annotations vs spanners), but in principle the same heuristic could be applied to both. But, I think that probably deserves more discussion, on forum, input from @oktophonie, etc.

Meanwhile, I propose hairpins in voice 2 appear only in that part (but moved to voice 1 just as the notes are), and hairpins in voice 1 will apply to all voices, and if you don't want it in the voice 2 part, you can make it invisible.

Hmm, another wrinkle: the code involved here is just when generating parts. In the non voices-to-parts case, the right thing already happened when adding hairpins after the fact. In the voices-to-parts case, anything we decide about what the behavior should be should work the same in both cases.

Unfortunately, this gets a bit deeper into the voices-to-parts data structures than I am currently comfortable with. I may either just leave the voices-to-parts behavior as is for now and focus ion fixing the more basic case, or turn this over to someone who knows that code better.

Correcting the code to match the intent seems to be as easy as making this change. But I am not sure why hairpins are handled separately from other spanners. I wonder what (if anything) would go wrong if we were to remove the whole else if (s->isHairpin()) { ... } clause.

Well, it's almost a bug in itself that it "works" when using the palette - even though you have a voice 2 note selected, the hairpin is actually added in voice 1. That's why it "works", but then, there is no way to achieve the eventual goal of voice 2 hairpins staying with voice 2 when using voices-to-parts. So actually, it's the keyboard code that is working better - it adds the hairpin in the selected voice whereas the palette does not. The bug is in the code that copies the hairpin to the parts, there was a logic error causing a hairpin in voice 2 to be seen as actually belonging to the next staff. With that logic error, the bug here at hand is fixed.

Then, however,r we would need to decide how to handle all the various cases with voices-to-parts - cleaning up any remaining inconsistencies between adding hairpins before vs after generating parts, making the behavior consistent between adding by palette and keyboard, and deciding which parts generating from a single staff should get which hairpins. Probably worth someone submitting a separate issue for that and really looking at all the different cases, and as I said, getting feedback from others as well.

@mattmcclinch indeed, I already tried removing that whole hairpin special case, it works :-). So does the other change you proposed, which is what I tried first. The two solutions seem to have slightly different effects on voices-to-parts but I didn't really check very exhaustively.

In reply to by Marc Sabatella

It seems this problems is related to Inconsistent behaviour with dynamics when creating parts from voices (and issue #304456 : Inconsistent behaviour with dynamics and hairpins, when use parts from voices ).
There the problem was, if you use multiple voices, any dynamic should apply to all voices. However, when using voices-to-parts, any dynamic on voice 1 can apply to or voice 1, or to voice 2-4. If the other voices do have a dynamic it is clear which dynamic to use. But if there is only a dynamic on voice 1, there is no way of telling whether is voice 1 only or it should go to the other voices also, it depends whether you want to se voices-to-part or not.
A way to solve this was using the Dynamic range (Score would be better name) which is now used for play back.