Continuous View: Volta changes Tempo of Playback

• Nov 12, 2018 - 22:18
Reported version
3.0
Priority
P0 - Critical
Type
Functional
Frequency
Once
Severity
S3 - Major
Reproducibility
Always
Status
closed
Regression
Yes
Workaround
No
Project

Playing the append score we start with the indicated temp of 200 bpm, but starting with the second volta the tempo drops to 120 bpm. When we remove the first voltas all is played at 200 bpm.

Score, mp3 and snapshot of score attached.

Attachment Size
TempoProblem.mscz 8.37 KB
TempoProblem.png 17.73 KB

Comments

I tried using the latest nightly, OS: Windows 10 (10.0), Arch.: x86_64, MuseScore version (64-bit): 3.0.0, revision: cc16e73 but it keeps crashing when I do anything but start playing. What I did find was that as written, the tempo changed from 200 to 120 when it got to volta 2. I couldn't delete volta 1 without a crash, but the tempo was 200 in it.

Sorry for this badly written issue. I was tired, when I wrote it.

The score was saved with a nightly build from 2018-11-12. (I am not at my MuseScore computer, I can not tell the exact version.)

Some words about the history of this score (which is stripped down from a bigger test score I started last week):
* When I started writing I set the tempo to 200 bpm and this perfectly work until Saturday
* On Saturday I have set the tempo to 100 bpm to check some chords. After setting the tempo back to 200 bpm the described problem arised.
* To be sure to not report a already fixed bug, I started yesterday a new session and imported my daily MusicXML backup. The resulting score was fine, the tempo was 200 bpm for the complete score.
* After this I restored the state before the MusicXML export (set musical font to MuseJazz, set double barline distance to a reasonable value, set some text styles to MusicJazzText and added some bar repeats to the drum set). After this I did not test again (sigh...), but added more music to the score.
* Later I heard, that the problem was there again and created this excerpt.

If no one find the reason for this problem today, I will try to recreate the score later to see, after which step the problem occurs.

Just installed latest nightly build (OS: Windows 7 SP 1 (6.1), Arch.: x86_64, MuseScore version (64-bit): 3.0.0, revision: cc16e73) on a computer, which never has seen MuseScore before :-)

Problem still there.

Recreated the problem score with the newest nightly build (OS: Windows 7 SP 1 (6.1), Arch.: x86_64, MuseScore version (64-bit): 3.0.0, revision: ef48b60).

Please load the append score TempoProblem 6.mscz and play it: all fine. Change the view to Continuous View and play it again: now it slows down in volta 2.

Attachment Size
TempoProblem 6.mscz 8.89 KB

And an even easier way:

Import the appended MusicXML file TempoProblem.mxl and play it: all fine. Switch to Continuous View and play it again: now it slows down in volta 2.

This means, we have nothing special hidden in the score which causes the problem. Also: No swing, no MuseJazz font, no style changes.

Attachment Size
TempoProblem.mxl 2.25 KB
Title Volta changes Tempo of Playback Continuous View: Volta changes Tempo of Playback

Just retested again. This problem still exists and can be constructed from the scratch:

  • New Score (treble clef template) with tempo 240 bpm
  • Write some notes in three bars
  • Add a repeat for the first two bars
  • Create a volta for bar 2 and a volta for bar 3
  • Switch to Continuous View
  • Play

As this seem to be a problem of finding the right tempo again after the volta in Continuous View, I renamed the issue.

Finally I found the time to look at the code and to start a debugging session. This left my quite confused :-)

When my example is loaded, we see in Page View:
* We have two Score::collectSystem() calls. (Why, I see only one system?!)
* The first Score::collectSystem() calls Score::setTempo() with 200 bpm (i.e. tempo=3.33333)
* The second Score::collectSystem() calls processLines(), which calls Ms::Volta::layoutSystem(), which calls Ms::Volta::setTempo(). This (correctly) fetches the tempo of the first bar (200 pbm) and calls Score::setTempo() with 200 bpm.

In Continuous View we see:
* We have Score::layoutLinear() call, which calls LayoutContext::layoutLinear()
* This call first processLines() (not the same as in Page View :-( ), which which calls Ms::Volta::layoutSystem(), which calls Ms::Volta::setTempo(). This takes the initial value of 120 bpm (tempo=2.0) and calls Score::setTempo() with 120 bpm.
* Than it calls directly Score::setTempo() with 200 bpm (i.e. tempo=3.33333).
* This means in Continuous View we have the wrong sequence.

I don't understand, what is happening. Can someone explain, why the Continuous View is implemented in a complete different way? And why do we have the Volta first and then the first bar? I am completely lost in the software design of the layout...

Edit: I see two systems in Page View, I was blind...

The problem in the Continuous View may be caused by the fact that in LayoutContext::layoutLinear() we see first layout the spanner segments and then the TempoText:

  //
  //    layout SpannerSegments for current system
  //

  if (etick > stick) {    // ignore vbox
        auto spanners = score->spannerMap().findOverlapping(stick, etick);

        std::vector ottavas;
        std::vector spanner;
        std::vector pedal;

        for (auto interval : spanners) {
              Spanner* sp = interval.value;
              if (sp->tick() < etick && sp->tick2() > stick) {
                    if (sp->isOttava())
                          ottavas.push_back(sp);
                    else if (sp->isPedal())
                          pedal.push_back(sp);
                    else if (!sp->isSlur())             // slurs are already handled
                          spanner.push_back(sp);
                    }
              }
        processLines(system, ottavas, false);
        processLines(system, pedal, true);
        processLines(system, spanner, false); // <-- here we call Volta::setTempo()

        //
        // vertical align volta segments
        //
        std::vector voltaSegments;
        for (SpannerSegment* ss : system->spannerSegments()) {
              if (ss->isVoltaSegment())
                   voltaSegments.push_back(ss);
             }
        if (voltaSegments.size() > 1) {
              qreal y = 0;
              for (SpannerSegment* ss : voltaSegments)
                    y = qMin(y, ss->offset().y());
              for (SpannerSegment* ss : voltaSegments)
                    ss->ryoffset() = y;
              }
        for (Spanner* sp : score->unmanagedSpanners()) {
              if (sp->tick() >= etick || sp->tick2() < stick)
                    continue;
              sp->layout();
              }
        }

  //
  // TempoText, Fermata
  //

  for (MeasureBase* mb : system->measures()) {
        if (!mb->isMeasure())
              continue;
        SegmentType st = SegmentType::ChordRest;
        Measure* m = toMeasure(mb);
        for (Segment* s = m->first(st); s; s = s->next(st)) {
              for (Element* e : s->annotations()) {
                    if (e->isTempoText()) {
                          TempoText* tt = toTempoText(e);
                          if (score->isMaster())
                                score->setTempo(tt->segment(), tt->tempo());  // <-- her we set the tempo for the first bar, which is referenced by Volta::setTempo()
                          tt->layout();
                          }
                    else if (e->isFermata())
                          e->layout();
                    }
              }
        }

Wow, this is really excellent analysis, I just wanted to commend you on it! I'm not familiar with this part of the code myself but will make sure those who are take a look.

The analysis was not so good, as the problem is not only in Continuous view :-)

Looking at my original score and at the score of https://musescore.org/en/node/279320, we see, that the problem can be also seen in Page View, when Tempo Text and Volta are on the same system. The reason seems to be, that the same wrong sequence is used in Page View (but is masked if Tempo Text and Volta on different systems).

I would try a PR myself, but I'm still looking for permission by my employer :-(

Not sure what your employer has got do do with this, as long as you do it in your spare time? (And you're not working for Sibelius, Finale, Capella...)

Quote from the CLA:

If you are employed as a software engineer, or if your employer is in the business of developing software, or otherwise may claim rights in the Contributions, please provide information about your employer's policy on contributing to open source projects, including the name of the supervisor to contact in connection with such contributions.

I'm pretty sure this only applies if you contribute as part of your job, not to you as a private person after hours.
Well, my interpretation, I didn't ask my employer for sure... and won't (never check for error conditions you're not prepared to handle ;-))

I know though that some of my employer's staff members do contribute to OpenSource (e.g. Samba, various Linux printer drivers) and as part of their job (and with permission then, of course, at least I assume so).

Status PR created fixed

Fixed in branch master, commit e3d1051c25

fix #278153: Moved layout of voltas behind Tempo Text: Voltas set the right tempo now, as they now reference the correct tempo set by the tempo text.

Also corrected testVoltaTemp.