Pedal segment starting on same note where previous pedal segment ends does not continue pedal playback

• Sep 13, 2014 - 06:43
Type
Functional
Severity
S4 - Minor
Status
closed
Project

Steps to reproduce:
1. Create a score with a piano instrument and some insert a few measures of notes to pedal (use 64th notes for easy testing)
2. Place a pedal segment under a section of the notes.
3. Place a connecting pedal segment that starts on the same note where the previous marking ends.
4. Play back the score.

Expected result: Piano notes contained in the first segment ring, then piano notes contained in the second segment ring.

Actual result: Only the piano notes in the first segment ring.

Using Nightly 1479442 on Windows 8.1

pedal-segment.png

I think adjacent segments are designed to start and end at a single note so that a continuous Pedal line can be drawn, as in the picture. It's worth noting, however, that the following "disconnected" pedal line produces the correct playback.

pedal-segment-wrong.png

My gut feeling is that the pedal-on/pedal-off events are in the wrong order at the point of change, so making a segment end before the start of the following segment, as in the second image, forces these events to be in the right order.

Attachment Size
pedal-segment.png 35.47 KB
pedal-segment-wrong.png 35.58 KB

Comments

Confirmed. Well, the behavior is confirmed, and I'm betting you are right about the cause :-). But FWIW, there were also changes shortly before Beta in how pedal and other lines were stored internally, so the problem could actually be there and not in the playback code per se.

It is indeed a problem with the timing of on- and off-pedal events. In the first example, the first two pedal spanners are actually a quarter note longer than they should be, because they subtend an extra quarter note. The off-time of the first pedal segment is therefore AFTER the on-time of the second pedal segment, causing the pedal to end prematurely (immediately after the extra note ends).

However, the solution is not as simple as discarding the extra note length, because the third pedal segment in this example requires its last note to be included.

I propose the following solution: Assume pedal segments include all notes that the segment covers (current implementation). When adding a new segment's pedal-on and pedal-off events, check that the channel's previous pedal-off-time is less than the new segment's pedal-on-time, and adjust if necessary.

In this example, Segment 1's Pedal-On is at 1920 (start of Measure 2), and Pedal-Off is 2400 ticks later (one measure + one quarter note), at 4320. Segment 2's Pedal-On is at 3840, so the solution would be to modify Segment 1's Pedal-Off to be at 3839 instead of 4320.

If I am understanding correctly, the first pedal segment has a tick count that *includes* the note it appears below. This is, I guess, the way we defined things to work for other spanners, since they are designed to actually include the final note, and then the layout decides how to draw this. And given how we draw pedal lines, this makes sense for pedal lines that truly do *end* on a note, since they do indeed need to keep the pedal on until the end of the note. And any change to this would require revisiting the layout code, which I'd like to avoid if possible.

But as you have discovered, this scheme doesn't make sense for pedal segments that represent pedal changes - they need to end just *before* the note. Actually, that's not precisely correct - what should actually happen is that the pedal change happen a tick or two *after* the note on event. That's how the pedal change is normally interpreted by a pianist - it happens just *after* the note below which it is rendered.

It seems the right place to manage this is in renderMidi, as opposed to trying to manage it within the pedal code itself. That is, I would propose we continue to store pedal events as we already are, but have renderMidi detect these overlaps and handle them appropriately. Not sure if that is what you are suggesting or if you were literally talking about doing the magic on the creation of the pedal line itself. I think that would be more problematic.

So in renderMidi, when we are creating the pedal events, we'd check for overlap, and when we see one, we would do something like the following:

t = start tick as recorded in second pedal line
set tick of pedal off event for first segment to t + 1
set tick of pedal on event for second segment to t + 2

I assume this means tracking state in some way we aren't currently.

Precisely - I actually compiled MuseScore myself last night and stepped through the code, and concluded the problem and solution were in rendermidi.cpp.

Now that the layout code does a simple test for how the line ends - extending for full duration of note if it ends with non-angled hook, aligning with note otherwise - it could possibly make sense to simplify the playback code to use the same heuristic. Not only would it be less code, but also more consistent with layout. Instead of an checking for other pedal segments on same channel, it would just a be a very straightforward check on the segment itself. Pedal segments starting with angled hooks would have start time adjusted to t + 2, pedal segments ending with angled hooks would have their end time adjusted to t + 1. All others unchanged from current.