From 2bd75bb3a71cfb3a293375089b9471ff8ead6f7b Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Thu, 10 Jan 2019 14:58:19 +0300 Subject: [PATCH] Fix fermata time stretch handling on partial re-layout --- libmscore/fraction.h | 4 +- libmscore/layout.cpp | 12 +- libmscore/score.cpp | 5 +- .../midi/testTimeStretchFermata-ref.mid | Bin 0 -> 377 bytes .../midi/testTimeStretchFermata.mscx | 340 ++++++++++++++++++ mtest/libmscore/midi/tst_midi.cpp | 43 ++- 6 files changed, 393 insertions(+), 11 deletions(-) create mode 100644 mtest/libmscore/midi/testTimeStretchFermata-ref.mid create mode 100644 mtest/libmscore/midi/testTimeStretchFermata.mscx diff --git a/libmscore/fraction.h b/libmscore/fraction.h index a49dd042c1..e9b786bd70 100644 --- a/libmscore/fraction.h +++ b/libmscore/fraction.h @@ -63,7 +63,6 @@ class Fraction { Fraction operator+(const Fraction& v) const { return Fraction(*this) += v; } Fraction operator-(const Fraction& v) const { return Fraction(*this) -= v; } Fraction operator*(const Fraction& v) const { return Fraction(*this) *= v; } - Fraction operator*(int v) const { return Fraction(*this) *= v; } Fraction operator/(const Fraction& v) const { return Fraction(*this) /= v; } Fraction operator/(int v) const { return Fraction(*this) /= v; } @@ -79,6 +78,9 @@ class Fraction { operator QVariant() const { return QVariant::fromValue(*this); } }; +inline Fraction operator*(const Fraction& f, int v) { return Fraction(f) *= v; } +inline Fraction operator*(int v, const Fraction& f) { return Fraction(f) *= v; } + #ifdef SCRIPT_INTERFACE //--------------------------------------------------------- diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index db938a7729..c5db99aa19 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -2657,6 +2657,11 @@ void Score::getNextMeasure(LayoutContext& lc) } measure->computeTicks(); + + // Reset tempo to set correct time stretch for fermata. + if (isMaster()) + resetTempoRange(measure->tick(), measure->endTick()); + for (Segment& segment : measure->segments()) { if (segment.isBreathType()) { qreal length = 0.0; @@ -2709,7 +2714,7 @@ void Score::getNextMeasure(LayoutContext& lc) if (e->isFermata()) stretch = qMax(stretch, toFermata(e)->timeStretch()); else if (e->isTempoText()) { - if (score()->isMaster()) { + if (isMaster()) { TempoText* tt = toTempoText(e); setTempo(tt->segment(), tt->tempo()); } @@ -4187,11 +4192,6 @@ void Score::doLayoutRange(int stick, int etick) lc.prevMeasure = 0; - // we need to reset tempo because fermata is setted - //inside getNextMeasure and it lead to twice timeStretch - if (isMaster()) - resetTempoRange(stick, etick); - getNextMeasure(lc); lc.curSystem = collectSystem(lc); diff --git a/libmscore/score.cpp b/libmscore/score.cpp index d9a8db1c33..28462c2fff 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -3315,11 +3315,12 @@ void Score::resetTempo() void Score::resetTempoRange(int tick1, int tick2) { + const bool zeroInRange = (tick1 <= 0 && tick2 > 0); tempomap()->clearRange(tick1, tick2); - if (tempomap()->empty()) + if (zeroInRange) tempomap()->setTempo(0, _defaultTempo); sigmap()->clearRange(tick1, tick2); - if (sigmap()->empty()) { + if (zeroInRange) { Measure* m = firstMeasure(); if (m) sigmap()->add(0, SigEvent(m->len(), m->timesig(), 0)); diff --git a/mtest/libmscore/midi/testTimeStretchFermata-ref.mid b/mtest/libmscore/midi/testTimeStretchFermata-ref.mid new file mode 100644 index 0000000000000000000000000000000000000000..769b71c24d6caaac9b97d698e33409b1ac0ed766 GIT binary patch literal 377 zcmeYb$w*;fU|?flWME``;2Tnu&A`Bz%%Vu30Z85tNRxCS)4yD~@swXrW$U<6WPj}y>E zp^79SYWpRDs(4IM^s-4cfbf + + 3.0.1 + 6d522ee + + + 0 + + + 480 + + 1 + 1 + 1 + 0 + + + + 2018-11-12 + + + + Linux + + + + + Treble + + + + stdNormal + + + Piano + + Piano + Pno. + Piano + 21 + 108 + 21 + 108 + keyboard.piano + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + Fluid + + + + + + 10 + + + Treble + + + + + + 4 + 4 + + + fermataAbove + 2 + + + quarter + + 69 + 17 + + + + fermataAbove + 3 + + + quarter + + 69 + 17 + + + + fermataAbove + + + quarter + + 69 + 17 + + + + quarter + + 69 + 17 + + + + + + + + measure + 4/4 + + + + + + + fermataAbove + 2 + + + 2.5 + 1 + = 150 + + + quarter + + 69 + 17 + + + + fermataAbove + 3 + + + quarter + + 69 + 17 + + + + fermataAbove + + + quarter + + 69 + 17 + + + + quarter + + 69 + 17 + + + + + + + + fermataAbove + 2 + + + quarter + + 69 + 17 + + + + fermataAbove + 3 + + + quarter + + 69 + 17 + + + + fermataAbove + + + quarter + + 69 + 17 + + + + quarter + + 69 + 17 + + + + + + + + measure + 4/4 + + + + + + + fermataAbove + 2 + + + 0.5 + 1 + = 30 + + + quarter + + 69 + 17 + + + + fermataAbove + 3 + + + quarter + + 69 + 17 + + + + fermataAbove + + + quarter + + 69 + 17 + + + + quarter + + 69 + 17 + + + + + + + + fermataAbove + 2 + + + quarter + + 69 + 17 + + + + fermataAbove + 3 + + + quarter + + 69 + 17 + + + + fermataAbove + + + quarter + + 69 + 17 + + + + quarter + + 69 + 17 + + + + + + + diff --git a/mtest/libmscore/midi/tst_midi.cpp b/mtest/libmscore/midi/tst_midi.cpp index 7a959ac6c5..b020d6d4fb 100644 --- a/mtest/libmscore/midi/tst_midi.cpp +++ b/mtest/libmscore/midi/tst_midi.cpp @@ -43,6 +43,7 @@ class TestMidi : public QObject, public MTest { Q_OBJECT void midiExportTestRef(const QString& file); + void testMidiExport(MasterScore* score, const QString& writeFile, const QString& refFile); private slots: void initTestCase(); @@ -67,6 +68,7 @@ class TestMidi : public QObject, public MTest midiExportTestRef("testVoltaDynamic"); // test changing Dynamic in prima and seconda volta midiExportTestRef("testVoltaStaffText"); // test changing StaffText in prima and seconda volta } + void midiTimeStretchFermata(); }; //--------------------------------------------------------- @@ -364,6 +366,31 @@ void TestMidi::midi03() delete score2; } +//--------------------------------------------------------- +// midiTimeStretchFermata +//--------------------------------------------------------- + +void TestMidi::midiTimeStretchFermata() + { + const QString file("testTimeStretchFermata"); + QString readFile(DIR + file + ".mscx"); + QString writeFile(file + "-test-%1.mid"); + QString reference(DIR + file + "-ref.mid"); + + MasterScore* score = readScore(readFile); + testMidiExport(score, writeFile.arg(1), reference); + + const Fraction frac1 = 2 * Fraction(4, 4) + Fraction(2, 4); // 3rd measure, 3rd beat + score->doLayoutRange(frac1.ticks(), frac1.ticks()); + testMidiExport(score, writeFile.arg(2), reference); + + const Fraction frac2 = 6 * Fraction(4, 4); // 7th measure + score->doLayoutRange(frac2.ticks(), frac2.ticks()); + testMidiExport(score, writeFile.arg(3), reference); + + delete score; + } + //--------------------------------------------------------- // events //--------------------------------------------------------- @@ -404,6 +431,19 @@ void TestMidi::events() QVERIFY(score); QVERIFY(compareFiles(writeFile, reference)); // QVERIFY(saveCompareScore(score, writeFile, reference)); + + delete score; + } + +//--------------------------------------------------------- +// testMidiExport +//--------------------------------------------------------- + +void TestMidi::testMidiExport(MasterScore* score, const QString& writeFile, const QString& refFile) + { + Q_ASSERT(writeFile.endsWith(".mid") && refFile.endsWith(".mid")); + QVERIFY(saveMidi(score, writeFile)); + QVERIFY(compareFiles(writeFile, refFile)); } //--------------------------------------------------------- @@ -418,8 +458,7 @@ void TestMidi::midiExportTestRef(const QString& file) QVERIFY(score); score->doLayout(); score->rebuildMidiMapping(); - QVERIFY(saveMidi(score, QString(file) + ".mid")); - QVERIFY(compareFiles(QString(file) + ".mid", DIR + QString(file) + "-ref.mid")); + testMidiExport(score, QString(file) + ".mid", DIR + QString(file) + "-ref.mid"); delete score; }