diff --git a/global/settings/types/preferencekeys.h b/global/settings/types/preferencekeys.h index 5ac4aed6ecf51..dd77d2f40aef5 100644 --- a/global/settings/types/preferencekeys.h +++ b/global/settings/types/preferencekeys.h @@ -59,6 +59,9 @@ #define PREF_APP_TELEMETRY_ALLOWED "application/telemetry/allowed" #define PREF_APP_BACKUP_GENERATE_BACKUP "application/backup/generateBackup" #define PREF_APP_BACKUP_SUBFOLDER "application/backup/subfolder" +#define PREF_APP_SHOW_PROGRESS_LAYOUT "application/show/progressBar/layout" +#define PREF_APP_SHOW_PROGRESS_SAVE "application/show/progressBar/save" +#define PREF_APP_SHOW_PROGRESS_AUTOSAVE "application/show/progressBar/autosave" #define PREF_EXPORT_AUDIO_NORMALIZE "export/audio/normalize" #define PREF_EXPORT_AUDIO_SAMPLERATE "export/audio/sampleRate" #define PREF_EXPORT_AUDIO_PCMRATE "export/audio/PCMRate" diff --git a/libmscore/check.cpp b/libmscore/check.cpp index 687aec51b11d3..3061dd9b7dd25 100644 --- a/libmscore/check.cpp +++ b/libmscore/check.cpp @@ -104,16 +104,18 @@ qDebug("checkScore: remove empty ChordRest segment"); if (lcr) { Fraction timeStretch = st->timeStretch(lcr->tick()); Fraction f = cr->globalTicks() * timeStretch; - qDebug("Chord/Rest gap at tick %d(%s+%d)-%d(%s) staffIdx %d measure %d (len = %d)", - tick.ticks(), lcr->name(), f.ticks(), - s->tick().ticks(), cr->name(), staffIdx, cr->measure()->no(), - (cr->tick() - tick).ticks()); + qDebug().nospace().noquote() + << "Chord/Rest gap at tick " << tick.print() + << "(" << lcr->name() << "+" << f.print() << ")" + << "-" << s->tick().print() << "(" << cr->name() <<")" + << " staffIdx " << staffIdx << " measure " << cr->measure()->no() + << " (len = " << (cr->tick() - tick).print() << ")"; } else { - qDebug("Chord/Rest gap at tick %d-%d(%s) staffIdx %d measure %d (len = %d)", - tick.ticks(), - s->tick().ticks(), cr->name(), staffIdx, cr->measure()->no(), - (cr->tick() - tick).ticks()); + qDebug().nospace().noquote() + << "Chord/Rest gap at tick " << tick.print() << "-" << s->tick().print() + << "(" << cr->name() << ")" << " staffIdx " << staffIdx << " measure " << cr->measure()->no() + << " (len = " << (cr->tick() - tick).print() << ")"; } #if 0 if (cr->tick() > tick) { @@ -262,8 +264,9 @@ bool Score::checkKeys() k = toKeySig(element)->key(); } if (staff(i)->key(m->tick()) != k) { - qDebug("measure %d (tick %d) : key %d, map %d", m->no(), m->tick().ticks(), int(k), - int(staff(i)->key(m->tick()))); + qDebug().nospace().noquote() + << "measure " << m->no() << "(tick " << m->tick().print() <<") : " + << "key " << int(k) << ", map " << int(staff(i)->key(m->tick())); rc = false; } } @@ -315,12 +318,9 @@ bool Score::checkClefs() void Measure::fillGap(const Fraction& pos, const Fraction& len, int track, const Fraction& stretch, bool useGapRests) { - qDebug("measure %6d pos %d, len %d/%d, stretch %d/%d track %d", - tick().ticks(), - pos.ticks(), - len.numerator(), len.denominator(), - stretch.numerator(), stretch.denominator(), - track); + qDebug().nospace().noquote() + << "measure " << tick().print() << " pos " << pos.print() << ", " + << "len " << len.print() << " stretch " << stretch.print() << " track " << track; TDuration d; d.setVal(len.ticks()); if (d.isValid()) { @@ -363,11 +363,17 @@ void Measure::checkMeasure(int staffIdx, bool useGapRests) currentPos = seg->rtick() * stretch; if (currentPos < expectedPos) { - qDebug("in measure overrun %6d at %d-%d track %d", tick().ticks(), (currentPos/stretch).ticks(), (expectedPos/stretch).ticks(), track); + qDebug().nospace().noquote() + << "in measure overrun" << tick().print() + << "at " << (currentPos/stretch).ticks() << "-" << (expectedPos/stretch).ticks() + << " track " << track; break; } else if (currentPos > expectedPos) { - qDebug("in measure underrun %6d at %d-%d track %d", tick().ticks(), (currentPos/stretch).ticks(), (expectedPos/stretch).ticks(), track); + qDebug().nospace().noquote() + << "in measure underrun " << tick().print() + << " at " << (currentPos/stretch).ticks() << "-" << (expectedPos/stretch).ticks() + << " track " << track; fillGap(expectedPos, currentPos - expectedPos, track, stretch); } @@ -385,7 +391,10 @@ void Measure::checkMeasure(int staffIdx, bool useGapRests) fillGap(expectedPos, f - expectedPos, track, stretch, useGapRests); } else if (f < expectedPos) - qDebug("measure overrun %6d, %d > %d, track %d", tick().ticks(), expectedPos.ticks(), f.ticks(), track); + qDebug().nospace().noquote() + << "measure overrun "<< tick().print() << "," + << expectedPos.print() << " > " << f.print() << ", " + << "track " << track; } } diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index d6b91040f7d31..1598d433cc48f 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -1711,7 +1711,9 @@ void Score::connectTies(bool silent) nnote = searchTieNote(n); if (nnote == 0) { if (!silent) { - qDebug("next note at %d track %d for tie not found (version %d)", s->tick().ticks(), i, _mscVersion); + qDebug().nospace().noquote() + << "next note at " << s->tick().print() + <<" track " << i <<" for tie not found (version " << _mscoreVersion << ")"; delete tie; n->setTieFor(0); } @@ -4558,7 +4560,9 @@ System* Score::collectSystem(LayoutContext& lc) #ifndef NDEBUG if (!qFuzzyCompare(mw, minWidth)) - qDebug("==layoutSystem %6d old %.1f new %.1f", system->measures().front()->tick().ticks(), minWidth, mw); + qDebug().nospace().noquote() + << "==layoutSystem " << system->measures().front()->tick().print() + << " old " << minWidth << " new " << mw; #endif rest = systemWidth - minWidth; // @@ -5699,12 +5703,38 @@ void Score::doLayoutRange(const Fraction& st, const Fraction& et) void LayoutContext::layout() { MeasureBase* lmb; + + QProgressDialog progress; + const bool layoutAll = (startTick <= Fraction(0,1) && (endTick < Fraction(0,1) || endTick >= score->last()->endTick())); + + const bool showProgress = (MScore::showProgressBarForLayout && layoutAll) || (MScore::showProgressBarForPartialLayout); + if (showProgress) { + const int totalMeasures = score->measures() ? score->measures()->size() : 0; + QString label; + if (layoutAll) + label = QObject::tr("Performing full layout") + QObject::tr(" for") + ":\n" + score->title() + "…"; + else + label = QObject::tr("Performing partial layout between ") + startTick.print() + " and " + endTick.print() + + QObject::tr(" for") + ":\n" + score->title() + "…"; + + progress.setLabelText(label); + progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)); + progress.setRange(0, totalMeasures); + progress.setCancelButton(nullptr); + progress.setWindowModality(Qt::WindowModal); + progress.setValue(0); + progress.setMinimumDuration(0); + } + do { getNextPage(); collectPage(); - if (page && !page->systems().isEmpty()) + if (page && !page->systems().isEmpty()) { lmb = page->systems().back()->measures().back(); + if (showProgress) + progress.setValue(lmb->index()); + } else lmb = nullptr; @@ -5720,6 +5750,8 @@ void LayoutContext::layout() } while (curSystem && !(rangeDone && lmb == pageOldMeasure)); // && page->system(0)->measures().back()->tick() > endTick // FIXME: perhaps the first measure was meant? Or last system? + progress.close(); + if (!curSystem) { // The end of the score. The remaining systems are not needed... qDeleteAll(systemList); diff --git a/libmscore/line.cpp b/libmscore/line.cpp index 69f563d825e06..0538efa263684 100644 --- a/libmscore/line.cpp +++ b/libmscore/line.cpp @@ -883,7 +883,9 @@ QPointF SLine::linePos(Grip grip, System** sys) const // it is possible CR won't be in correct track // prefer element in current track if available if (!cr) - qDebug("no end for lyricsline segment - start %d, ticks %d", tick().ticks(), ticks().ticks()); + qDebug().nospace().noquote() + << "no end for lyricsline segmente - start " << tick().print() << ", " + << "ticks " << ticks().print(); else if (cr->track() != track()) { Element* e = cr->segment()->element(track()); if (e) diff --git a/libmscore/mscore.cpp b/libmscore/mscore.cpp index 141d599ad2313..5dfdf0d464b01 100644 --- a/libmscore/mscore.cpp +++ b/libmscore/mscore.cpp @@ -56,6 +56,11 @@ bool MScore::showSystemBoundingRect = false; bool MScore::showCorruptedMeasures = true; bool MScore::useFallbackFont = true; +bool MScore::showProgressBarForLayout = true; +bool MScore::showProgressBarForPartialLayout = false; +bool MScore::showProgressBarForSave = true; +bool MScore::showProgressBarForAutosave = true; + bool MScore::saveTemplateMode = false; bool MScore::noGui = false; diff --git a/libmscore/mscore.h b/libmscore/mscore.h index 587296ee5719a..bf2c7f6f377c0 100644 --- a/libmscore/mscore.h +++ b/libmscore/mscore.h @@ -456,6 +456,11 @@ class MScore { static bool debugMode; static bool testMode; + static bool showProgressBarForLayout; + static bool showProgressBarForPartialLayout; + static bool showProgressBarForSave; + static bool showProgressBarForAutosave; + static int division; static int sampleRate; static int mtcType; diff --git a/libmscore/rendermidi.cpp b/libmscore/rendermidi.cpp index 572c789496fd6..b722e3a5ef0a7 100644 --- a/libmscore/rendermidi.cpp +++ b/libmscore/rendermidi.cpp @@ -17,6 +17,8 @@ #include +#include + #include "arpeggio.h" #include "articulation.h" #include "bend.h" @@ -2638,9 +2640,36 @@ void Score::renderMidi(EventMap* events, bool metronome, bool expandRepeats, con void MidiRenderer::renderScore(EventMap* events, const Context& ctx) { updateState(); + + int currentChunk = 0; + QProgressDialog progress; + if (MScore::showProgressBarForLayout) { + const int totalChunks = chunks.size(); + QString label = QObject::tr("Rendering MIDI events") + " " + + QObject::tr("for") + ":\n" + + score->title() + "…\n" + + QObject::tr("Safe to cancel early"); + + progress.setLabelText(label); + progress.setCancelButtonText(QObject::tr("Cancel")); + progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)); + progress.setRange(0, totalChunks); + progress.setWindowModality(Qt::WindowModal); + progress.setValue(0); + progress.setMinimumDuration(2500); + } + for (const Chunk& chunk : chunks) { + if (MScore::showProgressBarForLayout) { + progress.setValue(++currentChunk); + // Allow user to prematurely break rendering: + if (progress.wasCanceled()) + break; + } + renderChunk(chunk, events, ctx); } + progress.close(); } void MidiRenderer::renderChunk(const Chunk& chunk, EventMap* events, const Context& ctx) diff --git a/libmscore/score.h b/libmscore/score.h index 09d418818f221..475d477bc374e 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -473,6 +473,7 @@ class Score : public QObject, public ScoreElement { bool _showVBox { true }; bool _printing { false }; ///< True if we are drawing to a printer bool _autosaveDirty { true }; + bool _isAutosaving { false }; bool _savedCapture { false }; ///< True if we saved an image capture bool _saved { false }; ///< True if project was already saved; only on first ///< save a backup file will be created, subsequent @@ -914,6 +915,8 @@ class Score : public QObject, public ScoreElement { void setPrinting(bool val) { _printing = val; } void setAutosaveDirty(bool v) { _autosaveDirty = v; } bool autosaveDirty() const { return _autosaveDirty; } + bool isAutosaving() const { return _isAutosaving; } + void setAutosaving(bool v) { _isAutosaving = v; } virtual bool playlistDirty() const; virtual void setPlaylistDirty(); diff --git a/libmscore/scorefile.cpp b/libmscore/scorefile.cpp index 913726ca756ff..725dc94ce19bb 100644 --- a/libmscore/scorefile.cpp +++ b/libmscore/scorefile.cpp @@ -220,6 +220,26 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly) xml.setCurTrack(0); xml.setTrackDiff(-staffStart * VOICES); if (measureStart) { + + // progress bar + const bool showOnSave = (!isAutosaving() && MScore::showProgressBarForSave); + const bool showOnAutosave = (isAutosaving() && MScore::showProgressBarForAutosave); + int currentMeasureIdx = 0; + QProgressDialog progress; + if (showOnSave || showOnAutosave) { + int totalMeasuresByStaff = (staffEnd - staffStart) * score()->measures()->size(); + QString label = (showOnAutosave ? QObject::tr("Performing Autosave") + : QObject::tr("Save File")) + ":\n" + + score()->title() + "…"; + progress.setLabelText(label); + progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint)); + progress.setCancelButton(nullptr); + progress.setRange(0, totalMeasuresByStaff); + progress.setWindowModality(Qt::WindowModal); + progress.setValue(0); + progress.setMinimumDuration(0); + } + for (int staffIdx = staffStart; staffIdx < staffEnd; ++staffIdx) { xml.stag(staff(staffIdx), QString("id=\"%1\"").arg(staffIdx + 1 - staffStart)); xml.setCurTick(measureStart->tick()); @@ -238,11 +258,17 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly) else forceTimeSig = false; } + + if (showOnSave || showOnAutosave) + progress.setValue(++currentMeasureIdx); + // Largest consumption of time for file-saving: writeMeasure(xml, m, staffIdx, writeSystemElements, forceTimeSig); } xml.etag(); } + + progress.close(); } xml.setCurTrack(-1); if (isMaster()) { diff --git a/libmscore/utils.cpp b/libmscore/utils.cpp index 1109bd6a586aa..31f7b0ead925e 100644 --- a/libmscore/utils.cpp +++ b/libmscore/utils.cpp @@ -63,7 +63,9 @@ Measure* Score::tick2measure(const Fraction& tick) const // check last measure if (lm && (tick >= lm->tick()) && (tick <= lm->endTick())) return lm; - qDebug("tick2measure %d (max %d) not found", tick.ticks(), lm ? lm->tick().ticks() : -1); + qDebug().nospace().noquote() + << "tick2measure " << tick.print() << " (max " << (lm ? lm->tick().print() : Fraction::fromTicks(-1).print()) << ") " + << "not found"; return 0; } @@ -91,7 +93,9 @@ Measure* Score::tick2measureMM(const Fraction& t) const // check last measure if (lm && (tick >= lm->tick()) && (tick <= lm->endTick())) return lm; - qDebug("tick2measureMM %d (max %d) not found", tick.ticks(), lm ? lm->tick().ticks() : -1); + qDebug().nospace().noquote() + << "tick2measureMM " << tick.print() << "(max " << (lm ? lm->tick().print() : Fraction::fromTicks(-1).print()) << ") " + << "not found"; return 0; } @@ -159,7 +163,9 @@ Segment* Score::tick2segment(const Fraction& t, bool first, SegmentType st, bool } segment = nsegment; } - qDebug("no segment for tick %d (start search at %d (measure %d))", tick.ticks(), t.ticks(), m->tick().ticks()); + qDebug().nospace().noquote() + << "no segment for tick " << tick.print() << " (start search at " << t.print() + << " (measure "<< m->tick().print() << "))"; return 0; } diff --git a/mscore/file.cpp b/mscore/file.cpp index 74d5d7decde3f..048ec37c4f465 100644 --- a/mscore/file.cpp +++ b/mscore/file.cpp @@ -383,6 +383,7 @@ void MuseScore::askAboutApplyingEdwinIfNeed(const QString& fileSuffix) Score* MuseScore::openScore(const QString& fn, bool switchTab, const bool considerInCurrentSession, const QString& name) { + ScoreLoad sl; // // make sure we load a file only once // @@ -2549,8 +2550,7 @@ Score::FileError readScore(MasterScore* score, QString name, bool ignoreVersionE score->updateChannel(); score->updateExpressive(MuseScore::synthesizer("Fluid")); score->setSaved(false); - // TEST: Omit updating here since MuseScore::openScore() performs full layout after this - // score->update(); + // TEST: Omitting score->update() since MuseScore::openScore() performs full layout after this score->styleChanged(); if (!ignoreVersionError && !MScore::noGui) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 505b68455820f..2fe19cb5d3f09 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -549,6 +549,10 @@ void updateExternalValuesFromPreferences() { MScore::dropColor = preferences.getColor(PREF_UI_SCORE_NOTE_DROPCOLOR); MScore::defaultColor = preferences.getColor(PREF_UI_SCORE_DEFAULTCOLOR); + MScore::showProgressBarForLayout = preferences.getBool(PREF_APP_SHOW_PROGRESS_LAYOUT); + MScore::showProgressBarForSave = preferences.getBool(PREF_APP_SHOW_PROGRESS_SAVE); + MScore::showProgressBarForAutosave = preferences.getBool(PREF_APP_SHOW_PROGRESS_AUTOSAVE); + MScore::palettesHideWhenApplied = preferences.getBool(PREF_UI_APP_AUTOHIDE_PALETTES); MScore::pianoHighlightColor = preferences.getColor(PREF_UI_PIANO_HIGHLIGHTCOLOR); @@ -5893,6 +5897,7 @@ void MuseScore::autoSaveTimerTimeout() for (MasterScore* s : qAsConst(scoreList)) { if (s->autosaveDirty()) { // qDebug("<%s>", qPrintable(s->fileInfo()->completeBaseName())); + s->setAutosaving(true); QString tmp = s->tmpName(); if (!tmp.isEmpty()) { QFileInfo fi(tmp); @@ -5917,6 +5922,7 @@ void MuseScore::autoSaveTimerTimeout() sessionChanged = true; } s->setAutosaveDirty(false); + s->setAutosaving(false); } } if (sessionChanged) @@ -7565,6 +7571,7 @@ void MuseScore::cmd(QAction* a, const QString& cmd) MScore::showBoundingRect = a->isChecked(); MScore::showSegmentShapes = a->isChecked(); MScore::showSkylines = a->isChecked(); + MScore::showProgressBarForPartialLayout = MScore::showSkylines; if (cs) { cs->setLayoutAll(); cs->update(); diff --git a/mscore/preferences.cpp b/mscore/preferences.cpp index fba65fbeffe95..80de15e3e4637 100644 --- a/mscore/preferences.cpp +++ b/mscore/preferences.cpp @@ -164,6 +164,9 @@ void Preferences::init(bool storeInMemoryOnly) {PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN_XML, new BoolPreference(false, false)}, {PREF_APP_BACKUP_GENERATE_BACKUP, new BoolPreference(true)}, {PREF_APP_BACKUP_SUBFOLDER, new StringPreference(".mscbackup")}, + {PREF_APP_SHOW_PROGRESS_LAYOUT, new BoolPreference(true)}, + {PREF_APP_SHOW_PROGRESS_SAVE, new BoolPreference(true)}, + {PREF_APP_SHOW_PROGRESS_AUTOSAVE, new BoolPreference(true)}, {PREF_EXPORT_AUDIO_NORMALIZE, new BoolPreference(true, false)}, {PREF_EXPORT_AUDIO_SAMPLERATE, new IntPreference(44100, false)}, {PREF_EXPORT_AUDIO_PCMRATE, new IntPreference(16)}, diff --git a/mscore/searchComboBox.cpp b/mscore/searchComboBox.cpp index f91b9bc07731d..f2b5cbbceefca 100644 --- a/mscore/searchComboBox.cpp +++ b/mscore/searchComboBox.cpp @@ -131,6 +131,9 @@ QString AccessibleSearchBox::text(QAccessible::Text t) const case SearchComboBox::SearchType::SEARCH_REHEARSAL_MARK: type = tr("Rehearsal Mark"); break; + case SearchComboBox::SearchType::SEARCH_TICK: + type = tr("Tick"); + break; } QString found = searchBox->found() ? "" : tr("Not found") + " "; return QString("%1 %2 %3%4").arg(type, value, found, mscore->currentScoreView()->score()->accessibleInfo()); diff --git a/mtest/libmscore/tools/undoSlashRhythm01-ref.mscx b/mtest/libmscore/tools/undoSlashRhythm01-ref.mscx index 1781bd63dcd5a..4cb8d9105df33 100644 --- a/mtest/libmscore/tools/undoSlashRhythm01-ref.mscx +++ b/mtest/libmscore/tools/undoSlashRhythm01-ref.mscx @@ -946,8 +946,8 @@ quarter - -9 - -9 + -10 + -10 1 @@ -981,8 +981,8 @@ - -9 - -9 + -10 + -10 1 diff --git a/mtest/libmscore/tools/undoSlashRhythm02-ref.mscx b/mtest/libmscore/tools/undoSlashRhythm02-ref.mscx index 28d7e8d9d5128..12d6ab015011e 100644 --- a/mtest/libmscore/tools/undoSlashRhythm02-ref.mscx +++ b/mtest/libmscore/tools/undoSlashRhythm02-ref.mscx @@ -805,8 +805,8 @@ quarter - -9 - -9 + -10 + -10 eighth @@ -834,8 +834,8 @@ - -9 - -9 + -10 + -10 eighth diff --git a/mtest/musicxml/io/testBackupRoundingError_ref.mscx b/mtest/musicxml/io/testBackupRoundingError_ref.mscx index 5df7505978948..97fe99824712d 100644 --- a/mtest/musicxml/io/testBackupRoundingError_ref.mscx +++ b/mtest/musicxml/io/testBackupRoundingError_ref.mscx @@ -699,7 +699,7 @@ up 0 - 0 + -1 begin @@ -1246,8 +1246,8 @@ down - 6 - 6 + 5 + 5 begin @@ -1852,7 +1852,7 @@ up - 7 + 8 6 @@ -1897,7 +1897,7 @@ up - 3 + 4 8 diff --git a/mtest/musicxml/io/testCueGraceNotes_ref.mscx b/mtest/musicxml/io/testCueGraceNotes_ref.mscx index ce4af7f37275c..f7d6a157c1989 100644 --- a/mtest/musicxml/io/testCueGraceNotes_ref.mscx +++ b/mtest/musicxml/io/testCueGraceNotes_ref.mscx @@ -252,7 +252,7 @@ down 14 - 13 + 12 begin @@ -299,8 +299,8 @@ down - 18 - 14 + 17 + 13 begin