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); 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/libmscore/cmd.cpp b/libmscore/cmd.cpp index b0ab8adbb894f..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(); @@ -3306,16 +3307,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; 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()) { 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; diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 9f87549359648..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")); @@ -3446,8 +3447,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 +3471,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 +5085,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()); @@ -6747,7 +6753,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 +6909,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 +6947,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 +7069,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(); @@ -6992,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 @@ -7007,14 +7136,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 +7194,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 +7283,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(); @@ -8999,10 +9046,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); } 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 diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 91cbd1638837f..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); } } @@ -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: diff --git a/mscore/seq.cpp b/mscore/seq.cpp index 863af1e3683e1..88d4a1e839d6f 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 } } @@ -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); + } + } } //--------------------------------------------------------- @@ -1123,6 +1137,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 +1180,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(); @@ -1756,20 +1782,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())) @@ -1823,7 +1856,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));