From 25c0b38fc6f3c4f52869a0ce767a2c8253ebbd13 Mon Sep 17 00:00:00 2001 From: "J.G" Date: Sun, 21 Sep 2025 09:24:16 +0000 Subject: [PATCH 01/14] Aside Fix: findFirstTrill() update Got a crash during CollectEvents when navigating+activating. These changes might help tame the timing (tick called only once now and not using actualTicks, so less calculation during sequencer playback --- libmscore/rendermidi.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libmscore/rendermidi.cpp b/libmscore/rendermidi.cpp index 1ec4433955169..5479dd3e92be6 100644 --- a/libmscore/rendermidi.cpp +++ b/libmscore/rendermidi.cpp @@ -2072,8 +2072,12 @@ void renderGlissando(NoteEventList* events, Note *notestart) Trill* findFirstTrill(Chord *chord) { - auto spanners = chord->score()->spannerMap().findOverlapping(1+chord->tick().ticks(), - chord->tick().ticks() + chord->actualTicks().ticks() - 1); + auto& spannerMap = chord->score()->spannerMap(); + auto tick = chord->tick(); + auto duration = chord->ticks(); // originally chord->actualTicks(); + auto st = 1 + tick.ticks(); + auto et = tick.ticks() + duration.ticks() - 1; + auto spanners = spannerMap.findOverlapping(st, et); for (auto i : spanners) { if (i.value->type() != ElementType::TRILL) continue; From 3b6649e0bf8cc785e2ec3708ddaeddf9231fc74c Mon Sep 17 00:00:00 2001 From: "J.G" Date: Mon, 1 Sep 2025 01:00:44 +0000 Subject: [PATCH 02/14] MSVC: Fix else-if nesting exceeded max amount Bundled "toggle" and "play" commands --- mscore/musescore.cpp | 273 ++++++++++++++++++++++--------------------- 1 file changed, 142 insertions(+), 131 deletions(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 9f87549359648..e3563c6839213 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -6747,7 +6747,148 @@ void MuseScore::cmd(QAction* a, const QString& cmd) if (ScriptRecorder* rec = getScriptRecorder()) rec->recordCommand(cmd); - if (cmd == "instruments") + if (cmd.startsWith("play-")) { + const bool next = true; + const bool prev = false; + if (cmd == "play-next-system") + seq->nextSystem(next); + else if (cmd == "play-next-measure") + seq->nextMeasure(); + else if (cmd == "play-next-chord") + seq->nextChord(); + else if (cmd == "play-next-rehearsal-mark") + seq->nextRehearsalMark(next); + else if (cmd == "play-prev-system") + seq->nextSystem(prev); + else if (cmd == "play-prev-measure") + seq->prevMeasure(); + else if (cmd == "play-prev-chord") + seq->prevChord(); + else if (cmd == "play-prev-rehearsal-mark") + seq->nextRehearsalMark(prev); + else + cv->cmd(a); + } + else if (cmd.startsWith("color-override-")) { + std::string ss = cmd.toStdString(); + const char* token = &(ss.c_str())[15]; + cv->score()->cmdOverrideColor(token); + genIcons(); + Shortcut::refreshIcons(); + } + else if (cmd.startsWith("toggle-options-")) { + bool updateScore = cv->score()->cmdToggleOptions(cmd); + genIcons(); + Shortcut::refreshIcons(); + if (cs && updateScore) { + cs->setLayoutAll(); + cs->update(); + } + } + else if (cmd.startsWith("toggle")) { + if (cmd == "toggle-statusbar") { + preferences.setPreference(PREF_UI_APP_SHOWSTATUSBAR, a->isChecked()); + _statusBar->setVisible(a->isChecked()); + } + else if (cmd == "toggle-playpanel") + showPlayPanel(a->isChecked()); + else if (cmd == "toggle-navigator") + showNavigator(a->isChecked()); + else if (cmd == "toggle-timeline") + showTimeline(a->isChecked()); + else if (cmd == "toggle-midiimportpanel") + importmidiPanel->setVisible(a->isChecked()); + else if (cmd == "toggle-mixer") + showMixer(a->isChecked()); + + else if (cmd == "toggle-selection-window") + showSelectionWindow(a->isChecked()); + else if (cmd == "toggle-fileoperations") + fileTools->setVisible(!fileTools->isVisible()); + else if (cmd == "toggle-transport") + transportTools->setVisible(!transportTools->isVisible()); + else if (cmd == "toggle-concertpitch") + cpitchTools->setVisible(!cpitchTools->isVisible()); + else if (cmd == "toggle-imagecapture") + fotoTools->setVisible(!fotoTools->isVisible()); + else if (cmd == "toggle-noteinput") + entryTools->setVisible(!entryTools->isVisible()); + else if (cmd == "toggle-colorcontrol") + colorTools->setVisible(!colorTools->isVisible()); + else if (cmd == "toggle-optionscontrol") + toggleTools->setVisible(!toggleTools->isVisible()); + else if (cmd == "toggle-workspaces-toolbar") + workspacesTools->setVisible(!workspacesTools->isVisible()); + else if (cmd == "toggle-piano") + showPianoKeyboard(a->isChecked()); + else if (cmd == "toggle-scorecmp-tool") + reDisplayDockWidget(scoreCmpTool, a->isChecked()); + #ifdef MSCORE_UNSTABLE + else if (cmd == "toggle-script-recorder") + scriptRecorder->setVisible(a->isChecked()); + #endif + else if (cmd == "toggle-all-unprintable") { + // Master toggle command to show/unshow all invisible and unprintable elements: + cs->setShowInvisible(a->isChecked()); + cs->setShowUnprintable(a->isChecked()); + cs->setShowFrames(a->isChecked()); + cs->setShowPageborders(a->isChecked()); + cs->setMarkIrregularMeasures(a->isChecked()); + cs->update(); + } + else if (cmd == "toggle-fingering-visibility") { + bool wasNotShowingInvisible = false; + if (!cs->showInvisible()) { + wasNotShowingInvisible = true; + cs->setShowInvisible(true); + cs->rebuildBspTree(); + } + for (auto& page : cs->pages()) { + for (auto el : page->elements()) { + if (el->isFingering()) { + auto fingering = toFingering(el); + bool invert = !fingering->visible(); + fingering->setVisible(invert); + fingering->triggerLayout(); + } + else if (el->isImage()) { + auto img = toImage(el); + if (img->isEmpty()) { + bool invert = !img->visible(); + img->setVisible(invert); + img->triggerLayout(); + } + } + } + } + cs->setLayoutAll(); + cs->update(); + if (wasNotShowingInvisible) { + cs->setShowInvisible(false); + } + } + else if (cmd == "toggle-visible-en-passant") { + int begin = 0; + int end = cs->endTick().ticks(); + auto spanners = cs->spannerMap().findOverlapping(begin, end); + for (auto i : spanners) { + auto s = i.value; + if (s->isTextLineBase()) { + auto tlb = toTextLineBase(s); + bool enPassant = tlb->enPassantManifest(); + if (enPassant) { + bool toggle = !tlb->visible(); + tlb->setVisible(toggle); + } + } + } + cs->setLayoutAll(); + cs->update(); + } + else + cv->cmd(a); + } + else if (cmd == "instruments") editInstrumentList(); else if (cmd == "rewind") { if (cs) { @@ -6762,22 +6903,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) playPanel->heartBeat(0, 0, 0); } } - else if (cmd == "play-next-system") - seq->nextSystem(true/*next*/); - else if (cmd == "play-next-measure") - seq->nextMeasure(); - else if (cmd == "play-next-chord") - seq->nextChord(); - else if (cmd == "play-prev-system") - seq->nextSystem(false/*prev*/); - else if (cmd == "play-prev-measure") - seq->prevMeasure(); - else if (cmd == "play-prev-chord") - seq->prevChord(); - else if (cmd == "play-next-rehearsal-mark") - seq->nextRehearsalMark(); - else if (cmd == "play-prev-rehearsal-mark") - seq->nextRehearsalMark(false); else if (cmd == "seek-begin") seq->rewindStart(); else if (cmd == "seek-end") @@ -6816,10 +6941,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) showMasterPalette(qApp->translate("Palette", "Time Signatures")); else if (cmd == "symbols") showMasterPalette(qApp->translate("MasterPalette", "Symbols")); - else if (cmd == "toggle-statusbar") { - preferences.setPreference(PREF_UI_APP_SHOWSTATUSBAR, a->isChecked()); - _statusBar->setVisible(a->isChecked()); - } else if (cmd == "append-measures") cmdAppendMeasures(); else if (cmd == "insert-measures") @@ -6942,38 +7063,10 @@ void MuseScore::cmd(QAction* a, const QString& cmd) else if (cmd == "omr") showOmrPanel(a->isChecked()); #endif - else if (cmd == "toggle-playpanel") - showPlayPanel(a->isChecked()); - else if (cmd == "toggle-navigator") - showNavigator(a->isChecked()); - else if (cmd == "toggle-timeline") - showTimeline(a->isChecked()); - else if (cmd == "toggle-midiimportpanel") - importmidiPanel->setVisible(a->isChecked()); - else if (cmd == "toggle-mixer") - showMixer(a->isChecked()); else if (cmd == "synth-control") showSynthControl(a->isChecked()); - else if (cmd == "toggle-selection-window") - showSelectionWindow(a->isChecked()); else if (cmd == "show-keys") ; - else if (cmd == "toggle-fileoperations") - fileTools->setVisible(!fileTools->isVisible()); - else if (cmd == "toggle-transport") - transportTools->setVisible(!transportTools->isVisible()); - else if (cmd == "toggle-concertpitch") - cpitchTools->setVisible(!cpitchTools->isVisible()); - else if (cmd == "toggle-imagecapture") - fotoTools->setVisible(!fotoTools->isVisible()); - else if (cmd == "toggle-noteinput") - entryTools->setVisible(!entryTools->isVisible()); - else if (cmd == "toggle-colorcontrol") - colorTools->setVisible(!colorTools->isVisible()); - else if (cmd == "toggle-optionscontrol") - toggleTools->setVisible(!toggleTools->isVisible()); - else if (cmd == "toggle-workspaces-toolbar") - workspacesTools->setVisible(!workspacesTools->isVisible()); else if (cmd == "create-new-workspace") { mscore->createNewWorkspace(); emit mscore->workspacesChanged(); @@ -7007,14 +7100,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) editRaster(); else if (cmd == "hraster" || cmd == "vraster") // value in [hv]RasterAction already set ; - else if (cmd == "toggle-piano") - showPianoKeyboard(a->isChecked()); - else if (cmd == "toggle-scorecmp-tool") - reDisplayDockWidget(scoreCmpTool, a->isChecked()); -#ifdef MSCORE_UNSTABLE - else if (cmd == "toggle-script-recorder") - scriptRecorder->setVisible(a->isChecked()); -#endif else if (cmd == "plugin-creator") showPluginCreator(a); else if (cmd == "plugin-manager") @@ -7073,64 +7158,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) cs->setShowInvisible(a->isChecked()); cs->update(); } - else if (cmd == "toggle-all-unprintable") { - // Master toggle command to show/unshow all invisible and unprintable elements: - cs->setShowInvisible(a->isChecked()); - cs->setShowUnprintable(a->isChecked()); - cs->setShowFrames(a->isChecked()); - cs->setShowPageborders(a->isChecked()); - cs->setMarkIrregularMeasures(a->isChecked()); - cs->update(); - } - else if (cmd == "toggle-fingering-visibility") { - bool wasNotShowingInvisible = false; - if (!cs->showInvisible()) { - wasNotShowingInvisible = true; - cs->setShowInvisible(true); - cs->rebuildBspTree(); - } - for (auto& page : cs->pages()) { - for (auto el : page->elements()) { - if (el->isFingering()) { - auto fingering = toFingering(el); - bool invert = !fingering->visible(); - fingering->setVisible(invert); - fingering->triggerLayout(); - } - else if (el->isImage()) { - auto img = toImage(el); - if (img->isEmpty()) { - bool invert = !img->visible(); - img->setVisible(invert); - img->triggerLayout(); - } - } - } - } - cs->setLayoutAll(); - cs->update(); - if (wasNotShowingInvisible) { - cs->setShowInvisible(false); - } - } - else if (cmd == "toggle-visible-en-passant") { - int begin = 0; - int end = cs->endTick().ticks(); - auto spanners = cs->spannerMap().findOverlapping(begin, end); - for (auto i : spanners) { - auto s = i.value; - if (s->isTextLineBase()) { - auto tlb = toTextLineBase(s); - bool enPassant = tlb->enPassantManifest(); - if (enPassant) { - bool toggle = !tlb->visible(); - tlb->setVisible(toggle); - } - } - } - cs->setLayoutAll(); - cs->update(); - } else if (cmd == "show-unprintable") { cs->setShowUnprintable(a->isChecked()); cs->update(); @@ -7220,22 +7247,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) reportBug("panel"); else if (cmd == "leave-feedback") leaveFeedback("panel"); - else if (cmd.startsWith("color-override-")) { - std::string ss = cmd.toStdString(); - const char* token = &(ss.c_str())[15]; - cv->score()->cmdOverrideColor(token); - genIcons(); - Shortcut::refreshIcons(); - } - else if (cmd.startsWith("toggle-options-")) { - bool updateScore = cv->score()->cmdToggleOptions(cmd); - genIcons(); - Shortcut::refreshIcons(); - if (cs && updateScore) { - cs->setLayoutAll(); - cs->update(); - } - } #ifndef NDEBUG else if (cmd == "no-horizontal-stretch") { MScore::noHorizontalStretch = a->isChecked(); From 2df6e567ff684209e3008c1bfffe2496f47a1d12 Mon Sep 17 00:00:00 2001 From: "J.G" Date: Wed, 17 Sep 2025 20:28:08 +0000 Subject: [PATCH 03/14] Fix: Double & Half durations upon a list selection is more correct --- libmscore/cmd.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index b0ab8adbb894f..8cd7b0ee29a33 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -3306,16 +3306,18 @@ void Score::cmdIncDecDuration(int nSteps, bool stepDotted) pasteStaff(e, selection().startSegment(), selection().staffStart(), scale); return; } - if (selection().isList() && selection().elements().size() > 1) { + + if (selection().isList()) { // List - act as if pressing duration toggle (distinct from range based Half/Double - TDuration newDuration(stepDotted - ? _is.duration().shiftRetainDots(nSteps, stepDotted) - : _is.duration().shift(nSteps)); - _is.duration().shiftRetainDots(nSteps, stepDotted); - _is.setDuration(newDuration); - QSet crs = getSelectedChordRests(); - for (auto cr : getSelectedChordRests()) { - changeCRlen(cr, newDuration); + auto crs = getSelectedChordRests(); + for (auto cr : crs) { + TDuration odt = cr->durationType(); + TDuration ndt(stepDotted ? odt.shiftRetainDots(nSteps, stepDotted) : odt.shift(nSteps)); + bool isGrace = cr->isChord() && toChord(cr)->isGrace(); + if (isGrace) + undoChangeChordRestLen(cr, ndt); + else + changeCRlen(cr, ndt); } for (auto cr : crs) { Element* e = cr; From 4560427a65f56eea7300f94fd3ea3437c0da783d Mon Sep 17 00:00:00 2001 From: "J.G" Date: Sat, 20 Sep 2025 02:50:35 +0000 Subject: [PATCH 04/14] Fix: Playback panel - retain position/visibility when restarting application. PREF_UI_APP_STARTUP_SHOWPLAYPANEL shown as General option in Preferences will potentially override to force always showing at startup if enabled --- mscore/musescore.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index e3563c6839213..3fab120afc45f 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -3446,8 +3446,14 @@ void MuseScore::createPlayPanel() playPanel->setGain(synti->gain()); playPanel->setScore(cs); addDockWidget(Qt::RightDockWidgetArea, playPanel); - playPanel->setVisible(false); - playPanel->setFloating(false); + + QSettings settings; + settings.beginGroup("MainWindow"); + bool floatPanel = settings.value("floatPlayPanel").toBool(); + settings.endGroup(); + + playPanel->setFloating(floatPanel); + restoreGeometry(playPanel); } } @@ -3464,14 +3470,11 @@ void MuseScore::showPlayPanel(bool visible) return; createPlayPanel(); - - // The play panel must be set visible before being set floating for positioning - // and window geometry reasons. playPanel->setVisible(visible); - playPanel->setFloating(false); } else reDisplayDockWidget(playPanel, visible); + playId->setChecked(visible); } @@ -5081,6 +5084,8 @@ void MuseScore::writeSettings() settings.beginGroup("MainWindow"); settings.setValue("showPanel", paletteWidget && paletteWidget->isVisible()); settings.setValue("showInspector", _inspector && _inspector->isVisible()); + settings.setValue("showPlayPanel", playPanel && playPanel->isVisible()); + settings.setValue("floatPlayPanel", playPanel && playPanel->isFloating()); settings.setValue("showPianoKeyboard", _pianoTools && _pianoTools->isVisible()); settings.setValue("showSelectionWindow", selectionWindow && selectionWindow->isVisible()); settings.setValue("state", saveState()); @@ -9010,10 +9015,15 @@ void MuseScore::init(QStringList& argv) qApp->processEvents(); } - mscore->showPlayPanel(preferences.getBool(PREF_UI_APP_STARTUP_SHOWPLAYPANEL)); QSettings settings; if (settings.value("synthControlVisible", false).toBool()) mscore->showSynthControl(true); + + settings.beginGroup("MainWindow"); + const bool forceShowPlayPanel = preferences.getBool(PREF_UI_APP_STARTUP_SHOWPLAYPANEL); + const bool lastSessionShowedPlayPanel = settings.value("showPlayPanel").toBool(); + settings.endGroup(); + mscore->showPlayPanel(forceShowPlayPanel || lastSessionShowedPlayPanel); } From 1eb9e892d839920789d577a4e2fea1a77c7971a7 Mon Sep 17 00:00:00 2001 From: "J.G" Date: Wed, 8 Oct 2025 03:09:31 +0000 Subject: [PATCH 05/14] Sequencer: TEST - Convert a 1 second sleep to 1/10th second sleep for resetting --- audio/drivers/alsa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/drivers/alsa.cpp b/audio/drivers/alsa.cpp index 1ef289d073d61..9060c11e4481a 100644 --- a/audio/drivers/alsa.cpp +++ b/audio/drivers/alsa.cpp @@ -727,7 +727,7 @@ bool AlsaAudio::stop() for (;i < 4; ++i) { if (runAlsa == 0) break; - sleep(1); + usleep(100'000); } pthread_cancel(thread); pthread_join(thread, 0); From 0db6134fc718bdda3336822bbd90a336e86c32d8 Mon Sep 17 00:00:00 2001 From: "J.G" Date: Wed, 8 Oct 2025 06:24:29 +0000 Subject: [PATCH 06/14] Sequencer: Reset Audio when starting playback now with faster results. Purpose is to not need to restart manually when a midi device has powered off and powered back on again --- mscore/scoreview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 91cbd1638837f..665741df71b48 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -3212,6 +3212,9 @@ void ScoreView::cmd(const char* s) if (cv->state == ViewState::NORMAL || cv->state == ViewState::NOTE_ENTRY) { // Start: resetTempSpannerVisibility(_score); + + mscore->restartAudioEngine(); + if (!_selection.isNone()) { _score->deselectAll(); // Clear on-screen keyboard: From 6365ba63b4aec914bf93cd6fb4573bd66db33dcc Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 17 Oct 2025 00:57:26 +0000 Subject: [PATCH 07/14] Sequencer: Aside: increase NDEBUG threshold of stop/wait --- mscore/seq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mscore/seq.cpp b/mscore/seq.cpp index 863af1e3683e1..5bc2d0206637d 100644 --- a/mscore/seq.cpp +++ b/mscore/seq.cpp @@ -432,7 +432,7 @@ void Seq::stopWait() sleep.wait(&mutex, 100); mutex.unlock(); #ifndef NDEBUG - Q_ASSERT(++idx <= 10); + Q_ASSERT(++idx <= 100); #endif } } From d79a318d8ffaffbbffdd894efb9b18b412b6d7da Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 17 Oct 2025 08:46:56 +0000 Subject: [PATCH 08/14] Sequencer Update: Again, use event tick not cbegin() of events with extra precaution --- mscore/seq.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/mscore/seq.cpp b/mscore/seq.cpp index 5bc2d0206637d..d57c5d16c9283 100644 --- a/mscore/seq.cpp +++ b/mscore/seq.cpp @@ -1123,6 +1123,14 @@ void Seq::collectEvents(int utick, bool viaUserNavigation) { (void) viaUserNavigation; + // Note: e3bfc9d525 "Implement background partial MIDI rendering during playback" 2019-04-23) + // allows for partial midi rendering during playback: + + if (state == Transport::PLAY && playlistChanged) { + // do not collect even while playing + return; + } + mutex.lock(); if (midiRenderFuture.isRunning()) @@ -1158,9 +1166,13 @@ void Seq::collectEvents(int utick, bool viaUserNavigation) // Why was playPos updated here? One reason is that it occurs earlier/prior to ::heartBeatTimeout, // allowing its guiPos loop in relation to playPos to be using the correct playPos at that time - if (mscore->loop()) - playPos = events.find(cs->loopInTick().ticks()); - else {;} // playPos = events.cbegin(); + // Extra precaution to allow fixing the "lose position" upon start/stop: + auto eventAtTick = (utick == 0) ? events.cbegin() : events.find(utick); + playPos = mscore->loop() ? events.find(cs->loopInTick().ticks()) : eventAtTick; + const NPlayEvent& e = playPos->second; + if (e.type() != ME_NOTEON && !e.rest()) { + playPos = mscore->loop() ? events.find(cs->loopInTick().ticks()) : events.cbegin(); + } playlistChanged = false; unmarkNotes(); From 48415413f0b0060fbec4760c6bd0920109b83f3c Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 17 Oct 2025 16:41:07 +0000 Subject: [PATCH 09/14] Fix: MIDI input should use ChordRest's staff for sequencer instrument if a single CR is selected --- libmscore/cmd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index 8cd7b0ee29a33..acd744e253b4d 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -2425,7 +2425,8 @@ bool Score::processMidiInput() if (!noteEntryMode() || entryMethod == NoteEntryMethod::REALTIME_AUTO || entryMethod == NoteEntryMethod::REALTIME_MANUAL) { - int staffIdx = selection().staffStart(); + ChordRest* cr = selection().cr(); + int staffIdx = cr ? cr->staffIdx() : selection().staffStart(); Part* p; if (staffIdx < 0 || staffIdx >= nstaves()) p = staff(0)->part(); From ebca5ef67b544dedc4e9739b895d725499c78f59 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Wed, 22 Oct 2025 17:25:18 +0000 Subject: [PATCH 10/14] Seq: heartBeatTimeout: Use event tick instead of getCurTick() to update timeSig --- mscore/seq.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/mscore/seq.cpp b/mscore/seq.cpp index d57c5d16c9283..291ee0c66a6de 100644 --- a/mscore/seq.cpp +++ b/mscore/seq.cpp @@ -1768,20 +1768,27 @@ void Seq::heartBeatTimeout() --ppos; mutex.unlock(); - ensureBufferAsync(ppos->first); - if (cs && cs->sigmap()->timesig(getCurTick()).nominal()!=prevTimeSig) { - prevTimeSig = cs->sigmap()->timesig(getCurTick()).nominal(); - emit timeSigChanged(); - } - if (cs && curTempo()!=prevTempo) { - prevTempo = curTempo(); - emit tempoChanged(); + const int utick = ppos->first; + ensureBufferAsync(utick); + + if (cs) { + auto timeSig = cs->sigmap()->timesig(utick).nominal(); // was having issues arbitrarily here after multiple repeats with using getCurTick() + if (timeSig != prevTimeSig) { + prevTimeSig = timeSig; + emit timeSigChanged(); + } + + int tempo = curTempo(); + if (tempo != prevTempo) { + prevTempo = tempo; + emit tempoChanged(); + } } QRectF r; for (;guiPos != eventsEnd; ++guiPos) { - if (guiPos->first > ppos->first) + if (guiPos->first > utick) break; if (mscore->loop()) if (guiPos->first >= cs->repeatList().tick2utick(cs->loopOutTick().ticks())) @@ -1835,7 +1842,6 @@ void Seq::heartBeatTimeout() } } } - int utick = ppos->first; int t = cs->repeatList().utick2tick(utick); mscore->currentScoreView()->moveCursor(Fraction::fromTicks(t)); mscore->setPos(Fraction::fromTicks(t)); From d8b0ffc9e7bee2fcdfc6ceaa038eb5e9b7f4c99d Mon Sep 17 00:00:00 2001 From: "J.G." Date: Tue, 4 Nov 2025 00:39:54 +0000 Subject: [PATCH 11/14] Advanced Preference: Hide file menu/toolbars/file tabs when using Full-Screen command --- global/settings/types/preferencekeys.h | 3 +++ mscore/musescore.cpp | 35 ++++++++++++++++++++++++-- mscore/preferences.cpp | 2 ++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/global/settings/types/preferencekeys.h b/global/settings/types/preferencekeys.h index a40f62ba129af..1f3ea77e336f0 100644 --- a/global/settings/types/preferencekeys.h +++ b/global/settings/types/preferencekeys.h @@ -229,6 +229,9 @@ #define PREF_UI_APP_USENEWWIZARD "ui/application/useNewWizard" #define PREF_UI_APP_BUILD_DATE_ISO "ui/application/build/date/isoFormat" #define PREF_UI_APP_AUTOHIDE_PALETTES "ui/application/palette/applyAutoHides" +#define PREF_UI_APP_FULLSCREEN_HIDES_MENU "ui/application/hideMenuOnFullscreen" +#define PREF_UI_APP_FULLSCREEN_HIDES_TOOLBARS "ui/application/hideToolbarsOnFullscreen" + #define PREF_UI_PIANO_HIGHLIGHTCOLOR "ui/piano/highlightColor" #define PREF_UI_PIANO_WHITE_KEYS_COLOR "ui/piano/keys/color/white" #define PREF_UI_PIANO_BLACK_KEYS_COLOR "ui/piano/keys/color/black" diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 3fab120afc45f..a4321cd0df090 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -1319,6 +1319,7 @@ void MuseScore::populateFileOperations() #else viewModeCombo->setFocusPolicy(Qt::TabFocus); #endif + viewModeCombo->setFixedWidth(preferences.getInt(PREF_UI_THEME_ICONWIDTH) * guiScaling); viewModeCombo->setFixedHeight(preferences.getInt(PREF_UI_THEME_ICONHEIGHT) + 8); // hack viewModeCombo->setAccessibleName(tr("View Mode")); @@ -7090,11 +7091,41 @@ void MuseScore::cmd(QAction* a, const QString& cmd) startExcerptsDialog(); else if (cmd == "fullscreen") { _fullscreen = a->isChecked(); - if (_fullscreen) + if (_fullscreen) { showFullScreen(); - else + + if (preferences.getBool(PREF_UI_APP_FULLSCREEN_HIDES_MENU)) { + // Hide Menubar + Tab Selectors + Toolbars if this adv. preference is enabled + if (QWidget* menubar = mscore->menuWidget()) { + menubar->hide(); + } + tab1->getTab()->hide(); + } + if (preferences.getBool(PREF_UI_APP_FULLSCREEN_HIDES_TOOLBARS)) { + for (QToolBar* toolbar : { cpitchTools,fotoTools,fileTools,transportTools,entryTools,colorTools,toggleTools,workspacesTools,/*voiceTools,*/ }) { + if (toolbar) { + toolbar->hide(); + } + } + } + } + else { showNormal(); + if (preferences.getBool(PREF_UI_APP_FULLSCREEN_HIDES_MENU)) { + if (QWidget* menubar = mscore->menuWidget()) { + menubar->show(); + } + tab1->getTab()->show(); + } + if (preferences.getBool(PREF_UI_APP_FULLSCREEN_HIDES_TOOLBARS)) { + for (QToolBar* toolbar : { cpitchTools,fotoTools,fileTools,transportTools,entryTools,colorTools,toggleTools,workspacesTools,/*voiceTools,*/ }) { + if (toolbar) { + toolbar->show(); + } + } + } + } #ifdef Q_OS_MAC // Qt Bug: Toolbar goes into unified mode // after switching back from fullscreen diff --git a/mscore/preferences.cpp b/mscore/preferences.cpp index ff23dba884df2..f3518eba62c6e 100644 --- a/mscore/preferences.cpp +++ b/mscore/preferences.cpp @@ -297,6 +297,8 @@ void Preferences::init(bool storeInMemoryOnly) {PREF_UI_APP_RASTER_VERTICAL, new IntPreference(2)}, {PREF_UI_APP_SHOWSTATUSBAR, new BoolPreference(true)}, {PREF_UI_APP_AUTOHIDE_PALETTES, new BoolPreference(true)}, + {PREF_UI_APP_FULLSCREEN_HIDES_MENU, new BoolPreference(false)}, + {PREF_UI_APP_FULLSCREEN_HIDES_TOOLBARS, new BoolPreference(false)}, #if defined(Q_OS_MAC) || defined(Q_OS_WIN) // use system native file dialog, Qt file dialog is very slow on Windows and Mac {PREF_UI_APP_USENATIVEDIALOGS, new BoolPreference(true)}, #else // don't use system native file dialog, this is causing issues on some Linuxes From fad9083f78bcfcfdcdf6054ed3790ff3502ce0e2 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Wed, 22 Oct 2025 09:05:52 +0000 Subject: [PATCH 12/14] Fix: Last Chord sequenced should not consider note-offs --- mscore/seq.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mscore/seq.cpp b/mscore/seq.cpp index 291ee0c66a6de..88d4a1e839d6f 100644 --- a/mscore/seq.cpp +++ b/mscore/seq.cpp @@ -600,6 +600,20 @@ void Seq::playEvent(const NPlayEvent& event, unsigned framePos) } else if (type == ME_CONTROLLER || type == ME_PITCHBEND || type == ME_AFTERTOUCH || type == ME_POLYAFTER) putEvent(event, framePos); + + // --------------------------------- + // Remember last sequenced ChordRest + // --------------------------------- + if (event.type() == ME_CHORD) { + if (auto rest = event.rest()) + rest->score()->setLastCRSequenced(rest); + } + else if (event.type() == ME_NOTEON && event.velo()) { + if (auto n = event.note()) { + auto c = n->chord(); + n->score()->setLastCRSequenced(c); + } + } } //--------------------------------------------------------- From 8dc5e48b9086e4996e9cfc270562fb6461abca51 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Tue, 28 Oct 2025 22:06:49 +0000 Subject: [PATCH 13/14] Fix: Mouse Hover was showing on multi-pages at same position --- mscore/scoreview.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 665741df71b48..fedce0663a72d 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -1670,9 +1670,9 @@ void ScoreView::drawElements(QPainter& painter, QList& el, Element* ed bool opaqueHoverColor = (MScore::hoverColor.alpha() == 255); bool hoverUnder = opaqueHoverColor; bool haveHover = MScore::hoverColorEnabled && dropTarget; - - if (haveHover && hoverUnder) { - if (state != ViewState::LASSO) { + + if (haveHover && hoverUnder && state != ViewState::LASSO) { + if (el.contains(const_cast(dropTarget))) { drawHoverHighlight(painter, *dropTarget); } } From 8d8f6924ed7657e084c975d544346f6a03bda8c7 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Wed, 22 Oct 2025 09:06:27 +0000 Subject: [PATCH 14/14] Fix: Highlight More: Slurs tick updated --- libmscore/element.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmscore/element.cpp b/libmscore/element.cpp index 6504c36fc1984..4ebf2af4d8209 100644 --- a/libmscore/element.cpp +++ b/libmscore/element.cpp @@ -668,10 +668,10 @@ QColor Element::curColor(bool isVisible, QColor normalColor) const auto sp = ss->spanner(); auto t1 = sp->tick(); auto t2 = sp->tick2(); - t2 -= Fraction::fromTicks(1); + t2 -= Fraction::fromTicks(isSlurSegment() ? 0 : 1); // let slurs remain highlighted during the final element duration if (auto playingElement = ss->score()->getLastCRSequenced()) { auto pos = playingElement->tick(); - marked = (pos >= t1 && pos < t2); + marked = (pos >= t1 && pos <= t2); } } else if (isTextBase()) {