Crash when playing twice this file with metronome on

• Mar 15, 2013 - 11:42
Type
Functional
Severity
S2 - Critical
Status
closed
Project

Steps:
1- Open attached file;
2- Toggle metronome ON;
3- Press play;
4- After the first play has finished, press play again -> crash.

MuseScore Nightly build rev 05977b2
Windows XP Professional SP3

Note:
- If the metronome is off, these steps do not bring to a crash,
- If notes are added to the final measure (which now contains a full measure rest), these steps do not bring to a crash.

Is it something related only to my pc environment?

Attachment Size
test_corona2.mscz 1.88 KB

Comments

Additional notes:

-1a- It crashes if play is clicked right after the end of the first playback. If it is pressed a few seconds after the end, there is no crash at the moment, but the first metronome tick becomes a sort of squeaky noise and random crashes appear, expecially when closing the score and/or quitting the application.

-2a- If the last beat of the final measure is a 4th note instead of a rest, it does not crash and I do not observe the behavior of point -1a-. The same if the last beat is an 8th, 16th or 32nd note followed by the remaining rests needed to complete the beat (for example, in the 16th note case: 16th note, 16th rest, 8th rest).
If the last beat is a 64th or 128th note followed by rests, it crashes if play is pressed right after the end of the first playback, or it produces a squeaky noise for the first metronome tick as point -1a-, with associated random crashes when closing/quitting.

Just a wild guess: could it be a problem with the final metronome tick (i.e. the one in the last beat) which is somehow "clipped" during playback and creates problems in sending midi events to the synthetizer?
Unfortunately, I am not able to pin the lines where the crash happens, also because of the fact (point -1a-) that it depends on how much time passes between the end of the first playback and the beginning of the second playback.

My observations using 667cd5c on Ubuntu 12.04

Playing back your file crashes eventually. Sometimes I have to hit play more than 20 times, but it finally does crash.
It also does not depend on the metronome being on or off here.

It mostly crashes after beat 3 of measure 2, but once also crashed after beat 3 of measure 1.

I think I found where the problem is.
I reproduced the bug while running mscore under first Dr.Memory and then Application Verifier.
They both found just after pressing "play" the second time (i.e. step 4) a "first chance access violation" at line 560 of mscore/seq.cpp, inside Seq::metronome:
*p++ += v;
Indeed, p, which is the (output) buffer, seems to be not long enough and *p++ is not allocated memory (by using gdb, it cannot access the value of *p++ when Application Verifier is on). It seems that when I press play the second time, part of the last metronome click is still in queue to be played.
Probably the problem lies in the way metronome events are inserted at line 876 of libmscore/rendermidi.cpp inside Score::renderMidi:
events->insert(std::pair(tick, event));
This inserts ONLY the "on" event. The "off" event for metronome clicks is not inserted. Therefore, when the very last beat of the last measure is a rest, the endTick is set at the "on" event of the metronome click, at lines 733-737 of mscore/seq.cpp (inside Seq::collectEvents):
if (!events.empty()) {
auto e = events.cend();
--e;
endTick = e->first;
}
But the last metronome click at this endTick (="on" tick of metronome click) has not actually ended yet.
If the last beat of the last measure is a note (longer or equal to 1/32th note, followed by trailing rests or notes), such access violation disappears, because the endTick is set at the "off" tick of the last note (equal to its position + its length minus 1 tick), inserted in the events' list at line 120 of mscore/rendermidi.cpp (inside playNote function: events->insert(std::pair(offTime, ev));).

Does it make sense?

[ Additional observations (I kown little about C and C++, I may be wrong in these following observations)
The buffer p (=buffer) is a pointer to floats, if I understand correctly.
In lines 548 and 559 of mscore/seq.cpp the variable v is a qreal because metronomeVolume is a qreal (line 119 of mscore/seq.h: qreal metronomeVolume; and initialized at line 114 of mscore/seq.cpp: metronomeVolume = 0.3;).
In my environment sizeof(*p), sizeof(tack[idx]), sizeof(tick[idx]) give 4, while sizeof(v), sizeof(metronomeVolume) give 8.
There is also line 683 of mscore/seq.cpp: qreal val = *p; (and line 685 *p++ = val;)
I am wondering if these lines are correct; or maybe the fact that in all these cases it is *p++ and not *p which is set equal to a qreal value adjusts the things?
Please forgive me if these questions are silly: coming from Fortran, I still have problems with the ++ and -- operators and C memory allocation. ]