From 43b5036ac5cdd941fee1061c0ff0ed62bc07988c Mon Sep 17 00:00:00 2001 From: Bruno Vernay Date: Fri, 17 Aug 2018 16:55:49 +0200 Subject: [PATCH 01/49] Removing " Look in: styles" when not appropriate Palette an DrumSet namely --- mscore/file.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/mscore/file.cpp b/mscore/file.cpp index 6b20efd425eda..2e4f3b8a4f5bf 100644 --- a/mscore/file.cpp +++ b/mscore/file.cpp @@ -1309,7 +1309,6 @@ QString MuseScore::getPaletteFilename(bool open, const QString& name) restoreDialogState("loadPaletteDialog", loadPaletteDialog); loadPaletteDialog->setAcceptMode(QFileDialog::AcceptOpen); } - urls.append(QUrl::fromLocalFile(mscoreGlobalShare+"/styles")); dialog = loadPaletteDialog; } else { @@ -1471,7 +1470,6 @@ QString MuseScore::getDrumsetFilename(bool open) restoreDialogState("loadDrumsetDialog", loadDrumsetDialog); loadDrumsetDialog->setAcceptMode(QFileDialog::AcceptOpen); } - urls.append(QUrl::fromLocalFile(mscoreGlobalShare+"/styles")); dialog = loadDrumsetDialog; } else { From d556bdc3cb6a1802df5bf170a30aaf522de53348 Mon Sep 17 00:00:00 2001 From: Matt McClinch Date: Thu, 15 Nov 2018 17:03:55 -0500 Subject: [PATCH 02/49] fix #278080: Request to show empty page rather than no page for score with no content --- libmscore/layout.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 8c5d90cebb5ac..44b8fbbac21f6 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -3708,6 +3708,9 @@ void Score::doLayoutRange(int stick, int etick) _systems.clear(); qDeleteAll(pages()); pages().clear(); + LayoutContext lc; + lc.score = this; + lc.getNextPage(); return; } // qDebug("%p %d-%d %s systems %d", this, stick, etick, isMaster() ? "Master" : "Part", int(_systems.size())); From 886224063cdaf74a20e8dd58cbf36f938ebd6a29 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Tue, 4 Dec 2018 11:19:20 +0100 Subject: [PATCH 03/49] fix #278712: mscore/file.cpp and QSettings variables --- mscore/file.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mscore/file.cpp b/mscore/file.cpp index 220bd13544c30..d957c6fed5d6b 100644 --- a/mscore/file.cpp +++ b/mscore/file.cpp @@ -1696,8 +1696,10 @@ void MuseScore::exportFile() if (saveDirectory.isEmpty()) saveDirectory = preferences.getString(PREF_APP_PATHS_MYSCORES); - if (lastSaveCopyFormat.isEmpty()) - lastSaveCopyFormat = settings.value("lastSaveCopyFormat", "pdf").toString(); + if (lastSaveCopyFormat.isEmpty()) { + QSettings set; + lastSaveCopyFormat = set.value("lastSaveCopyFormat", "pdf").toString(); + } QString saveFormat = lastSaveCopyFormat; if (saveFormat.isEmpty()) @@ -1776,8 +1778,10 @@ bool MuseScore::exportParts() if (saveDirectory.isEmpty()) saveDirectory = preferences.getString(PREF_APP_PATHS_MYSCORES); - if (lastSaveCopyFormat.isEmpty()) - lastSaveCopyFormat = settings.value("lastSaveCopyFormat", "pdf").toString(); + if (lastSaveCopyFormat.isEmpty()) { + QSettings set; + lastSaveCopyFormat = set.value("lastSaveCopyFormat", "pdf").toString(); + } QString saveFormat = lastSaveCopyFormat; if (saveFormat.isEmpty()) From 0b37675892606ba3fc8960a9312f96893d929072 Mon Sep 17 00:00:00 2001 From: Martin Scotta Date: Fri, 14 Dec 2018 14:59:46 -0300 Subject: [PATCH 04/49] Add missing build variables The current Makefile does not allow to override the `BUILD_ALSA` and `BUILD_PORTMIDI` from the command-line. This change will allow developers to execute: ```sh make BUILD_ALSA=OFF BUILD_PORTMIDI=OFF ``` --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index 372dfea494d64..a98a866e8452c 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,9 @@ LABEL=""# E.g.: LABEL="Development Build" --> "MuseScore 2" becomes "MuseScore 2 BUILD_LAME="ON" # Non-free, required for MP3 support. Override with "OFF" to disable. BUILD_PULSEAUDIO="ON" # Override with "OFF" to disable. BUILD_JACK="ON" # Override with "OFF" to disable. +BUILD_ALSA="ON" # Override with "OFF" to disable. BUILD_PORTAUDIO="ON" # Override with "OFF" to disable. +BUILD_PORTMIDI="ON" # Override with "OFF" to disable. BUILD_WEBENGINE="ON" # Override with "OFF" to disable. USE_SYSTEM_FREETYPE="OFF" # Override with "ON" to enable. Requires freetype >= 2.5.2. COVERAGE="OFF" # Override with "ON" to enable. @@ -58,7 +60,9 @@ release: -DCMAKE_BUILD_NUMBER="${BUILD_NUMBER}" \ -DBUILD_LAME="${BUILD_LAME}" \ -DBUILD_PULSEAUDIO="${BUILD_PULSEAUDIO}" \ + -DBUILD_PULSEMIDI="${DBUILD_PULSEMIDI}" \ -DBUILD_JACK="${BUILD_JACK}" \ + -BUILD_ALSA="${BUILD_ALSA}" \ -DBUILD_PORTAUDIO="${BUILD_PORTAUDIO}" \ -DBUILD_WEBENGINE="${BUILD_WEBENGINE}" \ -DUSE_SYSTEM_FREETYPE="${USE_SYSTEM_FREETYPE}" \ @@ -86,7 +90,9 @@ debug: -DCMAKE_BUILD_NUMBER="${BUILD_NUMBER}" \ -DBUILD_LAME="${BUILD_LAME}" \ -DBUILD_PULSEAUDIO="${BUILD_PULSEAUDIO}" \ + -DBUILD_PULSEMIDI="${DBUILD_PULSEMIDI}" \ -DBUILD_JACK="${BUILD_JACK}" \ + -BUILD_ALSA="${BUILD_ALSA}" \ -DBUILD_PORTAUDIO="${BUILD_PORTAUDIO}" \ -DBUILD_WEBENGINE="${BUILD_WEBENGINE}" \ -DUSE_SYSTEM_FREETYPE="${USE_SYSTEM_FREETYPE}" \ From bb4caf454d48ca1bcb8af355766f83166b969955 Mon Sep 17 00:00:00 2001 From: Peter Jonas Date: Thu, 3 Oct 2019 04:53:33 +0100 Subject: [PATCH 05/49] Simplify ToolButtonMenu class Replace Types enum with a swapAction boolean. Remove the "Fixed" type since it is equivalent to having an empty list of alternative actions. --- mscore/musescore.cpp | 4 ++-- mscore/toolbuttonmenu.cpp | 37 ++++++++++++++++--------------------- mscore/toolbuttonmenu.h | 35 +++++++++++++++++------------------ 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index c36bee9f9c87a..8775c2fdbb58c 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -572,10 +572,10 @@ void MuseScore::populateNoteInputMenu() connect(noteEntryMethods, SIGNAL(triggered(QAction*)), this, SLOT(cmd(QAction*))); w = new ToolButtonMenu(tr("Note Entry Methods"), - ToolButtonMenu::TYPES::ICON_CHANGED, getAction("note-input"), noteEntryMethods, - this); + this, + false); w->setObjectName("note-entry-methods"); } else if (strncmp(s, "voice-", 6) == 0) { diff --git a/mscore/toolbuttonmenu.cpp b/mscore/toolbuttonmenu.cpp index 8b828677779eb..cee7ab5ba6a4b 100644 --- a/mscore/toolbuttonmenu.cpp +++ b/mscore/toolbuttonmenu.cpp @@ -13,24 +13,25 @@ namespace Ms { -ToolButtonMenu::ToolButtonMenu(QString str, - TYPES type, +ToolButtonMenu::ToolButtonMenu(QString name, QAction* defaultAction, QActionGroup* alternativeActions, - QWidget* parent) : AccessibleToolButton(parent, defaultAction) + QWidget* parent, + bool swapAction) + : AccessibleToolButton(parent, defaultAction) { - // if, and only if, type is ACTION_SWAPPED then the default action is also an alternative action. - Q_ASSERT((type == TYPES::ACTION_SWAPPED) == alternativeActions->actions().contains(defaultAction)); + // does the default action count as one of the alternative actions? + Q_ASSERT(swapAction == alternativeActions->actions().contains(defaultAction)); - _type = type; + _swapAction = swapAction; _alternativeActions = alternativeActions; - setMenu(new QMenu(str, this)); + setMenu(new QMenu(name, this)); menu()->setToolTipsVisible(true); setPopupMode(QToolButton::MenuButtonPopup); - if (_type != TYPES::ACTION_SWAPPED) { + if (!swapAction) { addAction(defaultAction); addSeparator(); } @@ -45,11 +46,11 @@ ToolButtonMenu::ToolButtonMenu(QString str, connect(_alternativeActions, SIGNAL(triggered(QAction*)), this, SLOT(handleAlternativeAction(QAction*))); - if (_type != TYPES::ACTION_SWAPPED) { + if (!swapAction) { + // select first alternative action and use its icon for the default action QAction* a = _alternativeActions->actions().first(); a->setChecked(true); - if (_type == TYPES::ICON_CHANGED) - changeIcon(a); + switchIcon(a); } } @@ -57,16 +58,10 @@ void ToolButtonMenu::handleAlternativeAction(QAction* a) { Q_ASSERT(_alternativeActions->actions().contains(a)); - switch (_type) { - case TYPES::FIXED: - break; - case TYPES::ICON_CHANGED: - changeIcon(a); - break; - case TYPES::ACTION_SWAPPED: - setDefaultAction(a); - break; - } + if (_swapAction) + setDefaultAction(a); + else + switchIcon(a); QAction* def = defaultAction(); diff --git a/mscore/toolbuttonmenu.h b/mscore/toolbuttonmenu.h index a903c962fee43..3673a36ccb2bb 100644 --- a/mscore/toolbuttonmenu.h +++ b/mscore/toolbuttonmenu.h @@ -20,45 +20,44 @@ namespace Ms { // ToolButtonMenu // ============== // This creates a button with an arrow next to it. Clicking the button triggers the default -// action, while pressing the arrow brings up a menu of alternative actions and/or other -// actions. Selecting an alternative action has some effect on the default action's icon -// and/or its behavior. Other actions have no effect on the default action. +// action, while pressing the arrow brings up a menu of alternative actions. Selecting an +// alternative action triggers it and also has some effect on the default action. +// +// The menu may contain: +// - Any number of alternative actions in addition to the default action. +// - Other actions that do not affect the default action. +// - These are not considered "alternative actions" for our purposes. +// +// The effect of selecting an alternative action is determined by the swapAction boolean. +// TRUE: The selected action replaces the default action (it becomes the new default). +// FALSE: The default action remains unchanged, but its icon is updated to match the +// icon of the selected alternative action. //--------------------------------------------------------- class ToolButtonMenu : public AccessibleToolButton { // : public QToolButton { Q_OBJECT - public: - enum class TYPES { - // What happens to the default action if an alternative (non-default) action is triggered? - FIXED, // default action is also triggered but is otherwise unchanged. - ICON_CHANGED, // default action is triggered and its icon is modified and/or set to that of the triggering action. - ACTION_SWAPPED // default action is not triggered. Triggering action (and its icon) become the new default. - }; - private: - TYPES _type; QActionGroup* _alternativeActions; + bool _swapAction; public: ToolButtonMenu(QString str, - TYPES type, QAction* defaultAction, QActionGroup* alternativeActions, - QWidget* parent); + QWidget* parent = nullptr, + bool swapAction = true); void addAction(QAction* a) { menu()->addAction(a); } void addSeparator() { menu()->addSeparator(); } void addActions(QList actions) { for (QAction* a : actions) addAction(a); } private: void switchIcon(QAction* a) { - Q_ASSERT(_type == TYPES::ICON_CHANGED && _alternativeActions->actions().contains(a)); + Q_ASSERT(!_swapAction); + Q_ASSERT(_alternativeActions->actions().contains(a)); defaultAction()->setIcon(a->icon()); } - protected: - virtual void changeIcon(QAction* a) { switchIcon(a); } - private slots: void handleAlternativeAction(QAction* a); From 8cf16ac708561670f47809d2d2fb6c3e77638d3e Mon Sep 17 00:00:00 2001 From: Peter Jonas Date: Thu, 3 Oct 2019 06:16:12 +0100 Subject: [PATCH 06/49] Make note input ToolButtonMenu accessible for keyboard users --- mscore/toolbuttonmenu.cpp | 15 +++++++++++++++ mscore/toolbuttonmenu.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/mscore/toolbuttonmenu.cpp b/mscore/toolbuttonmenu.cpp index cee7ab5ba6a4b..5dd23ffef1554 100644 --- a/mscore/toolbuttonmenu.cpp +++ b/mscore/toolbuttonmenu.cpp @@ -69,4 +69,19 @@ void ToolButtonMenu::handleAlternativeAction(QAction* a) def->trigger(); } +void ToolButtonMenu::keyPressEvent(QKeyEvent* event) + { + switch(event->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Space: + menu()->exec(this->mapToGlobal(QPoint(0, size().height()))); + menu()->setFocus(); + menu()->setActiveAction(defaultAction()); + break; + default: + AccessibleToolButton::keyPressEvent(event); + } + } + } // namespace Ms diff --git a/mscore/toolbuttonmenu.h b/mscore/toolbuttonmenu.h index 3673a36ccb2bb..078765d1964de 100644 --- a/mscore/toolbuttonmenu.h +++ b/mscore/toolbuttonmenu.h @@ -61,6 +61,9 @@ class ToolButtonMenu : public AccessibleToolButton { // : public QToolButton { private slots: void handleAlternativeAction(QAction* a); + protected: + void keyPressEvent(QKeyEvent* event) override; + }; } // namespace Ms From 2ed4a7e86ce8c91c851c756c242ce6fbb06329c8 Mon Sep 17 00:00:00 2001 From: Peter Jonas Date: Thu, 26 Dec 2019 20:25:11 +0000 Subject: [PATCH 07/49] fix #297040: Palette keyboard navigation +collect_artifacts Implements standard keyboard navigation for an item view / tree view as demonstrated by QAbstractItemView and QTreeView classes. Also changes how elements are displayed as necessary to indicate the different kinds of selection (e.g. when current item is not selected). - Adds blue outline for current item (selected items have blue fill). - Changing item also selects it (unless Ctrl is held). - More button behaves like a normal item for navigation purposes New keyboard shortcuts: - Asterisk (*) key expands or collapses all items - Menu key (or [Ctrl+]Shift+F10) opens context menus - Press any letter key to jump to palette starting with that letter Various improvements to screen reader output: - Palette names end in "palette" to distinguish from elements - Says when palettes are expanded - Says how many elements in palette, and palettes in view - Says when palette elements are selected --- mscore/palette/palettemodel.cpp | 4 +- mscore/qml/palettes/Palette.qml | 324 +++++++++++++------ mscore/qml/palettes/PaletteTree.qml | 236 ++++++++++---- mscore/qml/palettes/PalettesWidget.qml | 2 +- mscore/qml/palettes/PalettesWidgetHeader.qml | 21 +- mscore/qml/palettes/TreePaletteHeader.qml | 17 +- 6 files changed, 443 insertions(+), 161 deletions(-) diff --git a/mscore/palette/palettemodel.cpp b/mscore/palette/palettemodel.cpp index 9e227bfe95faa..1d8a8bf45eecf 100644 --- a/mscore/palette/palettemodel.cpp +++ b/mscore/palette/palettemodel.cpp @@ -253,8 +253,10 @@ QVariant PaletteTreeModel::data(const QModelIndex& index, int role) const if (const PalettePanel* pp = findPalettePanel(index)) { switch (role) { case Qt::DisplayRole: - case Qt::AccessibleTextRole: return pp->translatedName(); + case Qt::ToolTipRole: + case Qt::AccessibleTextRole: + return QString("%1 palette").arg(pp->translatedName()); case VisibleRole: return pp->visible(); case CustomRole: diff --git a/mscore/qml/palettes/Palette.qml b/mscore/qml/palettes/Palette.qml index 13cfbc7e740a2..41914000c2f03 100644 --- a/mscore/qml/palettes/Palette.qml +++ b/mscore/qml/palettes/Palette.qml @@ -33,8 +33,6 @@ GridView { interactive: height < contentHeight // TODO: check if it helps on Mac boundsBehavior: Flickable.StopAtBounds - keyNavigationEnabled: true - property size cellSize property bool drawGrid: false property bool showMoreButton: false @@ -107,7 +105,7 @@ GridView { StyledButton { id: moreButton visible: showMoreButton - activeFocusOnTab: parent.currentItem === paletteTree.currentTreeItem + activeFocusOnTab: this === paletteTree.currentTreeItem highlighted: visualFocus || hovered @@ -118,7 +116,19 @@ GridView { color: globalStyle.voice1Color opacity: moreButton.down ? 0.4 : (moreButton.highlighted ? 0.2 : 0.0) } + border.color: moreButton.activeFocus ? "lightblue" : "transparent" // show current item + border.width: 2 + } + + onActiveFocusChanged: { + if (activeFocus) { + paletteTree.currentTreeItem = this; + + if (mscore.keyboardModifiers() === Qt.NoModifier) + paletteView.selectionModel.clearSelection(); + } } + anchors.bottom: parent.bottom anchors.right: parent.right width: { @@ -139,6 +149,29 @@ GridView { visualFocusTextColor: "darkblue" onClicked: paletteView.moreButtonClicked() + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Up: + focusPreviousItem(); + break; + case Qt.Key_Down: + paletteTree.focusNextItem(false); + break; + default: + return; // don't accept event + } + event.accepted = true; + } + + function focusPreviousItem() { + if (paletteView.count == 0) { + paletteTree.currentItem.forceActiveFocus(); + } else { + paletteView.currentIndex = paletteView.count - 1 + paletteView.currentItem.forceActiveFocus(); + } + } } PlaceholderManager { @@ -334,14 +367,101 @@ GridView { Utils.removeSelectedItems(paletteController, selectionModel, paletteRootIndex); } - Keys.onDeletePressed: { - removeSelectedCells(); + function focusNextItem(flags) { + if (flags === undefined) + flags = ItemSelectionModel.ClearAndSelect; + + if (currentIndex == count - 1) { + if (moreButton.visible) + moreButton.forceActiveFocus(); + else + paletteTree.focusNextItem(false); + } else { + currentIndex++; // next grid item + } + } + + function focusPreviousItem(flags) { + if (flags === undefined) + flags = ItemSelectionModel.ClearAndSelect; + + if (currentIndex == 0) + paletteTree.currentItem.forceActiveFocus(); + else + currentIndex--; // previous grid item + } + + function focusFirstItem() { + if (count == 0 && moreButton.visible) { + moreButton.forceActiveFocus(); + } else { + currentIndex = 0; + currentItem.forceActiveFocus(); + } + } + + function focusLastItem() { + if (moreButton.visible) { + moreButton.forceActiveFocus(); + } else { + currentIndex = count - 1; + currentItem.forceActiveFocus(); + } + } + + function focusNextMatchingItem(str) { + const nextIndex = (currentIndex === count - 1) ? 0 : currentIndex + 1; + const modelIndex = paletteModel.index(nextIndex, 0, paletteRootIndex); + const matchedIndexList = paletteModel.match(modelIndex, Qt.DisplayRole, str); + if (matchedIndexList.length) { + currentIndex = matchedIndexList[0].row; + currentItem.forceActiveFocus(); + } + } + + function updateSelection(itemPressed) { + if (itemPressed === undefined) + itemPressed = false; // reason function was called + + const modifiers = mscore.keyboardModifiers(); + const shiftHeld = modifiers & Qt.ShiftModifier; + const ctrlHeld = modifiers & Qt.ControlModifier; + const herePreviously = selectionModel.currentIndex.parent === paletteRootIndex; + + if (!ctrlHeld || !herePreviously) + selectionModel.clearSelection(); + + if (shiftHeld && herePreviously) + selectionModel.selectRange(currentItem.modelIndex); + else if (ctrlHeld) + selectionModel.setCurrentIndex(currentItem.modelIndex, itemPressed ? ItemSelectionModel.Toggle : ItemSelectionModel.NoUpdate); + else + selectionModel.setCurrentIndex(currentItem.modelIndex, ItemSelectionModel.Select); } + Keys.onPressed: { - if (event.key == Qt.Key_Backspace) { - removeSelectedCells(); - event.accepted = true; + switch (event.key) { + case Qt.Key_Up: + focusPreviousItem(); + break; + case Qt.Key_Down: + focusNextItem(); + break; + case Qt.Key_Left: + paletteTree.currentItem.forceActiveFocus(); + break; + case Qt.Key_Right: + if (moreButton.visible) + moreButton.forceActiveFocus(); + break; + case Qt.Key_Backspace: + case Qt.Key_Delete: + removeSelectedCells(); + break; + default: + return; // don't accept event } + event.accepted = true; } model: DelegateModel { @@ -357,8 +477,10 @@ GridView { property var parentModelIndex: paletteView.paletteRootIndex onActiveFocusChanged: { - if (activeFocus) + if (activeFocus) { paletteTree.currentTreeItem = this; + paletteView.updateSelection(false); + } } opacity: enabled ? 1.0 : 0.3 @@ -370,7 +492,7 @@ GridView { property bool selected: (paletteView.selectionModel && paletteView.selectionModel.hasSelection) ? paletteView.isSelected(modelIndex) : false // hasSelection is to trigger property bindings if selection changes, see https://doc.qt.io/qt-5/qml-qtqml-models-itemselectionmodel.html#hasSelection-prop - highlighted: activeFocus || hovered || !!model.cellActive + highlighted: visualFocus || hovered || !!model.cellActive width: paletteView.cellWidth height: paletteView.cellHeight @@ -387,36 +509,48 @@ GridView { } background: Rectangle { - id: cellBackground - - color: globalStyle.voice1Color - opacity: 0.0 + color: "transparent" + border.color: paletteCell.activeFocus ? "lightblue" : "transparent" // show current item + border.width: 2 width: ((paletteCell.rowIndex + 1) % paletteView.ncolumns) ? paletteView.cellWidth : paletteView.lastColumnCellWidth - states: [ + Rectangle { + id: cellBackground + anchors.fill: parent + color: globalStyle.voice1Color + opacity: 0.0 + } + } - State { - name: "SELECTED" - when: paletteCell.selected + onStateChanged: { + console.debug("STATE CHANGED " + state) + } - PropertyChanges { target: cellBackground; opacity: 0.5 } - }, + states: [ + // Note: if "when" is true for multiple states then + // the first state listed here takes precendence. - State { - name: "PRESSED" - when: paletteCellDragArea.pressed + State { + name: "PRESSED" + when: leftClickArea.pressed - PropertyChanges { target: cellBackground; opacity: 0.75 } - }, + PropertyChanges { target: cellBackground; opacity: 0.75 } + }, - State { - name: "HOVERED" - when: paletteCell.highlighted && !paletteCell.selected + State { + name: "SELECTED" + when: selected - PropertyChanges { target: cellBackground; opacity: 0.2 } - } - ] - } + PropertyChanges { target: cellBackground; opacity: 0.5 } + }, + + State { + name: "HOVERED" + when: highlighted + + PropertyChanges { target: cellBackground; opacity: 0.2 } + } + ] readonly property var toolTip: model.toolTip @@ -428,74 +562,59 @@ GridView { mscore.tooltip.item = null; } - text: model.accessibleText - // TODO: these may be needed for support of other screenreaders - //Accessible.name: model.accessibleText - //Accessible.description: model.accessibleText + text: model.accessibleText; // Accessible.name is ignored for some reason + Accessible.selectable: true; + Accessible.selected: selected; - onClicked: { - if (paletteView.paletteController.applyPaletteElement(paletteCell.modelIndex, mscore.keyboardModifiers())) { - paletteView.selectionModel.setCurrentIndex(paletteCell.modelIndex, ItemSelectionModel.Current); - return; - } - - forceActiveFocus(); - - paletteView.currentIndex = index; - - const selection = paletteView.selectionModel; - - if (selection) { - const modifiers = mscore.keyboardModifiers(); - const rootIndex = paletteView.paletteRootIndex; - - if (selection.currentIndex.parent != rootIndex) - selection.clearSelection(); - - if (modifiers & Qt.ShiftModifier && selection.currentIndex.parent == rootIndex) { - const model = paletteView.paletteModel; - const firstRow = selection.currentIndex.row; - const lastRow = paletteCell.rowIndex; - const step = firstRow < lastRow ? 1 : -1; - const endRow = lastRow + step; - for (var row = firstRow; row != endRow; row += step) { - const idx = model.index(row, 0, rootIndex); - selection.select(idx, ItemSelectionModel.Select); - } - // update current index - selection.setCurrentIndex(idx, ItemSelectionModel.Current); - - } else { - var cmd = selected ? ItemSelectionModel.Toggle : ItemSelectionModel.ClearAndSelect; - if (modifiers & Qt.ControlModifier) - cmd = ItemSelectionModel.Toggle; - selection.setCurrentIndex(modelIndex, cmd); - } + Keys.onPressed: { + const shiftHeld = event.modifiers & Qt.ShiftModifier; + const ctrlHeld = event.modifiers & Qt.ControlModifier; + switch (event.key) { + case Qt.Key_Space: + paletteView.updateSelection(true); + break; + case Qt.Key_Enter: + case Qt.Key_Return: + paletteView.selectionModel.setCurrentIndex(modelIndex, ItemSelectionModel.ClearAndSelect); + paletteView.paletteController.applyPaletteElement(modelIndex, mscore.keyboardModifiers()); + break; + case Qt.Key_F10: + if (!shiftHeld) + return; + // fallthrough + case Qt.Key_Menu: + showCellMenu(); + break; + default: + if (event.modifiers === Qt.NoModifier && event.text.match(/\w/) !== null) + paletteView.focusNextMatchingItem(event.text); + else + return; // don't accept event } + event.accepted = true; } - onDoubleClicked: {} - MouseArea { - id: paletteCellDragArea + id: leftClickArea anchors.fill: parent drag.target: this - onPressed: icon.grabToImage(function(result) { - parent.Drag.imageSource = result.url - dragDropReorderTimer.restart(); - }) + onPressed: { + paletteView.currentIndex = paletteCell.rowIndex; + paletteCell.forceActiveFocus(); + paletteView.updateSelection(true); + paletteCell.beginDrag(); + } - onClicked: parent.onClicked(mouse) - onDoubleClicked: parent.onDoubleClicked(mouse) - } + onClicked: { + if (paletteView.paletteController.applyPaletteElement(paletteCell.modelIndex, mscore.keyboardModifiers())) + paletteView.selectionModel.setCurrentIndex(paletteCell.modelIndex, ItemSelectionModel.Current); + } - Keys.onPressed: { - if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + onDoubleClicked: { const index = paletteCell.modelIndex; paletteView.selectionModel.setCurrentIndex(index, ItemSelectionModel.Current); - paletteView.paletteController.applyPaletteElement(index, mscore.keyboardModifiers()); - event.accepted = true; + paletteView.paletteController.applyPaletteElement(index, mouse.modifiers); } } @@ -504,14 +623,10 @@ GridView { anchors.fill: parent acceptedButtons: Qt.RightButton - onClicked: { - contextMenu.modelIndex = paletteCell.modelIndex; - contextMenu.canEdit = paletteView.paletteController.canEdit(paletteView.paletteRootIndex); - contextMenu.popup(); - } + onClicked: showCellMenu(true) } - Drag.active: paletteCellDragArea.drag.active + Drag.active: leftClickArea.drag.active Drag.dragType: Drag.Automatic Drag.supportedActions: Qt.CopyAction | (model.editable ? Qt.MoveAction : 0) Drag.mimeData: Drag.active ? mimeData : {} @@ -548,6 +663,27 @@ GridView { } // Drag.hotSpot: Qt.point(64, 0) // TODO + function beginDrag() { + icon.grabToImage(function(result) { + Drag.imageSource = result.url + dragDropReorderTimer.restart(); + }) + } + + function showCellMenu(useCursorPos) { + if (useCursorPos === undefined) + useCursorPos = false; + contextMenu.modelIndex = modelIndex; + contextMenu.canEdit = paletteView.paletteController.canEdit(paletteView.paletteRootIndex); + if (useCursorPos) + contextMenu.popup(); + else { + contextMenu.x = x + width; + contextMenu.y = y; + contextMenu.open(); + } + } + Connections { // force not hiding palette cell if it is being dragged to a score enabled: paletteCell.paletteDrag diff --git a/mscore/qml/palettes/PaletteTree.qml b/mscore/qml/palettes/PaletteTree.qml index 7b004bb932064..0046baa0d8ec3 100644 --- a/mscore/qml/palettes/PaletteTree.qml +++ b/mscore/qml/palettes/PaletteTree.qml @@ -26,10 +26,9 @@ import "utils.js" as Utils ListView { id: paletteTree - Accessible.role: Accessible.Tree // makes NVDA say "TreeView" + Accessible.name: qsTr("Palettes Tree, contains %n palettes", "", count) - keyNavigationEnabled: true - activeFocusOnTab: true + activeFocusOnTab: true // allow focus even when empty property PaletteWorkspace paletteWorkspace property var paletteModel: paletteWorkspace ? paletteWorkspace.mainPaletteModel : null @@ -54,6 +53,7 @@ ListView { } property bool enableAnimations: true + property int expandDuration: enableAnimations ? 150 : 0 // duration of expand / collapse animations function insertCustomPalette(idx) { if (paletteTree.paletteController.insertNewItem(paletteTreeDelegateModel.rootIndex, idx)) @@ -63,6 +63,18 @@ ListView { ItemSelectionModel { id: paletteSelectionModel model: paletteTree.paletteModel + + function selectRange(endIndex) { + const firstRow = currentIndex.row; + const lastRow = endIndex.row; + const parentIndex = endIndex.parent; + const step = firstRow < lastRow ? 1 : -1; + const endRow = lastRow + step; + for (var row = firstRow; row !== endRow; row += step) { + const idx = paletteTree.paletteModel.index(row, 0, parentIndex); + select(idx, ItemSelectionModel.Select); + } + } } function applyCurrentElement() { @@ -102,40 +114,38 @@ ListView { Utils.removeSelectedItems(paletteController, paletteSelectionModel, parentIndex); } - Keys.onDeletePressed: { - expandedPopupIndex = null; - removeSelectedItems(); - } Keys.onPressed: { - if (event.key == Qt.Key_Backspace) { - expandedPopupIndex = null; - removeSelectedItems(); - event.accepted = true; - } else if (event.key == Qt.Key_Home) { - positionViewAtBeginning(); - event.accepted = true; - } else if (event.key == Qt.Key_End) { - positionViewAtEnd(); - event.accepted = true; - } else if (event.key == Qt.Key_PageUp) { - var idx = indexAt(contentX, contentY); - if (idx < 0) - idx = 0; - if (idx > 0 && itemAt(contentX, contentY).height > height) - contentY -= height; - else - positionViewAtIndex(idx, ListView.End); - event.accepted = true; - } else if (event.key == Qt.Key_PageDown) { - var idx = indexAt(contentX, contentY + height); - if (idx < 0) - idx = count - 1; - if (idx < count - 1 && itemAt(contentX, contentY + height).height > height) - contentY += height; - else - positionViewAtIndex(idx, ListView.Beginning); - event.accepted = true; + switch (event.key) { + case Qt.Key_Down: + focusNextItem(); + break; + case Qt.Key_Up: + focusPreviousItem(); + break; + case Qt.Key_Home: + focusFirstItem(); + break; + case Qt.Key_End: + focusLastItem(); + break; + case Qt.Key_PageUp: + focusPreviousPageItem(); + break; + case Qt.Key_PageDown: + focusNextPageItem(); + break; + case Qt.Key_Backspace: + case Qt.Key_Delete: + expandedPopupIndex = null; + removeSelectedItems(); + break; + case Qt.Key_Asterisk: + expandCollapseAll(null); + break; + default: + return; // don't accept event } + event.accepted = true; } displaced: Transition { @@ -163,20 +173,117 @@ ListView { return { display: "", gridSize: Qt.size(1, 1), drawGrid: false, custom: false, editable: false, expanded: false }; } - function focusFirstItem() { - currentIndex = 0; - if (filter.length) // on searching jump directly to the found cells + function focusNextItem(includeChildren) { + if (includeChildren === undefined) // https://stackoverflow.com/a/44128406 + includeChildren = true; + + if (includeChildren && currentItem.expanded) { currentItem.focusFirstItem(); + return; + } + + if (currentIndex == count - 1) + return; // no next item + + incrementCurrentIndex(); + currentItem.forceActiveFocus(); + positionViewAtIndex(currentIndex, ListView.Contain); + } + + function focusPreviousItem(includeChildren) { + if (includeChildren === undefined) // https://stackoverflow.com/a/44128406 + includeChildren = true; + + if (currentIndex == 0) + return; // no previous item + + decrementCurrentIndex(); + + if (includeChildren && currentItem.expanded) + currentItem.focusLastItem(); else currentItem.forceActiveFocus(); + + positionViewAtIndex(currentIndex, ListView.Contain); + } + + function focusNextPageItem() { + if (currentIndex < count - 1) { + currentIndex++; // move by at least one item + // try to keep going, but new item must stay entirely in view + var distance = currentItem.height; + while (currentIndex < count - 1) { + currentIndex++; // try another + distance += currentItem.height; + if (distance > height) { + currentIndex--; // too far, go back one + break; + } + } + } + currentItem.forceActiveFocus(); + positionViewAtIndex(currentIndex, ListView.Contain); + } + + function focusPreviousPageItem() { + if (currentIndex > 0) { + currentIndex--; // move by at least one item + // try to keep going, but new item must stay entirely in view + var distance = currentItem.height; + while (currentIndex > 0) { + currentIndex--; // try another + distance += currentItem.height; + if (distance > height) { + currentIndex++; // too far, go back one + break; + } + } + } + currentItem.forceActiveFocus(); + positionViewAtIndex(currentIndex, ListView.Contain); + } + + function focusFirstItem() { + currentIndex = 0; + currentItem.forceActiveFocus(); + positionViewAtIndex(currentIndex, ListView.Contain); } function focusLastItem() { currentIndex = count - 1; - if (filter.length) // on searching jump directly to the found cells + if (currentItem.expanded) currentItem.focusLastItem(); else currentItem.forceActiveFocus(); + positionViewAtIndex(currentIndex, ListView.Contain); + } + + function focusNextMatchingItem(str) { + const nextIndex = (currentIndex < count - 1) ? currentIndex + 1 : 0; + const modelIndex = paletteModel.index(nextIndex, 0); + const matchedIndexList = paletteModel.match(modelIndex, Qt.DisplayRole, str); + if (matchedIndexList.length) { + currentIndex = matchedIndexList[0].row; + currentItem.forceActiveFocus(); + positionViewAtIndex(currentIndex, ListView.Contain); + } + } + + function expandCollapseAll(expand) { + console.assert([true, false, null].indexOf(expand) !== -1, "Invalid value for expand: " + expand); + // expand = true - expand all + // false - collapse all + // null - decide based on current state + if (expand === null) { + // if any are collapsed then expand all, otherwise collapse all + const startIndex = paletteModel.index(0, 0); + const collapsedIndexList = paletteModel.match(startIndex, PaletteTreeModel.PaletteExpandedRole, false); + expand = !!collapsedIndexList.length; + } + for (var idx = 0; idx < count; idx++) { + const paletteIndex = paletteModel.index(idx, 0); + paletteModel.setData(paletteIndex, expand, PaletteTreeModel.PaletteExpandedRole); + } } // set highlight color for selected palette depending on using light or dark mode @@ -204,19 +311,26 @@ ListView { } function focusFirstItem() { - mainPalette.currentIndex = 0; - mainPalette.currentItem.forceActiveFocus(); + mainPalette.focusFirstItem(); } function focusLastItem() { - mainPalette.currentIndex = mainPalette.count - 1; - mainPalette.currentItem.forceActiveFocus(); + mainPalette.focusLastItem(); } property bool expanded: filter.length || model.expanded function toggleExpand() { model.expanded = !expanded } + Timer { + id: expandTimer + interval: expandDuration + 50 // allow extra grace period + onTriggered: paletteTree.positionViewAtIndex(index, ListView.Contain) + } + onExpandedChanged: { + if (ListView.isCurrentItem && !filter.length) + expandTimer.restart(); + } property bool selected: paletteSelectionModel.hasSelection ? paletteSelectionModel.isSelected(modelIndex) : false onClicked: { @@ -258,28 +372,42 @@ ListView { Keys.onPressed: { switch (event.key) { case Qt.Key_Right: - if (expanded) - mainPalette.focus = true; - else + case Qt.Key_Plus: + if (!expanded) toggleExpand(); + else if (event.key === Qt.Key_Right) + focusFirstItem(); break; case Qt.Key_Left: - if (expanded && !mainPalette.focus) + case Qt.Key_Minus: + if (expanded) toggleExpand(); - focus = true; break; case Qt.Key_Space: case Qt.Key_Enter: case Qt.Key_Return: toggleExpand(); break; + case Qt.Key_F10: + if (!(event.modifiers & Qt.ShiftModifier)) + return; + // fallthrough + case Qt.Key_Menu: + paletteHeader.showPaletteMenu(); + break; default: - return; // don't accept event + if (event.modifiers === Qt.NoModifier && event.text.match(/\w/) !== null) + paletteTree.focusNextMatchingItem(event.text); + else + return; // don't accept event } event.accepted = true; } - text: model.display + text: filter.length ? qsTr("%1, contains %n matching elements", "palette", mainPalette.count).arg(model.accessibleText) + : model.expanded ? qsTr("%1 expanded", "tree item not collapsed").arg(model.accessibleText) + : model.accessibleText + Accessible.role: Accessible.TreeItem width: parent.width @@ -354,14 +482,14 @@ ListView { Transition { from: "collapsed"; to: "expanded" enabled: paletteTree.enableAnimations - NumberAnimation { target: mainPaletteContainer; property: "height"; from: 0; to: mainPaletteContainer.implicitHeight; easing.type: Easing.OutCubic; duration: 150 } + NumberAnimation { target: mainPaletteContainer; property: "height"; from: 0; to: mainPaletteContainer.implicitHeight; easing.type: Easing.OutCubic; duration: paletteTree.expandDuration } }, Transition { from: "expanded"; to: "collapsed" enabled: paletteTree.enableAnimations SequentialAnimation { PropertyAction { target: mainPaletteContainer; property: "visible"; value: true } // temporarily set palette visible to animate it being hidden - NumberAnimation { target: mainPaletteContainer; property: "height"; from: mainPaletteContainer.implicitHeight; to: 0; easing.type: Easing.OutCubic; duration: 150 } + NumberAnimation { target: mainPaletteContainer; property: "height"; from: mainPaletteContainer.implicitHeight; to: 0; easing.type: Easing.OutCubic; duration: paletteTree.expandDuration } PropertyAction { target: mainPaletteContainer; property: "visible"; value: false } // make palette invisible again PropertyAction { target: mainPaletteContainer; property: "height"; value: mainPaletteContainer.implicitHeight } // restore the height binding } @@ -376,7 +504,7 @@ ListView { opacity: enabled ? 1 : 0.3 expanded: control.expanded hovered: control.hovered - text: control.text + text: model.display hidePaletteElementVisible: { return !control.selected && control.expanded && paletteSelectionModel.hasSelection && paletteSelectionModel.columnIntersectsSelection(0, control.modelIndex) @@ -471,7 +599,7 @@ ListView { cellSize: control.cellSize drawGrid: control.drawGrid - paletteName: control.text + paletteName: model.display paletteIsCustom: model.custom paletteEditingEnabled: model.editable diff --git a/mscore/qml/palettes/PalettesWidget.qml b/mscore/qml/palettes/PalettesWidget.qml index bb7f6311b3966..b4798d858c489 100644 --- a/mscore/qml/palettes/PalettesWidget.qml +++ b/mscore/qml/palettes/PalettesWidget.qml @@ -42,7 +42,7 @@ Item { paletteTree.applyCurrentElement(); } - FocusChainBreak {} + FocusChainBreak { id: focusBreaker } PalettesWidgetHeader { id: palettesWidgetHeader diff --git a/mscore/qml/palettes/PalettesWidgetHeader.qml b/mscore/qml/palettes/PalettesWidgetHeader.qml index e17da721e532b..262b13fe3b499 100644 --- a/mscore/qml/palettes/PalettesWidgetHeader.qml +++ b/mscore/qml/palettes/PalettesWidgetHeader.qml @@ -48,11 +48,22 @@ Item { anchors.right: parent.right placeholderText: qsTr("Search") - //TODO: in the future we may wish these values to differ - //Accessible.name: qsTr("Search") - Accessible.name: placeholderText font: globalStyle.font + onTextChanged: resultsTimer.restart() + onActiveFocusChanged: { + resultsTimer.stop(); + Accessible.name = qsTr("Palette Search") + } + + Timer { + id: resultsTimer + interval: 500 + onTriggered: { + parent.Accessible.name = parent.text.length === 0 ? qsTr("Palette Search") : qsTr("%n palettes match", "", paletteTree.count); + } + } + color: globalStyle.text background: Rectangle { @@ -61,8 +72,7 @@ Item { } KeyNavigation.tab: paletteTree.currentTreeItem - KeyNavigation.up: paletteTree - KeyNavigation.down: paletteTree + Keys.onDownPressed: paletteTree.focusFirstItem(); Keys.onUpPressed: paletteTree.focusLastItem(); @@ -78,6 +88,7 @@ Item { visible: searchTextInput.text.length && searchTextInput.width > 2 * width flat: true onClicked: searchTextInput.clear() + activeFocusOnTab: false // don't annoy keyboard users tabbing to palette (they can use Ctrl+A, Delete to clear search) padding: 4 diff --git a/mscore/qml/palettes/TreePaletteHeader.qml b/mscore/qml/palettes/TreePaletteHeader.qml index 4b7f59f3b8274..10eaac7662123 100644 --- a/mscore/qml/palettes/TreePaletteHeader.qml +++ b/mscore/qml/palettes/TreePaletteHeader.qml @@ -47,6 +47,12 @@ Item { implicitHeight: paletteExpandArrow.height implicitWidth: paletteExpandArrow.implicitWidth + textItem.implicitWidth + paletteHeaderMenuButton.implicitWidth + 8 // 8 for margins + function showPaletteMenu() { + paletteHeaderMenu.x = paletteHeaderMenuButton.x + paletteHeaderMenuButton.width - paletteHeaderMenu.width; + paletteHeaderMenu.y = paletteHeaderMenuButton.y; + paletteHeaderMenu.open(); + } + StyledToolButton { id: paletteExpandArrow z: 1000 @@ -94,6 +100,10 @@ Item { // icon.source: "icons/delete.png" text: qsTr("Remove element") visible: paletteHeader.hidePaletteElementVisible && paletteHeader.editingEnabled + activeFocusOnTab: mainPalette.currentItem === paletteTree.currentTreeItem + + KeyNavigation.backtab: mainPalette.currentItem + KeyNavigation.tab: focusBreaker onHoveredChanged: { if (hovered) { @@ -130,12 +140,7 @@ Item { text: qsTr("Palette menu") // used by screen readers (they ignore Accessible.name for buttons) - onClicked: { - paletteHeaderMenu.x = paletteHeaderMenuButton.x + paletteHeaderMenuButton.width - paletteHeaderMenu.width; - paletteHeaderMenu.y = paletteHeaderMenuButton.y; -// paletteHeaderMenu.y = paletteHeaderMenuButton.y + paletteHeaderMenuButton.height; - paletteHeaderMenu.open(); - } + onClicked: showPaletteMenu() } MouseArea { From 71e0623def0666893239d156410f5bfe25137c3d Mon Sep 17 00:00:00 2001 From: MarcSabatella Date: Mon, 27 Jan 2020 14:29:09 -0700 Subject: [PATCH 08/49] add accessible names & labels --- mscore/inspector/inspector_element.ui | 6 ++++++ mscore/inspector/inspector_note.ui | 6 ++++++ mscore/inspector/offset_select.ui | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/mscore/inspector/inspector_element.ui b/mscore/inspector/inspector_element.ui index d604f1000901e..427d626c0ac0e 100644 --- a/mscore/inspector/inspector_element.ui +++ b/mscore/inspector/inspector_element.ui @@ -132,6 +132,9 @@ Minimum distance: + + minDistance + @@ -295,6 +298,9 @@ 0 + + Minimum distance + sp diff --git a/mscore/inspector/inspector_note.ui b/mscore/inspector/inspector_note.ui index fecffe426767f..2ef673f58ff47 100644 --- a/mscore/inspector/inspector_note.ui +++ b/mscore/inspector/inspector_note.ui @@ -555,6 +555,9 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + velocity + @@ -565,6 +568,9 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + tuning + diff --git a/mscore/inspector/offset_select.ui b/mscore/inspector/offset_select.ui index 2a7ef8b2f5bcf..0044276ffe55d 100644 --- a/mscore/inspector/offset_select.ui +++ b/mscore/inspector/offset_select.ui @@ -23,6 +23,9 @@ X: + + xVal + @@ -97,6 +100,9 @@ Y: + + yVal + From a44827b3619631bf29790572fccb5e06979c881d Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Tue, 4 Feb 2020 00:37:32 +0200 Subject: [PATCH 09/49] Do not create thumbnail on autosave Creating thumbnails on autosave was already disabled in 4cd48850a30423dd8b8805123449e37c7132c17b but only for the first score autosave. Subsequent autosaves still generated thumbnails. This commit makes all autosaves not create thumbnails. --- libmscore/score.h | 2 +- libmscore/scorefile.cpp | 4 ++-- mscore/musescore.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libmscore/score.h b/libmscore/score.h index 51b2c89fe952d..84b9a7aa38f83 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -789,7 +789,7 @@ class Score : public QObject, public ScoreElement { bool saveFile(QFileInfo& info); bool saveFile(QIODevice* f, bool msczFormat, bool onlySelection = false); - bool saveCompressedFile(QFileInfo&, bool onlySelection); + bool saveCompressedFile(QFileInfo&, bool onlySelection, bool createThumbnail = true); bool saveCompressedFile(QFileDevice*, QFileInfo&, bool onlySelection, bool createThumbnail = true); void print(QPainter* printer, int page); diff --git a/libmscore/scorefile.cpp b/libmscore/scorefile.cpp index 93ef9c8f77b21..d139220529545 100644 --- a/libmscore/scorefile.cpp +++ b/libmscore/scorefile.cpp @@ -486,7 +486,7 @@ bool MasterScore::saveFile() // saveCompressedFile //--------------------------------------------------------- -bool Score::saveCompressedFile(QFileInfo& info, bool onlySelection) +bool Score::saveCompressedFile(QFileInfo& info, bool onlySelection, bool createThumbnail) { if (readOnly() && info == *masterScore()->fileInfo()) return false; @@ -495,7 +495,7 @@ bool Score::saveCompressedFile(QFileInfo& info, bool onlySelection) MScore::lastError = tr("Open File\n%1\nfailed: %2").arg(info.filePath(), strerror(errno)); return false; } - return saveCompressedFile(&fp, info, onlySelection); + return saveCompressedFile(&fp, info, onlySelection, createThumbnail); } //--------------------------------------------------------- diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 327d804739fa8..5a19a08134373 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -5039,7 +5039,7 @@ void MuseScore::autoSaveTimerTimeout() if (!tmp.isEmpty()) { QFileInfo fi(tmp); // TODO: cannot catch exception here: - s->saveCompressedFile(fi, false); + s->saveCompressedFile(fi, false, false); // no thumbnail } else { QDir dir; From 3ec122fc29bd564786864c247b291fec276f9eb6 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Tue, 4 Feb 2020 02:12:14 +0200 Subject: [PATCH 10/49] Avoid iterating over all spanners when saving ChordRest's slurs --- libmscore/chordrest.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libmscore/chordrest.cpp b/libmscore/chordrest.cpp index 2622e64700567..c0b0e644fc31c 100644 --- a/libmscore/chordrest.cpp +++ b/libmscore/chordrest.cpp @@ -177,14 +177,18 @@ void ChordRest::writeProperties(XmlWriter& xml) const for (Lyrics* lyrics : _lyrics) lyrics->write(xml); + + const int curTick = xml.curTick().ticks(); + if (!isGrace()) { Fraction t(globalTicks()); if (staff()) t /= staff()->timeStretch(xml.curTick()); xml.incCurTick(t); } - for (auto i : score()->spanner()) { // TODO: don’t search whole list - Spanner* s = i.second; + + for (auto i : score()->spannerMap().findOverlapping(curTick - 1, curTick + 1)) { + Spanner* s = i.value; if (s->generated() || !s->isSlur() || toSlur(s)->broken() || !xml.canWrite(s)) continue; From f7efe843b5fb284294b82efabba6a39895649e4f Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Wed, 5 Feb 2020 15:41:43 +0200 Subject: [PATCH 11/49] fix #284988: Remove "Restart MuseScore" option from crash reporter This option doesn't work reliably so better remove it. --- CMakeLists.txt | 1 - build/config.h.in | 1 - crashreporter/crashreporter.cpp | 7 ------- crashreporter/crashreporter.ui | 26 ++++++-------------------- 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c39d8d28bcc89..0f5148e71da9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -810,7 +810,6 @@ if (BUILD_CRASH_REPORTER) add_subdirectory(crashreporter) add_dependencies(mscore mscore-crash-reporter) set (CRASHREPORTER_EXECUTABLE "${CRASHREPORTER_EXECUTABLE_NAME}${CMAKE_EXECUTABLE_SUFFIX}") - set (MSCORE_EXECUTABLE "${MSCORE_EXECUTABLE_NAME}${CMAKE_EXECUTABLE_SUFFIX}") endif (BUILD_CRASH_REPORTER) ## diff --git a/build/config.h.in b/build/config.h.in index e65523103cbfe..a948a447871fb 100644 --- a/build/config.h.in +++ b/build/config.h.in @@ -37,7 +37,6 @@ #cmakedefine HAS_AUDIOFILE #cmakedefine USE_SSE -#define MSCORE_EXECUTABLE "${MSCORE_EXECUTABLE}" #cmakedefine BUILD_CRASH_REPORTER #define CRASHREPORTER_EXECUTABLE "${CRASHREPORTER_EXECUTABLE}" #define CRASH_REPORT_URL "${CRASH_REPORT_URL}" diff --git a/crashreporter/crashreporter.cpp b/crashreporter/crashreporter.cpp index db26c77b7658f..09eb1551c26e5 100644 --- a/crashreporter/crashreporter.cpp +++ b/crashreporter/crashreporter.cpp @@ -124,13 +124,6 @@ void CrashReporter::onUploadFinished(QNetworkReply* reply) if (success) { QMessageBox::information(this, tr("Success!"), tr("Crash report uploaded successfully!")); - if (_ui->restartCheckBox->isChecked()) { - static_assert(sizeof(MSCORE_EXECUTABLE) > 1, - "MSCORE_EXECUTABLE should be defined to make it possible to restart MuseScore" - ); - const QDir appDir(qApp->applicationDirPath()); - QProcess::startDetached(appDir.filePath(MSCORE_EXECUTABLE)); - } close(); } else diff --git a/crashreporter/crashreporter.ui b/crashreporter/crashreporter.ui index 433bf4e556f2a..ba005e75257c2 100644 --- a/crashreporter/crashreporter.ui +++ b/crashreporter/crashreporter.ui @@ -34,13 +34,6 @@ - - - - Send report - - - @@ -54,23 +47,17 @@ - - + + - Cancel + Send report - - - - Restart MuseScore after this report is sent - + + - Restart MuseScore - - - true + Cancel @@ -78,7 +65,6 @@ commentText - restartCheckBox sendReportButton cancelButton From 31018335c3354646cb19477bf17b5d87ba2c7b5c Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Sat, 8 Feb 2020 11:44:26 +0200 Subject: [PATCH 12/49] Fix MacOS notarization errors --- build/package_mac | 13 +++++++++++-- build/travis/job_macos/install.sh | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/build/package_mac b/build/package_mac index 0acd857b794a0..909303a0df786 100755 --- a/build/package_mac +++ b/build/package_mac @@ -191,13 +191,22 @@ ln -s /Applications/ ${VOLUME}/Applications set_bundle_display_options ${VOLUME} mv ${VOLUME}/Pictures ${VOLUME}/.Pictures +# Most nested locations should go first +CODE_PATHS=( + "${VOLUME}/${LONGER_NAME}.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app" + "${VOLUME}/${LONGER_NAME}.app" +) + #codesign echo "Codesign" -codesign --deep -s "Developer ID Application: MuseScore" "${VOLUME}/${LONGER_NAME}.app" +# `codesign --deep` doesn't seem to search for code in Contents/Resources directory so sign libraries in it manually +find "${VOLUME}/${LONGER_NAME}.app/Contents/Resources" -name '*.dylib' -exec codesign --options runtime --deep -s "Developer ID Application: MuseScore" '{}' ';' +# Sign code in other (more conventional) locations +codesign --options runtime --deep -s "Developer ID Application: MuseScore" "${CODE_PATHS[@]}" echo "spctl" spctl --assess --type execute "${VOLUME}/${LONGER_NAME}.app" echo "Codesign verify" -codesign --verify --deep --strict --verbose=2 "${VOLUME}/${LONGER_NAME}.app" +codesign --verify --deep --strict --verbose=2 "${CODE_PATHS[@]}" echo "Unmount" # Unmount the disk image diff --git a/build/travis/job_macos/install.sh b/build/travis/job_macos/install.sh index 02c2759076035..01917ec5641aa 100755 --- a/build/travis/job_macos/install.sh +++ b/build/travis/job_macos/install.sh @@ -6,7 +6,7 @@ if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then fi # install dependencies -wget -c --no-check-certificate -nv -O bottles.zip https://musescore.org/sites/musescore.org/files/bottles-MuseScore-3.0.zip +wget -c --no-check-certificate -nv -O bottles.zip https://musescore.org/sites/musescore.org/files/2020-02/bottles-MuseScore-3.0-yosemite.zip unzip bottles.zip # we don't use freetype From 6373ac3dfe6e9612845995887dcc876477f25379 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sat, 15 Feb 2020 12:51:50 +0100 Subject: [PATCH 13/49] copy `#include ` to all.h but continue to use it directly in excerpt.h (but before the 'internal' headers) and use it directly in xm.h and changeMap.h too, which so far don't seem to include them directly nor indirectly --- all.h | 1 + libmscore/changeMap.h | 2 ++ libmscore/excerpt.h | 3 ++- libmscore/xml.h | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/all.h b/all.h index 8ecb0eefec272..d6a24ffc93d8c 100644 --- a/all.h +++ b/all.h @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include diff --git a/libmscore/changeMap.h b/libmscore/changeMap.h index b55d0def1fa0a..eef1df316e2e6 100644 --- a/libmscore/changeMap.h +++ b/libmscore/changeMap.h @@ -13,6 +13,8 @@ #ifndef __CHANGEMAP_H__ #define __CHANGEMAP_H__ +#include + #include "fraction.h" /** diff --git a/libmscore/excerpt.h b/libmscore/excerpt.h index 48f51e29c51ba..8aabc63d1b694 100644 --- a/libmscore/excerpt.h +++ b/libmscore/excerpt.h @@ -13,6 +13,8 @@ #ifndef __EXCERPT_H__ #define __EXCERPT_H__ +#include + #include "fraction.h" namespace Ms { @@ -29,7 +31,6 @@ class XmlReader; // @@ Excerpt //--------------------------------------------------------- -#include class Excerpt : public QObject { MasterScore* _oscore; diff --git a/libmscore/xml.h b/libmscore/xml.h index fece84f77382e..c6c84136fa03e 100644 --- a/libmscore/xml.h +++ b/libmscore/xml.h @@ -13,6 +13,8 @@ #ifndef __XML_H__ #define __XML_H__ +#include + #include "connector.h" #include "stafftype.h" #include "interval.h" From ed19fdf72c4a92d3370ec9cf13185cc47b81db16 Mon Sep 17 00:00:00 2001 From: Daniel Flynn Date: Sun, 16 Feb 2020 22:35:17 -0600 Subject: [PATCH 14/49] fix durationtype.cpp conflict with Windows defined Chord type Resolves error when compiling mtest/libmscore/durationtype/tst_durationtype.cpp Error encountered: 'error: reference to 'Chord' is ambiguous' which refers to minGW 'wingdi.h' header which defines a Chord type of its own. --- mtest/libmscore/durationtype/tst_durationtype.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mtest/libmscore/durationtype/tst_durationtype.cpp b/mtest/libmscore/durationtype/tst_durationtype.cpp index 6e7c70daf512e..2b514dc9ce725 100644 --- a/mtest/libmscore/durationtype/tst_durationtype.cpp +++ b/mtest/libmscore/durationtype/tst_durationtype.cpp @@ -71,7 +71,7 @@ void TestDurationType::halfDuration() score->startCmd(); score->cmdAddPitch(42, false, false); - Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); + Ms::Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); QVERIFY(c->ticks() == Fraction(1, 1)); score->endCmd(); @@ -80,7 +80,7 @@ void TestDurationType::halfDuration() score->startCmd(); score->cmdHalfDuration(); score->endCmd(); - Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); + Ms::Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); QVERIFY(c->ticks() == Fraction(i / 2, 128)); } } @@ -106,7 +106,7 @@ void TestDurationType::doubleDuration() // repeatedly double-duration from V_128 to V_WHOLE for (int i = 1; i < 128; i *= 2) { score->cmdDoubleDuration(); - Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); + Ms::Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); QVERIFY(c->ticks() == Fraction(2 * i, 128)); } score->endCmd(); @@ -128,13 +128,13 @@ void TestDurationType::decDurationDotted() score->startCmd(); score->cmdAddPitch(42, false, false); - Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); + Ms::Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); QVERIFY(c->ticks() == Fraction(1, 1)); // repeatedly dec-duration-dotted from V_WHOLE to V_128 for (int i = 128; i > 1; i /= 2) { score->cmdDecDurationDotted(); - Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); + Ms::Chord* c = score->firstMeasure()->findChord(Fraction(0,1), 0); QVERIFY(c->ticks() == Fraction(i + i/2, 256)); score->cmdDecDurationDotted(); From fe182f715a37f8508d11562eaa5f6055d7a12e54 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Mon, 17 Feb 2020 22:07:14 +0100 Subject: [PATCH 15/49] Fix #301124: Always show correct pathname in Score Properties even after a "Save as", then also show where the file initialy got read from --- mscore/metaedit.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mscore/metaedit.cpp b/mscore/metaedit.cpp index 8321f2e1557a4..565664fd60332 100644 --- a/mscore/metaedit.cpp +++ b/mscore/metaedit.cpp @@ -44,7 +44,13 @@ MetaEditDialog::MetaEditDialog(Score* s, QWidget* parent) revision->setText(QString::number(rev, 16)); else revision->setText(QString::number(rev, 10)); - filePath->setText(score->importedFilePath()); + + QString currentFileName = score->masterScore()->fileInfo()->absoluteFilePath(); + QString previousFileName = score->importedFilePath(); + if (previousFileName.isEmpty() || previousFileName == currentFileName) // New score or no "Save as" used + filePath->setText(previousFileName); + else + filePath->setText(QString("%1\n%2\n%3").arg(currentFileName, tr("initially read from:"), previousFileName)); filePath->setTextInteractionFlags(Qt::TextSelectableByMouse); int idx = 0; From 706ce447337b26fed2f0dfbcff6003e6c2791d5f Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Tue, 18 Feb 2020 07:03:11 +0100 Subject: [PATCH 16/49] also deal with the case of a crash before 1st save + collect_artifacts --- mscore/metaedit.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mscore/metaedit.cpp b/mscore/metaedit.cpp index 565664fd60332..f2421b787b1a8 100644 --- a/mscore/metaedit.cpp +++ b/mscore/metaedit.cpp @@ -50,7 +50,9 @@ MetaEditDialog::MetaEditDialog(Score* s, QWidget* parent) if (previousFileName.isEmpty() || previousFileName == currentFileName) // New score or no "Save as" used filePath->setText(previousFileName); else - filePath->setText(QString("%1\n%2\n%3").arg(currentFileName, tr("initially read from:"), previousFileName)); + filePath->setText(QString("%1\n%2\n%3") + .arg(QFileInfo::exists(currentFileName) ? currentFileName : "" + tr("Not saved yet,") + "", + tr("initially read from:"), previousFileName)); filePath->setTextInteractionFlags(Qt::TextSelectableByMouse); int idx = 0; From 77844eac449b4f8cb2be68ce711dc7d4f3b0584d Mon Sep 17 00:00:00 2001 From: Niek van den Berg Date: Mon, 17 Feb 2020 10:38:20 +0100 Subject: [PATCH 17/49] Fix #301079 - Request: Add track names to exported midi file as an UTF-8 string. --- mscore/exportmidi.cpp | 29 +++++++++++++++++- mtest/libmscore/midi/testArpeggio-ref.mid | Bin 193 -> 203 bytes mtest/libmscore/midi/testBends1-ref.mid | Bin 1077 -> 1097 bytes mtest/libmscore/midi/testBends2-ref.mid | Bin 1117 -> 1157 bytes ...testInitialKeySigThenRepeatToMeas2-ref.mid | Bin 172 -> 182 bytes mtest/libmscore/midi/testMidiPort-ref.mid | Bin 6331 -> 8119 bytes mtest/libmscore/midi/testMutedUnison-ref.mid | Bin 104 -> 114 bytes .../midi/testRepeatsWithKeySigs-ref.mid | Bin 239 -> 249 bytes ...tRepeatsWithKeySigsExceptFirstMeas-ref.mid | Bin 227 -> 237 bytes .../midi/testSingleNoteDynamics-ref.mid | Bin 5141 -> 5151 bytes .../midi/testTimeStretchFermata-ref.mid | Bin 377 -> 387 bytes ...estTimeStretchFermataTempoEdit-120-ref.mid | Bin 264 -> 274 bytes ...estTimeStretchFermataTempoEdit-200-ref.mid | Bin 264 -> 274 bytes mtest/libmscore/midi/testVoltaDynamic-ref.mid | Bin 516 -> 527 bytes .../libmscore/midi/testVoltaStaffText-ref.mid | Bin 503 -> 514 bytes mtest/libmscore/midi/testVoltaTemp-ref.mid | Bin 513 -> 524 bytes 16 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mscore/exportmidi.cpp b/mscore/exportmidi.cpp index d69cf3dd5a326..5a8cd3914e1b7 100644 --- a/mscore/exportmidi.cpp +++ b/mscore/exportmidi.cpp @@ -79,6 +79,33 @@ void ExportMidi::writeHeader() } #endif + //-------------------------------------------- + // write track names + //-------------------------------------------- + + int staffIdx = 0; + for (auto& track1: mf.tracks()) { + Staff* staff = cs->staff(staffIdx); + + QByteArray partName = staff->partName().toUtf8(); + int len = partName.length() + 1; + unsigned char* data = new unsigned char[len]; + + memcpy(data, partName.data(), len); + + MidiEvent ev; + ev.setType(ME_META); + ev.setMetaType(META_TRACK_NAME); + ev.setEData(data); + ev.setLen(len); + + track1.insert(0, ev); + + + ++staffIdx; + } + + //-------------------------------------------- // write time signature //-------------------------------------------- @@ -129,7 +156,7 @@ void ExportMidi::writeHeader() // assume every staff corresponds to a midi track //--------------------------------------------------- - int staffIdx = 0; + staffIdx = 0; for (auto& track1: mf.tracks()) { Staff* staff = cs->staff(staffIdx); KeyList* keys = staff->keyList(); diff --git a/mtest/libmscore/midi/testArpeggio-ref.mid b/mtest/libmscore/midi/testArpeggio-ref.mid index ce5bb251e1981b08e3f1749bbb054f012c4742e1..3c9ab455f5ca4f01428af55166e4fea420f84b3a 100644 GIT binary patch delta 21 dcmX@ec$#s7DEC%||IBOwnTdJ%3=_px0{~Fv2Soq? delta 11 ScmX@jc#v^|DC6ph3abGbTm(D- diff --git a/mtest/libmscore/midi/testBends1-ref.mid b/mtest/libmscore/midi/testBends1-ref.mid index 99ecf3f88f04aae72820f12e162e536ac31f5d2a..05ae785d1575fa00c2270ccf16158340ee32406b 100644 GIT binary patch delta 32 ncmdnWagt+#sHic+e`W#KoYdr!qReCk_tMOg#3F``V)85iu8;~Z delta 12 TcmX@fv6W+jD5LyFEqN9I8e#)d diff --git a/mtest/libmscore/midi/testBends2-ref.mid b/mtest/libmscore/midi/testBends2-ref.mid index 1690ec15a1c03761981062e4b5a7b9a9759efd7b..ed3259d7a33169a9e89716aed55d5c13f5a4472c 100644 GIT binary patch delta 59 zcmcc1(aJeNRP-vte`W#KoYdr!qReCk_tMOg#3F``VkekHCxK)flk-c9OAs=f?=#gg F0swNQ6z~85 delta 19 acmZqWyvs2`l=0w3trJX)b(`6l>lgt|*cOyNJDF#fn%#QLKOk>nS{d$M6W=!khdO<3blC=3N?= zlgaZfCbRn-PM=3a^rFa%^5Jj>{E^8fs@6CXxH=7bLn7*$PNy*&MP1iKcItxG@LD2o zVUc%{H-kq^c5#WgBP)v{ifWbb6zlJlFCB#`jAi231b$C88w$0cMW4ny)F}BZ`hcPc>2aFvu=40%L zv17*kjGZuc%GeoW=Zsx2cF9$AYUgy6 z(=krRIi28ilG7g9BcQy-_>obGVC%jq7c`gV*3(<4rgISp`n!s#ieK~B#&J?Hd-(@RdT zIKAdH#OV#Ex18Q_de7+tr;nV5Iep^vnbQ|eUpal_^!*R5Nc>bys^3p^a*6-8#1GK9 BieCT# diff --git a/mtest/libmscore/midi/testMutedUnison-ref.mid b/mtest/libmscore/midi/testMutedUnison-ref.mid index 815ffbc7913d952aeaac42ad53cb0646d6c045ac..3a9325021632ababdaa1c21adad04303234cc116 100644 GIT binary patch delta 19 acmc~Onjp#@!||j+G*KZ401rz7)&Kwi diff --git a/mtest/libmscore/midi/testRepeatsWithKeySigs-ref.mid b/mtest/libmscore/midi/testRepeatsWithKeySigs-ref.mid index 9a167d985e055e4264926f8c50ee639afcdf6434..d34c24b5333bae9c72dc327bc0be97bc3590738e 100644 GIT binary patch delta 21 dcmaFQ_>*yhDEDKA|IBOwnTdJ%3=_p}0svaa2mJs5 delta 11 Scmey#_?~fsDC5nE3O4~A+643f diff --git a/mtest/libmscore/midi/testRepeatsWithKeySigsExceptFirstMeas-ref.mid b/mtest/libmscore/midi/testRepeatsWithKeySigsExceptFirstMeas-ref.mid index 23b5b3d6137ac3dbc2611b8b9a3c380dd52a0424..a03db6ccc25de89a6cf078d2a627f865c8969783 100644 GIT binary patch delta 21 dcmaFN_?B^kDED=S|IBOwnTdJ%3=_r90svSu2h9Kg delta 11 ScmaFM_?U5mDC60Q3TFWvt^~vY diff --git a/mtest/libmscore/midi/testSingleNoteDynamics-ref.mid b/mtest/libmscore/midi/testSingleNoteDynamics-ref.mid index 75e1a048d3b06c0de327feaddc692a551207dbc1..27ad91c0494c7f84db2dc93fd746b9d80d0dc60e 100644 GIT binary patch delta 23 ecmbQLF<)bX2#*LS!+&PBfXu|ae1?r;|Ahfjr3Wei delta 13 UcmbQQF;!!N2$S&tjSByT0U}ogAOHXW diff --git a/mtest/libmscore/midi/testTimeStretchFermata-ref.mid b/mtest/libmscore/midi/testTimeStretchFermata-ref.mid index 769b71c24d6caaac9b97d698e33409b1ac0ed766..a94913076e14faff4b9af20b731b8684ee72e095 100644 GIT binary patch delta 22 dcmey#)XY3VlslK{>d~!lreduLNX%&8xRA) diff --git a/mtest/libmscore/midi/testTimeStretchFermataTempoEdit-120-ref.mid b/mtest/libmscore/midi/testTimeStretchFermataTempoEdit-120-ref.mid index 95e4b8f669ea2f8fb33e1d3cc5d1999d4572fc95..309db85903463208a694e5706392d05569b24a5b 100644 GIT binary patch delta 21 ccmeBRn#43gl=~0Ee`dCT%*4EWhKXXI08C5=V*mgE delta 11 ScmbQl)WI}Cl=0I1UZB%JY-qKQnt+W`0g)9>YelcZ>jBvIq76 delta 12 TcmeBYX10pJcf;84;cYu_6R`$ delta 12 TcmZo-`OZ8+l=0z4#fOXl9(e@3 diff --git a/mtest/libmscore/midi/testVoltaTemp-ref.mid b/mtest/libmscore/midi/testVoltaTemp-ref.mid index 5aed47eab19013d6d519dccdbd52a9621f464aaf..1d09c1f2bc3f8c4258be13f22714d5197e4f9263 100644 GIT binary patch delta 23 ecmZo<>0y~5%JYrkKQnt+W`0g)9>Yel*NgyL_y_6$ delta 12 TcmeBSX=Iro%J_Pt;%i0#8l(he From cda31c3382187530e2e4b36445dafd67c4542723 Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 25 Feb 2020 20:49:57 +0800 Subject: [PATCH 18/49] fix #301555 part 1: invisible arpeggios occupy space --- libmscore/chord.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index 13f38335df8af..2c8c8873f4adf 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -1966,9 +1966,11 @@ void Chord::layoutPitched() qreal arpeggioDistance = score()->styleP(Sid::ArpeggioNoteDistance) * mag_; _arpeggio->layout(); // only for width() ! _arpeggio->setHeight(0.0); - lll += _arpeggio->width() + arpeggioDistance + chordX; + qreal extraX = _arpeggio->width() + arpeggioDistance + chordX; qreal y1 = upnote->pos().y() - upnote->headHeight() * .5; - _arpeggio->setPos(-lll, y1); + _arpeggio->setPos(-(lll + extraX), y1); + if (_arpeggio->visible()) + lll += extraX; // _arpeggio->layout() called in layoutArpeggio2() // handle the special case of _arpeggio->span() > 1 @@ -1978,8 +1980,8 @@ void Chord::layoutPitched() // allocate enough room for glissandi if (_endsGlissando) { - if (!rtick().isZero() // if not at beginning of measure - || graceNotesBefore.size() > 0) // or there are graces before + if (!rtick().isZero() // if not at beginning of measure + || graceNotesBefore.size() > 0) // or there are graces before lll += _spatium * 0.5 + minTieLength; // special case of system-initial glissando final note is handled in Glissando::layout() itself } From 8cb60db1cf9fef3e45ee7c5f635f34c5f3c5644f Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Wed, 26 Feb 2020 10:39:50 +0100 Subject: [PATCH 19/49] fix #301600: Option to disable the pop-up "Reset the positions of all elements?" --- global/settings/types/preferencekeys.h | 1 + mscore/musescore.cpp | 36 +++++++++++----- mscore/preferences.cpp | 1 + mscore/prefsdialog.cpp | 15 ++++++- mscore/prefsdialog.ui | 57 ++++++++++++++++++++++++-- 5 files changed, 94 insertions(+), 16 deletions(-) diff --git a/global/settings/types/preferencekeys.h b/global/settings/types/preferencekeys.h index 791e48a9d9113..399d1899f8857 100644 --- a/global/settings/types/preferencekeys.h +++ b/global/settings/types/preferencekeys.h @@ -64,6 +64,7 @@ #define PREF_IMPORT_MUSICXML_IMPORTLAYOUT "import/musicXML/importLayout" #define PREF_IMPORT_OVERTURE_CHARSET "import/overture/charset" #define PREF_IMPORT_STYLE_STYLEFILE "import/style/styleFile" +#define PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS "import/compatibility/resetElementPositions" #define PREF_APP_PALETTESCALE "application/paletteScale" #define PREF_IO_ALSA_DEVICE "io/alsa/device" #define PREF_IO_ALSA_FRAGMENTS "io/alsa/fragments" diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 7ad45d2cc4b89..c0fe2fc6f4e90 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -2535,18 +2535,32 @@ void MuseScore::reloadInstrumentTemplates() void MuseScore::askResetOldScorePositions(Score* score) { if (score->mscVersion() < 300) { - QMessageBox msgBox; - QString question = tr("Reset the positions of all elements?"); - msgBox.setWindowTitle(question); - msgBox.setText(tr("To best take advantage of automatic placement in MuseScore 3 when importing '%1' from MuseScore %2, it is recommended to reset the positions of all elements.") - .arg(score->masterScore()->fileInfo()->completeBaseName(), score->mscoreVersion()) + "\n\n" + question); - msgBox.setIcon(QMessageBox::Question); - msgBox.setStandardButtons( - QMessageBox::Yes | QMessageBox::No - ); - - if (msgBox.exec() == QMessageBox::Yes) + QString pref = preferences.getString(PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS); + if (pref == "No") + return; + else if (pref == "Yes") score->cmdResetAllPositions(); + else { // either set to "Ask" or not at all + QMessageBox msgBox; + QCheckBox ask; + ask.setText(tr("Don't ask me again.")); + ask.setToolTip(tr("You can change this behaviour any time in 'Preferences… > Import > Reset Element Positions'")); + msgBox.setCheckBox(&ask); + QString question = tr("Reset the positions of all elements?"); + msgBox.setWindowTitle(question); + msgBox.setText(tr("To best take advantage of automatic placement in MuseScore 3 when importing '%1' from MuseScore %2, it is recommended to reset the positions of all elements.") + .arg(score->masterScore()->fileInfo()->completeBaseName(), score->mscoreVersion()) + "\n\n" + question); + msgBox.setIcon(QMessageBox::Question); + msgBox.setStandardButtons( + QMessageBox::Yes | QMessageBox::No + ); + + int res = msgBox.exec(); + if (res == QMessageBox::Yes) + score->cmdResetAllPositions(); + if (ask.checkState() == Qt::Checked) + preferences.setPreference(PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS, res == QMessageBox::No? "Yes" : "No"); + } } } diff --git a/mscore/preferences.cpp b/mscore/preferences.cpp index 438df56bf92a2..72af7a81acfec 100644 --- a/mscore/preferences.cpp +++ b/mscore/preferences.cpp @@ -113,6 +113,7 @@ void Preferences::init(bool storeInMemoryOnly) {PREF_IMPORT_MUSICXML_IMPORTLAYOUT, new BoolPreference(true, false)}, {PREF_IMPORT_OVERTURE_CHARSET, new StringPreference("GBK", false)}, {PREF_IMPORT_STYLE_STYLEFILE, new StringPreference("", false)}, + {PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS, new StringPreference("", false)}, {PREF_IO_ALSA_DEVICE, new StringPreference("default", false)}, {PREF_IO_ALSA_FRAGMENTS, new IntPreference(3, false)}, {PREF_IO_ALSA_PERIODSIZE, new IntPreference(1024, false)}, diff --git a/mscore/prefsdialog.cpp b/mscore/prefsdialog.cpp index 6416f80c5ee70..668bf412aec27 100644 --- a/mscore/prefsdialog.cpp +++ b/mscore/prefsdialog.cpp @@ -394,7 +394,7 @@ void PreferenceDialog::updateValues(bool useDefaultValues) alsaFragments->setValue(preferences.getInt(PREF_IO_ALSA_FRAGMENTS)); drawAntialiased->setChecked(preferences.getBool(PREF_UI_CANVAS_MISC_ANTIALIASEDDRAWING)); limitScrollArea->setChecked(preferences.getBool(PREF_UI_CANVAS_SCROLL_LIMITSCROLLAREA)); - switch(preferences.sessionStart()) { + switch (preferences.sessionStart()) { case SessionStart::EMPTY: emptySession->setChecked(true); break; case SessionStart::LAST: lastSession->setChecked(true); break; case SessionStart::NEW: newSession->setChecked(true); break; @@ -409,6 +409,13 @@ void PreferenceDialog::updateValues(bool useDefaultValues) importLayout->setChecked(preferences.getBool(PREF_IMPORT_MUSICXML_IMPORTLAYOUT)); importBreaks->setChecked(preferences.getBool(PREF_IMPORT_MUSICXML_IMPORTBREAKS)); + QString resetElementPositions = preferences.getString(PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS); + if (resetElementPositions == "No") + resetElementPositionsNo->setChecked(true); + else if (resetElementPositions == "Yes") + resetElementPositionsYes->setChecked(true); + else // "Ask" or unset (or anything else) + resetElementPositionsAlwaysAsk->setChecked(true); if (preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT)) { exportAllLayouts->setChecked(true); } @@ -952,6 +959,12 @@ void PreferenceDialog::apply() preferences.setPreference(PREF_EXPORT_PNG_USETRANSPARENCY, pngTransparent->isChecked()); preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, importBreaks->isChecked()); preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTLAYOUT, importLayout->isChecked()); + if (resetElementPositionsAlwaysAsk->isChecked()) + preferences.setPreference(PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS, "Ask"); + else if (resetElementPositionsYes->isChecked()) + preferences.setPreference(PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS, "Yes"); + else if (resetElementPositionsNo->isChecked()) + preferences.setPreference(PREF_IMPORT_COMPATIBILITY_RESET_ELEMENT_POSITIONS, "No"); preferences.setPreference(PREF_IO_MIDI_ADVANCEONRELEASE, advanceOnRelease->isChecked()); preferences.setPreference(PREF_IO_MIDI_ENABLEINPUT, enableMidiInput->isChecked()); preferences.setPreference(PREF_IO_MIDI_EXPANDREPEATS, expandRepeats->isChecked()); diff --git a/mscore/prefsdialog.ui b/mscore/prefsdialog.ui index c6f0e08f9b9ca..b5c5212678ee6 100644 --- a/mscore/prefsdialog.ui +++ b/mscore/prefsdialog.ui @@ -3245,7 +3245,7 @@ Adjusting latency can help synchronize your MIDI hardware with MuseScore's inter - + Style Used for Import @@ -3299,7 +3299,7 @@ Adjusting latency can help synchronize your MIDI hardware with MuseScore's inter - + Character Set Used When Importing Binary Files @@ -3346,7 +3346,7 @@ Adjusting latency can help synchronize your MIDI hardware with MuseScore's inter - + 0 @@ -3378,7 +3378,7 @@ Adjusting latency can help synchronize your MIDI hardware with MuseScore's inter - + 0 @@ -3453,6 +3453,52 @@ Adjusting latency can help synchronize your MIDI hardware with MuseScore's inter + + + + Reset element positions when importing scores from older MuseScore versions. + + + Reset Element Positions + + + + + + Always ask + + + + + + + Yes + + + + + + + No + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + @@ -4306,6 +4352,9 @@ Adjusting latency can help synchronize your MIDI hardware with MuseScore's inter importLayout importBreaks shortestNote + resetElementPositionsAlwaysAsk + resetElementPositionsYes + resetElementPositionsNo pngResolution pngTransparent exportPdfDpi From b63eb796106299fb401c5e379d89dc1aa3df2f2e Mon Sep 17 00:00:00 2001 From: AntonioBL Date: Wed, 19 Feb 2020 16:14:14 +0100 Subject: [PATCH 20/49] Run vtests on PRs and commits to master branch and compare to parent commit vtest results; output a comment and upload a report when differences are found --- .github/workflows/vtests.yml | 117 +++++++++++++++++++++++++++++++++++ .gitignore | 1 + vtest/gen | 8 ++- vtest/gen_compare | 79 +++++++++++++++++++++++ vtest/style.css | 2 +- 5 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/vtests.yml create mode 100755 vtest/gen_compare diff --git a/.github/workflows/vtests.yml b/.github/workflows/vtests.yml new file mode 100644 index 0000000000000..126967210f984 --- /dev/null +++ b/.github/workflows/vtests.yml @@ -0,0 +1,117 @@ +name: CI_vtests + +on: + pull_request: + branches: + - master + push: + branches: + - master + +jobs: + run_vtests: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Retrieve base commit for PR + if: github.event_name == 'pull_request' + run: | + export BASEREF=${{ github.event.pull_request.base.sha }} + if [ -z "$BASEREF" ]; then + export found=0 + else + export found=1 + fi + echo "::set-env name=BASEREF::${BASEREF}" + echo "::set-env name=found::${found}" + - name: Retrieve base commit for push commit + if: github.event_name == 'push' + run: | + export BASEREF=$( git show -s --pretty=%P ${{ github.sha }} | head -c 10 ) + if [ -z "$BASEREF" ]; then + export found=0 + else + export found=1 + fi + echo "::set-env name=BASEREF::${BASEREF}" + echo "::set-env name=found::${found}" + - name: Install dependencies + if: contains( env.found, '1') + run: | + sudo apt-get update + sudo apt-get install libasound2-dev portaudio19-dev libmp3lame-dev libsndfile1-dev libportmidi-dev + sudo apt-get install libssl-dev libpulse-dev libfreetype6-dev libfreetype6 + sudo apt-get install libdrm-dev libgl1-mesa-dev libegl1-mesa-dev + - name: Setup the environment + if: contains( env.found, '1') + run: | + sed -i 's/travis_retry//g' build/travis/job1_Tests/environment.sh + source build/travis/job1_Tests/environment.sh + echo "::set-env name=PATH::${PATH}" + echo "::set-env name=QT_PLUGIN_PATH::${QT_PLUGIN_PATH}" + echo "::set-env name=QML2_IMPORT_PATH::${QML2_IMPORT_PATH}" + - name: Build + if: contains( env.found, '1') + run: | + make installdebug CPUS=2 PREFIX="$HOME/software" COVERAGE=ON + - name: Build reference branch + if: contains( env.found, '1') + run: | + mkdir -p "$HOME/softwarebase" + git checkout $BASEREF + make clean + make installdebug CPUS=2 PREFIX="$HOME/softwarebase" COVERAGE=ON 2>/dev/null + - name: Run reference vtests + if: contains( env.found, '1') + run: | + cd vtest + export VTEST_MSCORE="$HOME/softwarebase/bin/mscore" + export VTEST_BROWSER=ls + export VTEST_DIR=$(pwd) + xvfb-run ./gen + - name: Run vtests + if: contains( env.found, '1') + run: | + git checkout - + cd vtest + mkdir -p compare + find ./html -name "*-1.png" -exec mv '{}' ./compare \; + rm -rf html 2>/dev/null + export VTEST_MSCORE="$HOME/software/bin/mscore" + export VTEST_BROWSER=ls + export VTEST_DIR=$(pwd) + xvfb-run ./gen + - name: Compare vtests + if: contains( env.found, '1') + run: | + cd vtest + export VTEST_DIR=$(pwd) + ./gen_compare + - name: Upload artifact + if: contains( env.found, '1') && contains( env.VTEST_DIFF_FOUND, 'true') + uses: actions/upload-artifact@v1 + with: + name: compare + path: ./vtest/compare + - name: Comment PR + if: github.event_name == 'pull_request' && contains( env.found, '1') && contains( env.VTEST_DIFF_FOUND, 'true') + uses: thollander/actions-comment-pull-request@1.0.0 + with: + message: 'This is an automatic message. This PR appears to change some of the visual tests. + Please carefully review the new visual test results in the uploaded artifact that can be found + [here](https://github.com/musescore/MuseScore/actions/runs/${{ github.run_id }})' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Comment push commit + if: github.event_name == 'push' && contains( env.found, '1') && contains( env.VTEST_DIFF_FOUND, 'true') + uses: peter-evans/commit-comment@v1.1.0 + with: + body: | + This is an automatic message. This commit appears to change some of the visual tests. + Please carefully review the new visual test results in the uploaded artifact that can be found + [here][1] + + [1]: https://github.com/musescore/MuseScore/actions/runs/${{ github.run_id }} + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7c5d84b5e6343..53fb48babfd4b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ CMakeLists.txt.user.* *.qmlc *.jsc vtest/html +vtest/compare thirdparty/mupdf-qt vtest/LOG vtest/META-INF diff --git a/vtest/gen b/vtest/gen index f5ae275ce6507..61c4a755b15b4 100755 --- a/vtest/gen +++ b/vtest/gen @@ -78,7 +78,13 @@ fi DPI=130 -DIR="$(cd "$(dirname "$0")" && pwd)" +if [ -n "$VTEST_DIR" ]; then +# SRC env variable needed for Github action vtests + echo "::set-env name=SRC::${SRC}" + DIR="$VTEST_DIR" +else + DIR="$(cd "$(dirname "$0")" && pwd)" +fi mkdir -p $DIR/html cd $DIR/html rm -f *.png diff --git a/vtest/gen_compare b/vtest/gen_compare new file mode 100755 index 0000000000000..37a988e74825a --- /dev/null +++ b/vtest/gen_compare @@ -0,0 +1,79 @@ +#!/bin/bash + +echo "Run vtest comparison" + +# Create "compare" folder +if [ -n "$VTEST_DIR" ]; then + DIR="$VTEST_DIR" +else + DIR="$(cd "$(dirname "$0")" && pwd)" +fi +mkdir -p $DIR/compare +cd $DIR/compare + +# rm -f *.png +# Download reference images +# wget -nd -r -P . -A png http://vtest.musescore.org/${BASEREF}/vtest.html +# rm -f *-ref.png +# rm -f *-diff.png + +# This flag will become true only if differences are found +export VTEST_DIFF_FOUND=false + +# Generate first part of the html report +F=vtest_compare.html +rm -f $F +cp ../style.css . +echo "" >> $F +echo " " >> $F +echo " " >> $F +echo " " >> $F +echo " " >> $F +echo "
" >> $F +echo " Current" >> $F +echo " Reference" >> $F +echo " Comparison" >> $F +echo "
" >> $F +echo "
" >> $F + +# Compare current PNG results and reference files from parent commit +echo "Compare PNG files and references" +for src in $SRC; do + if test -f ../html/$src-1.png; then + LOG=$(compare -metric AE -fuzz 0.0% ../html/$src-1.png $src-1.png $src-diff.png 2>&1) + if (( $LOG > 0 )); then + echo "Comparison of $src gave result $LOG" + mv $src-1.png $src-ref.png 2>/dev/null + cp ../html/$src-1.png . 2>/dev/null + export VTEST_DIFF_FOUND=true + echo "

$src #

" >> $F + echo "
" >> $F + echo " " >> $F + echo " " >> $F + echo " " >> $F + echo "
" >> $F + else + rm $src-diff.png 2>/dev/null + rm $src-1.png 2>/dev/null + fi + else + echo "There were errors generating image $src" + export VTEST_DIFF_FOUND=true + echo "

$src #

" >> $F + echo "
" >> $F + echo " " >> $F + echo " " >> $F + echo " " >> $F + echo "
" >> $F + fi + done +# Close html file tags +echo " " >> $F +echo "" >> $F + +# Remove "compare" folder if no differences were detected +cd .. +if [ "$VTEST_DIFF_FOUND" = false ]; then + rm -rf ./compare +fi +echo "::set-env name=VTEST_DIFF_FOUND::${VTEST_DIFF_FOUND}" diff --git a/vtest/style.css b/vtest/style.css index 69b13c6758248..abff95626628d 100644 --- a/vtest/style.css +++ b/vtest/style.css @@ -15,5 +15,5 @@ } #topmargin { - height:20px; + height:30px; } \ No newline at end of file From 58355be681cb9bff51340d1b6482299af2d5187b Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Thu, 27 Feb 2020 11:07:44 +0100 Subject: [PATCH 21/49] fix #301656: add "Baritone Horn (Central Europe)" basically sound similar to Baritone Horn and range similar to Euphonium --- share/instruments/instruments.xml | 36 ++++++++++++++++++++++++++++++ share/instruments/instrumentsxml.h | 7 ++++++ 2 files changed, 43 insertions(+) diff --git a/share/instruments/instruments.xml b/share/instruments/instruments.xml index d8a72b8a3a565..a2f79bda9d492 100644 --- a/share/instruments/instruments.xml +++ b/share/instruments/instruments.xml @@ -3246,6 +3246,7 @@ + Baritone Horn Baritone Horn Bar. Hn. Baritone Horn @@ -3278,6 +3279,41 @@ concertband + + Baritone Horn (Central Europe) + Baritone Horn + Bar. Hn. + Baritone Horn (Central Europe) + brass.baritone-horn + F + 1 + 40-67 + 34-70 + + + + concertband + marching + + + Baritone Horn (Central Europe, Treble Clef) + Baritone Horn + Bar. Hn. + Baritone Horn (Central Europe, Treble Clef) + brass.baritone-horn + G + F + 1 + 40-67 + 34-70 + -8 + -14 + + + + concertband + marching + Posthorn Psthn. diff --git a/share/instruments/instrumentsxml.h b/share/instruments/instrumentsxml.h index 12ac7dc3b364e..6bd7e65d877d8 100644 --- a/share/instruments/instrumentsxml.h +++ b/share/instruments/instrumentsxml.h @@ -497,8 +497,15 @@ QT_TRANSLATE_NOOP3("InstrumentsXML", "E♭ A. Hn.", "E♭ Alto Horn"), QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn"), QT_TRANSLATE_NOOP3("InstrumentsXML", "Bar. Hn.", "Baritone Horn"), QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn"), +QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn"), QT_TRANSLATE_NOOP3("InstrumentsXML", "Bar. Hn.", "Baritone Horn"), QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn (Treble Clef)"), +QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn"), +QT_TRANSLATE_NOOP3("InstrumentsXML", "Bar. Hn.", "Baritone Horn"), +QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn (Central Europe)"), +QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn"), +QT_TRANSLATE_NOOP3("InstrumentsXML", "Bar. Hn.", "Baritone Horn"), +QT_TRANSLATE_NOOP("InstrumentsXML", "Baritone Horn (Central Europe, Treble Clef)"), QT_TRANSLATE_NOOP("InstrumentsXML", "Posthorn"), QT_TRANSLATE_NOOP3("InstrumentsXML", "Psthn.", "Posthorn"), QT_TRANSLATE_NOOP("InstrumentsXML", "Alphorn"), From 306cf054b2da5463aa9c83f1b14673d9728b3596 Mon Sep 17 00:00:00 2001 From: Matt McClinch Date: Thu, 27 Feb 2020 10:34:42 -0500 Subject: [PATCH 22/49] fix #299768: Hairpin: when copied, all custom settings are lost and the element resets to default Resolves: https://musescore.org/en/node/299768. --- libmscore/chordrest.cpp | 15 ++++++--------- libmscore/paste.cpp | 14 +++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/libmscore/chordrest.cpp b/libmscore/chordrest.cpp index 2622e64700567..beab86b4d3e81 100644 --- a/libmscore/chordrest.cpp +++ b/libmscore/chordrest.cpp @@ -617,16 +617,13 @@ Element* ChordRest::drop(EditData& data) case ElementType::HAIRPIN: { - const Hairpin* hairpin = toHairpin(e); - ChordRest* endCR = this; - if (hairpin->ticks().isNotZero()) { - const Fraction tick2 = tick() + hairpin->ticks() - Fraction::eps(); - endCR = score()->findCR(tick2, track()); - } - score()->addHairpin(hairpin->hairpinType(), this, endCR); - delete e; + Hairpin* hairpin = toHairpin(e); + hairpin->setTick(tick()); + hairpin->setTrack(track()); + hairpin->setTrack2(track()); + score()->undoAddElement(hairpin); } - return nullptr; + return e; default: qDebug("cannot drop %s", e->name()); diff --git a/libmscore/paste.cpp b/libmscore/paste.cpp index edf7dece4b2a9..e9af8af8203c8 100644 --- a/libmscore/paste.cpp +++ b/libmscore/paste.cpp @@ -796,13 +796,13 @@ void Score::pasteSymbols(XmlReader& e, ChordRest* dst) undoAddElement(d); } else if (tag == "HairPin") { - Hairpin h(this); - h.setTrack(destTrack); - h.read(e); - h.setTrack(destTrack); - ChordRest* destCR1 = findCR(destTick, destTrack); - ChordRest* destCR2 = findCR(destTick + h.ticks() - Fraction::eps(), destTrack); - addHairpin(h.hairpinType(), destCR1, destCR2); + Hairpin* h = new Hairpin(this); + h->setTrack(destTrack); + h->read(e); + h->setTrack(destTrack); + h->setTrack2(destTrack); + h->setTick(destTick); + undoAddElement(h); } else { // From 2fdc875f02b7f84ea18202d558b18a6add69f5a9 Mon Sep 17 00:00:00 2001 From: Peter Jonas Date: Sat, 29 Feb 2020 17:23:04 +0000 Subject: [PATCH 23/49] Palettes: simplify cell drawing code Split code into smaller functions and make use of painter coordinate transformations to make the logic easier to follow. --- mscore/palette/palettetree.cpp | 256 +++++++++++++++++++++------------ mscore/palette/palettetree.h | 5 +- 2 files changed, 171 insertions(+), 90 deletions(-) diff --git a/mscore/palette/palettetree.cpp b/mscore/palette/palettetree.cpp index e76999c1bfb3a..2c882caddc0cd 100644 --- a/mscore/palette/palettetree.cpp +++ b/mscore/palette/palettetree.cpp @@ -928,144 +928,222 @@ void PaletteTree::retranslate() p->retranslate(); } +//--------------------------------------------------------- +// paintIconElement +/// Paint an icon element so that it fills a QRect, preserving +/// aspect ratio, and leaving a small margin around the edges. +//--------------------------------------------------------- + +static void paintIconElement(QPainter& painter, const QRect& rect, Element* e) + { + Q_ASSERT(e && e->isIcon()); + painter.save(); // so we can restore it after we are done using it + + constexpr int margin = 4.0; + qreal extent = qMin(rect.height(), rect.width()) - margin; + + Icon* icon = toIcon(e); + icon->setExtent(extent); + + extent /= 2.0; + QPointF iconCenter(extent, extent); + + painter.translate(rect.center() - iconCenter); // change coordinates + icon->draw(&painter); + painter.restore(); // restore coordinates + } + //--------------------------------------------------------- // paintPaletteElement +/// Function object for use with Element::scanElements() to +/// paint an element and its child elements. //--------------------------------------------------------- static void paintPaletteElement(void* data, Element* e) { QPainter* p = static_cast(data); p->save(); - p->translate(e->pos()); + p->translate(e->pos()); // necessary for drawing child elements e->draw(p); p->restore(); } //--------------------------------------------------------- -// PaletteCellIconEngine::paint +// paintScoreElement +/// Paint a non-icon element centered at the origin of the +/// painter's coordinate system. If alignToStaff is true then +/// the element is only centered horizontally; i.e. vertical +/// alignment is unchanged from the default so that item will +/// appear at the correct height on the staff. //--------------------------------------------------------- -void PaletteCellIconEngine::paint(QPainter* painter, const QRect& r, QIcon::Mode mode, QIcon::State state) +static void paintScoreElement(QPainter& p, Element* e, qreal spatium, bool alignToStaff) { - const bool selected = mode == QIcon::Selected; + Q_ASSERT(e && !e->isIcon()); + p.save(); // so we can restore painter after we are done using it - const qreal oldSpatium = gscore->spatium(); + const qreal sizeRatio = spatium / gscore->spatium(); + p.scale(sizeRatio, sizeRatio); // scale coordinates so element is drawn at correct size - qreal _spatium = gscore->spatium(); -// qreal mag = PALETTE_SPATIUM * _extraMag * guiScaling / _spatium; - qreal mag = PALETTE_SPATIUM * _extraMag / _spatium; - gscore->setSpatium(SPATIUM20); + e->layout(); // calculate bbox + QPointF origin = e->bbox().center(); - QPainter& p = *painter; + if (alignToStaff) { + origin.setY(0.0); // y = 0 is position of the element's parent. + // If the parent is the staff (or a segment on the staff) then + // y = 0 corresponds to the position of the top staff line. + } - const int hgrid = r.width(); - const int vgrid = r.height(); + p.translate(-1.0 * origin); // shift coordinates so element is drawn at correct position - qreal dy = lrint(2 * PALETTE_SPATIUM * _extraMag); + e->scanElements(&p, paintPaletteElement); + p.restore(); // return painter to saved initial state + } - // - // draw symbols - // +//--------------------------------------------------------- +// paintStaff +/// Paint a 5 line staff centered within a QRect and return the +/// distance from the top of the QRect to the uppermost staff line. +//--------------------------------------------------------- - // QPen pen(palette().color(QPalette::Normal, QPalette::Text)); +static qreal paintStaff(QPainter& p, const QRect& rect, qreal spatium) + { + p.save(); // so we can restore painter after we are done using it QPen pen(Qt::black); - pen.setWidthF(MScore::defaultStyle().value(Sid::staffLineWidth).toDouble() * PALETTE_SPATIUM * _extraMag); + pen.setWidthF(MScore::defaultStyle().value(Sid::staffLineWidth).toDouble() * spatium); + p.setPen(pen); - const qreal _yOffset = 0.0; // TODO + constexpr int numStaffLines = 5; + const qreal staffHeight = spatium * (numStaffLines - 1); + const qreal topLineDist = rect.center().y() - (staffHeight / 2.0); - const int yoffset = gscore->spatium() * _yOffset; - const QRect rShift = r.translated(0, yoffset); - p.setPen(pen); - QColor c(MScore::selectColor[0]); - if (selected) { - c.setAlpha(100); - p.fillRect(r, c); + // lines bounded horizontally by edge of target (with small margin) + constexpr qreal margin = 3.0; + const qreal x1 = rect.left() + margin; + const qreal x2 = rect.right() - margin; + + // draw staff lines with middle line centered vertically on target + qreal y = topLineDist; + for (int i = 0; i < numStaffLines; ++i) { + p.drawLine(QLineF(x1, y, x2, y)); + y += spatium; } - else if (state == QIcon::On) { - c.setAlpha(60); + + p.restore(); // return painter to saved initial state + return topLineDist; + } + +//--------------------------------------------------------- +// paintBackground +//--------------------------------------------------------- + +static void paintBackground(QPainter& p, const QRect& r, bool selected, bool current) + { + QColor c(MScore::selectColor[0]); + if (current || selected) { + c.setAlpha(selected ? 100 : 60); p.fillRect(r, c); } + } - PaletteCellConstPtr cc = cell(); +//--------------------------------------------------------- +// paintTag +//--------------------------------------------------------- - if (!cc) +static void paintTag(QPainter& painter, const QRect& rect, QString tag) + { + if (tag.isEmpty()) return; - QString tag = cc->tag; - if (!tag.isEmpty()) { - p.setPen(Qt::darkGray); - QFont f(p.font()); - f.setPointSize(12); - p.setFont(f); - if (tag == "ShowMore") - p.drawText(r, Qt::AlignCenter, "???"); - else - p.drawText(rShift, Qt::AlignLeft | Qt::AlignTop, tag); - } + painter.save(); // so we can restore it after we are done using it + painter.setPen(Qt::darkGray); + QFont f(painter.font()); + f.setPointSize(12); + painter.setFont(f); - p.setPen(pen); + if (tag == "ShowMore") + painter.drawText(rect, Qt::AlignCenter, "???"); + else + painter.drawText(rect, Qt::AlignLeft | Qt::AlignTop, tag); - Element* el = cc->element.get(); - if (!el) - return; + painter.restore(); // return to saved initial state (undo pen and font changes, etc.) + } - const bool drawStaff = cc->drawStaff; +//--------------------------------------------------------- +// elementColor +//--------------------------------------------------------- - qreal cellMag = cc->mag * mag; - if (el->isIcon()) { - toIcon(el)->setExtent((hgrid < vgrid ? hgrid : vgrid) - 4); - cellMag = 1.0; - } - el->layout(); +static QColor elementColor(Element* el, bool selected) + { + Q_ASSERT(el); - if (drawStaff) { - qreal y = r.y() + vgrid * .5 - dy + _yOffset * _spatium * cellMag; - qreal x = r.x() + 3; - qreal w = hgrid - 6; - for (int i = 0; i < 5; ++i) { - qreal yy = y + PALETTE_SPATIUM * i * _extraMag; - p.drawLine(QLineF(x, yy, x + w, yy)); - } + if (selected) + return QApplication::palette(mscore).color(QPalette::Normal, QPalette::HighlightedText); + + if (el->isChord()) { + return el->curColor(); // Show voice colors for notes. + // This is used in the "drumtools" palette that appears + // when entering notes on an unpitched percussion staff. } - p.save(); - p.setRenderHint(QPainter::Antialiasing, true); // TODO: needed? - p.scale(cellMag, cellMag); - double gw = hgrid / cellMag; - double gh = vgrid / cellMag; - const double gx = r.x() + cc->xoffset * _spatium; - const double gy = r.y() + cc->yoffset * _spatium; + return QApplication::palette(mscore).color(QPalette::Normal, QPalette::Text); + } - double sw = el->width(); - double sh = el->height(); - double sy; +//--------------------------------------------------------- +// PaletteCellIconEngine::paintCell +//--------------------------------------------------------- - if (drawStaff) - sy = gy + gh * .5 - 2.0 * _spatium; - else - sy = gy + (gh - sh) * .5 - el->bbox().y(); - double sx = gx + (gw - sw) * .5 - el->bbox().x(); +void PaletteCellIconEngine::paintCell(QPainter& p, const QRect& r, bool selected, bool current) const + { + const qreal _yOffset = 0.0; // TODO - sy += _yOffset * _spatium; + paintBackground(p, r, selected, current); - p.translate(sx, sy); + if (!_cell) + return; - QColor color; - if (selected) - color = QApplication::palette(mscore).color(QPalette::Normal, QPalette::HighlightedText); - else { - // show voice colors for notes - if (el->isChord()) - color = el->curColor(); - else - color = QApplication::palette(mscore).color(QPalette::Normal, QPalette::Text); + paintTag(p, r, _cell->tag); + + Element* el = _cell->element.get(); + if (!el) + return; + + if (el->isIcon()) { + paintIconElement(p, r, el); + return; // never draw staff for icon elements + } + + const bool drawStaff = _cell->drawStaff; + const qreal spatium = PALETTE_SPATIUM * _extraMag * _cell->mag; + + QPointF origin = r.center(); // draw element at center of cell by default + p.translate(0, _yOffset * spatium); // offset both element and staff + + if (drawStaff) { + const qreal topLinePos = paintStaff(p, r, spatium); // draw dummy staff lines onto rect. + origin.setY(topLinePos); // vertical position relative to staff instead of cell center. } + p.translate(origin); + p.translate(_cell->xoffset * spatium, _cell->yoffset * spatium); // additional offset for element only + + QColor color(elementColor(el, selected)); p.setPen(QPen(color)); - el->scanElements(&p, paintPaletteElement); - p.restore(); - gscore->setSpatium(oldSpatium); + paintScoreElement(p, el, spatium, drawStaff); + } + +//--------------------------------------------------------- +// PaletteCellIconEngine::paint +//--------------------------------------------------------- + +void PaletteCellIconEngine::paint(QPainter* painter, const QRect& r, QIcon::Mode mode, QIcon::State state) + { + QPainter& p = *painter; + p.save(); // so we can restore it later + p.setRenderHint(QPainter::Antialiasing, true); + paintCell(p, r, mode == QIcon::Selected, state == QIcon::On); + p.restore(); // return painter to saved initial state (undo any changes to pen, coordinates, font, etc.) } } // namespace Ms diff --git a/mscore/palette/palettetree.h b/mscore/palette/palettetree.h index 727c3a92ad749..33022fa37bf1f 100644 --- a/mscore/palette/palettetree.h +++ b/mscore/palette/palettetree.h @@ -79,13 +79,16 @@ class PaletteCellIconEngine : public QIconEngine { PaletteCellConstPtr cell() const { return _cell; } + private: + void paintCell(QPainter& p, const QRect& r, bool selected, bool current) const; + public: PaletteCellIconEngine(PaletteCellConstPtr cell, qreal extraMag = 1.0) : _cell(cell), _extraMag(extraMag) {} QIconEngine* clone() const override { return new PaletteCellIconEngine(cell(), _extraMag); } - void paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) override; + void paint(QPainter* painter, const QRect& r, QIcon::Mode mode, QIcon::State state) override; }; //--------------------------------------------------------- From 6f61450dd2a711bfc62c4e4f3f1fe9605f5116f2 Mon Sep 17 00:00:00 2001 From: Peter Jonas Date: Sat, 29 Feb 2020 17:23:31 +0000 Subject: [PATCH 24/49] fix #301789: Accessibility: no speech for keysig chooser +collect_artifacts Re-implement the New Score Wizard's key signature chooser as a QListView using the same model as is used by the QML palettes. QListViews are accessible by default. --- mscore/CMakeLists.txt | 1 + mscore/newwizard.cpp | 27 ++------ mscore/newwizard.h | 4 +- mscore/palette/palettelistview.cpp | 108 +++++++++++++++++++++++++++++ mscore/palette/palettelistview.h | 60 ++++++++++++++++ mscore/palette/palettemodel.cpp | 5 +- 6 files changed, 182 insertions(+), 23 deletions(-) create mode 100644 mscore/palette/palettelistview.cpp create mode 100644 mscore/palette/palettelistview.h diff --git a/mscore/CMakeLists.txt b/mscore/CMakeLists.txt index 8967588e9874d..504da3fd67e08 100644 --- a/mscore/CMakeLists.txt +++ b/mscore/CMakeLists.txt @@ -460,6 +460,7 @@ add_library(mscoreapp STATIC palette/createpalettedialog.cpp palette/palettedialog.cpp palette/palettecelldialog.cpp palette/palettemodel.cpp palette/palettetree.cpp palette/paletteworkspace.cpp palette/palettewidget.cpp + palette/palettelistview.cpp scorecmp/scorecmp.cpp scorecmp/scorediffmodel.cpp scorecmp/scorelistmodel.cpp resourceManager.cpp downloadUtils.cpp textcursor.cpp continuouspanel.cpp accessibletoolbutton.cpp scoreaccessibility.cpp diff --git a/mscore/newwizard.cpp b/mscore/newwizard.cpp index c99b333cb086c..6b93328d27dc6 100644 --- a/mscore/newwizard.cpp +++ b/mscore/newwizard.cpp @@ -21,7 +21,7 @@ #include "newwizard.h" #include "musescore.h" #include "preferences.h" -#include "palette.h" +#include "palette/palettelistview.h" #include "instrdialog.h" #include "templateBrowser.h" #include "extension.h" @@ -383,25 +383,14 @@ NewWizardKeysigPage::NewWizardKeysigPage(QWidget* parent) b1->setTitle(tr("Key Signature")); b1->setAccessibleName(b1->title()); b1->setAccessibleDescription(tr("Choose a key signature")); - sp = MuseScore::newKeySigPalette(); - sp->setMoreElements(false); - sp->setShowContextMenu(false); - sp->setSelectable(true); - sp->setDisableElementsApply(true); - int keysigCMajorIdx = 14; - sp->setSelected(keysigCMajorIdx); - PaletteScrollArea* sa = new PaletteScrollArea(sp); - // set widget name to include name of selected element - // we could set the description, but some screen readers ignore it - QString name = tr("Key Signature: %1").arg(qApp->translate("Palette", sp->cellAt(keysigCMajorIdx)->name.toUtf8())); - ScoreAccessibility::makeReadable(name); - sa->setAccessibleName(name); - QAccessibleEvent event(sa, QAccessible::NameChanged); - QAccessible::updateAccessibility(&event); + QVBoxLayout* l1 = new QVBoxLayout; - l1->addWidget(sa); b1->setLayout(l1); + _plv = new PaletteListView(mscore->newKeySigPalettePanel()); + l1->addWidget(_plv); + _plv->setCurrentRow(14); // C Major + tempoGroup = new QGroupBox; tempoGroup->setCheckable(true); tempoGroup->setChecked(false); @@ -435,9 +424,7 @@ NewWizardKeysigPage::NewWizardKeysigPage(QWidget* parent) KeySigEvent NewWizardKeysigPage::keysig() const { - int idx = sp->getSelectedIdx(); - Element* e = sp->element(idx); - return static_cast(e)->keySigEvent(); + return static_cast(_plv->currentElement())->keySigEvent(); } //--------------------------------------------------------- diff --git a/mscore/newwizard.h b/mscore/newwizard.h index 658b4e67c504a..c61c0a6ac1a16 100644 --- a/mscore/newwizard.h +++ b/mscore/newwizard.h @@ -32,7 +32,7 @@ namespace Ms { class Score; -class Palette; +class PaletteListView; class StaffListItem; class InstrumentsWidget; class TemplateBrowser; @@ -158,7 +158,7 @@ class NewWizardTemplatePage : public QWizardPage { class NewWizardKeysigPage : public QWizardPage { Q_OBJECT - Palette* sp; + PaletteListView* _plv; QDoubleSpinBox* _tempo; QGroupBox* tempoGroup; diff --git a/mscore/palette/palettelistview.cpp b/mscore/palette/palettelistview.cpp new file mode 100644 index 0000000000000..b9fdf6bf42e55 --- /dev/null +++ b/mscore/palette/palettelistview.cpp @@ -0,0 +1,108 @@ +//============================================================================= +// PaletteListView +// +// Copyright (C) 2020 Peter Jonas +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 +// as published by the Free Software Foundation and appearing in +// the file LICENCE.GPL +//============================================================================= + +#include "palettelistview.h" + +#include "palettemodel.h" + +namespace Ms { + +//--------------------------------------------------------- +// PaletteListView::PaletteListView +//--------------------------------------------------------- + +PaletteListView::PaletteListView(PalettePanel* panel, QWidget* parent) + : QListView(parent) + { + setViewMode(QListView::IconMode); + setMovement(QListView::Static); + setResizeMode(QListView::Adjust); + setIconSize(panel->gridSize()); + setSpacing(-5); // zero spacing still has a large gap between icons + + PaletteTree* tree = new PaletteTree(); + tree->append(panel); + + PaletteTreeModel* model = new PaletteTreeModel(tree); + QModelIndex parentCategory = model->index(0, 0, QModelIndex()); + + setModel(model); + setRootIndex(parentCategory); + } + +//--------------------------------------------------------- +// PaletteListView::currentCell +//--------------------------------------------------------- + +const PaletteCell* PaletteListView::currentCell() const + { + return model()->data(currentIndex(), PaletteTreeModel::PaletteCellRole).value(); + } + +//--------------------------------------------------------- +// PaletteListView::currentElement +//--------------------------------------------------------- + +Element* PaletteListView::currentElement() const + { + return currentCell()->element.get(); + } + +//--------------------------------------------------------- +// PaletteListView::focusNextMatchingCell +//--------------------------------------------------------- + +void PaletteListView::focusNextMatchingCell(const QString& str) + { + const int nextRow = (currentRow() == count() - 1) ? 0 : currentRow() + 1; + const QModelIndex nextIndex = model()->index(nextRow, 0, rootIndex()); + const auto matchedIndexList = model()->match(nextIndex, Qt::ToolTipRole, str); + if (!matchedIndexList.isEmpty()) + setCurrentIndex(matchedIndexList.first()); + } + +//--------------------------------------------------------- +// onlyContainsVisibleCharacters +/// Return true if string is non-empty and contains no whitespace +/// or control characters, otherwise false. +//--------------------------------------------------------- + +static bool onlyContainsVisibleCharacters(const QString& str) + { + constexpr auto options = QRegularExpression::UseUnicodePropertiesOption; + const QRegularExpression pattern("^[[:graph:]]+$", options); + return pattern.match(str).hasMatch(); + } + +//--------------------------------------------------------- +// PaletteListView::keyPressEvent +//--------------------------------------------------------- + +void PaletteListView::keyPressEvent(QKeyEvent* event) + { + const int key = event->key(); + switch (key) { + case Qt::Key_Down: + case Qt::Key_Right: + incrementCurrentRow(); + break; + case Qt::Key_Up: + case Qt::Key_Left: + decrementCurrentRow(); + break; + default: + if (onlyContainsVisibleCharacters(event->text())) + focusNextMatchingCell(event->text()); + else + QListView::keyPressEvent(event); + } + } +} diff --git a/mscore/palette/palettelistview.h b/mscore/palette/palettelistview.h new file mode 100644 index 0000000000000..7576e9b73e755 --- /dev/null +++ b/mscore/palette/palettelistview.h @@ -0,0 +1,60 @@ +//============================================================================= +// PaletteListView +// +// Copyright (C) 2020 Peter Jonas +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 +// as published by the Free Software Foundation and appearing in +// the file LICENCE.GPL +//============================================================================= + +#ifndef __PALETTELISTVIEW_H__ +#define __PALETTELISTVIEW_H__ + +namespace Ms { + +class Element; +class PalettePanel; + +struct PaletteCell; + +//--------------------------------------------------------- +// PaletteListView +/// Display a simple icon list of elements from a single +/// palette category (e.g. key signatures). +//--------------------------------------------------------- + +class PaletteListView : public QListView // see also QListWidget + { + Q_OBJECT + + public: + PaletteListView(PalettePanel* panel, QWidget* parent = nullptr); + const PaletteCell* currentCell() const; + Element* currentElement() const; + void focusNextMatchingCell(const QString& str); + + int count() { return model()->rowCount(rootIndex()); } + int currentRow() { return currentIndex().row(); } + void setCurrentRow(int row) { setCurrentIndex(model()->index(row, 0, rootIndex())); } + + void incrementCurrentRow() + { + if (currentRow() < (count() - 1)) + setCurrentRow(currentRow() + 1); + } + + void decrementCurrentRow() + { + if (currentRow() > 0) + setCurrentRow(currentRow() - 1); + } + + protected: + virtual void keyPressEvent(QKeyEvent* event) override; + + }; +} + +#endif // __PALETTELISTVIEW_H__ diff --git a/mscore/palette/palettemodel.cpp b/mscore/palette/palettemodel.cpp index 9e227bfe95faa..e09ab1252287f 100644 --- a/mscore/palette/palettemodel.cpp +++ b/mscore/palette/palettemodel.cpp @@ -278,7 +278,10 @@ QVariant PaletteTreeModel::data(const QModelIndex& index, int role) const if (PaletteCellConstPtr cell = findCell(index)) { switch (role) { - case Qt::DisplayRole: // TODO don't display cell names in palettes + case Qt::DisplayRole: + return QVariant(); // Don't show element names in + // item views (i.e. just show icons). If you need + // to know the name, use the ToolTip instead. case Qt::ToolTipRole: return cell->translatedName(); case Qt::AccessibleTextRole: { From f6fb8c1a8678044d0025124867d246bab9ae6864 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sun, 1 Mar 2020 11:48:32 +0100 Subject: [PATCH 25/49] fix #301786: Add Barbershop template for women and shortened the men's version (too) by 6 measures for them to fit one page (like the other templates), for their thumbnails to include the final barline --- .../02-Choral/08-Barbershop_Quartet.mscx | 99 --- .../11-Barbershop_Quartet_(Women).mscx | 683 ++++++++++++++++++ share/templates/CMakeLists.txt | 1 + 3 files changed, 684 insertions(+), 99 deletions(-) create mode 100644 share/templates/02-Choral/11-Barbershop_Quartet_(Women).mscx diff --git a/share/templates/02-Choral/08-Barbershop_Quartet.mscx b/share/templates/02-Choral/08-Barbershop_Quartet.mscx index cad1531a4602a..e14f6c01d14df 100644 --- a/share/templates/02-Choral/08-Barbershop_Quartet.mscx +++ b/share/templates/02-Choral/08-Barbershop_Quartet.mscx @@ -416,57 +416,6 @@ BASS - - - line - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -729,54 +678,6 @@ BASS - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - diff --git a/share/templates/02-Choral/11-Barbershop_Quartet_(Women).mscx b/share/templates/02-Choral/11-Barbershop_Quartet_(Women).mscx new file mode 100644 index 0000000000000..ed0eb6519969b --- /dev/null +++ b/share/templates/02-Choral/11-Barbershop_Quartet_(Women).mscx @@ -0,0 +1,683 @@ + + + 3.0.0 + 3543170 + + + 0 + + + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + stdNormal + + G + + + TENOR LEAD + + TENOR +LEAD + Tenor/Lead + 56 + 84 + 56 + 79 + voice.soprano + G8vb + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + Fluid + + + + Fluid + + + + + + + stdNormal + + G + F8va + + BARITONE BASS + + BARI +BASS + Baritone/Bass + 51 + 81 + 51 + 77 + voice.alto + F + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + Fluid + + + + Fluid + + + + + + 10 + + + Barbershop Quartet (Women) + + + + + + 4 + 4 + + + + + + + 0 + T/L + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + + + 4 + 4 + + + + + + + 0 + B/B + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + + measure + 4/4 + + + + + + diff --git a/share/templates/CMakeLists.txt b/share/templates/CMakeLists.txt index d480c597ab551..fef91a89ae123 100644 --- a/share/templates/CMakeLists.txt +++ b/share/templates/CMakeLists.txt @@ -41,6 +41,7 @@ install(FILES 02-Choral/08-Barbershop_Quartet.mscx 02-Choral/09-Liturgical_Unmetrical.mscx 02-Choral/10-Liturgical_Unmetrical_+_Organ.mscx + 02-Choral/11-Barbershop_Quartet_\(Women\).mscx DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}templates/02-Choral ) From abe2fe50953514affcc2586da15fcb10241f1aa7 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sun, 1 Mar 2020 11:51:22 +0100 Subject: [PATCH 26/49] Rename Choral templates for better sorting +collect_artifacts --- ...shop_Quartet.mscx => 08-Barbershop_Quartet_(Men).mscx} | 2 +- ...et_(Women).mscx => 09-Barbershop_Quartet_(Women).mscx} | 0 ...ical_Unmetrical.mscx => 10-Liturgical_Unmetrical.mscx} | 0 ...+_Organ.mscx => 11-Liturgical_Unmetrical_+_Organ.mscx} | 0 share/templates/CMakeLists.txt | 8 ++++---- 5 files changed, 5 insertions(+), 5 deletions(-) rename share/templates/02-Choral/{08-Barbershop_Quartet.mscx => 08-Barbershop_Quartet_(Men).mscx} (99%) rename share/templates/02-Choral/{11-Barbershop_Quartet_(Women).mscx => 09-Barbershop_Quartet_(Women).mscx} (100%) rename share/templates/02-Choral/{09-Liturgical_Unmetrical.mscx => 10-Liturgical_Unmetrical.mscx} (100%) rename share/templates/02-Choral/{10-Liturgical_Unmetrical_+_Organ.mscx => 11-Liturgical_Unmetrical_+_Organ.mscx} (100%) diff --git a/share/templates/02-Choral/08-Barbershop_Quartet.mscx b/share/templates/02-Choral/08-Barbershop_Quartet_(Men).mscx similarity index 99% rename from share/templates/02-Choral/08-Barbershop_Quartet.mscx rename to share/templates/02-Choral/08-Barbershop_Quartet_(Men).mscx index e14f6c01d14df..5ce1dc00083e4 100644 --- a/share/templates/02-Choral/08-Barbershop_Quartet.mscx +++ b/share/templates/02-Choral/08-Barbershop_Quartet_(Men).mscx @@ -157,7 +157,7 @@ BASS 10 - Barbershop Quartet + Barbershop Quartet (Men) diff --git a/share/templates/02-Choral/11-Barbershop_Quartet_(Women).mscx b/share/templates/02-Choral/09-Barbershop_Quartet_(Women).mscx similarity index 100% rename from share/templates/02-Choral/11-Barbershop_Quartet_(Women).mscx rename to share/templates/02-Choral/09-Barbershop_Quartet_(Women).mscx diff --git a/share/templates/02-Choral/09-Liturgical_Unmetrical.mscx b/share/templates/02-Choral/10-Liturgical_Unmetrical.mscx similarity index 100% rename from share/templates/02-Choral/09-Liturgical_Unmetrical.mscx rename to share/templates/02-Choral/10-Liturgical_Unmetrical.mscx diff --git a/share/templates/02-Choral/10-Liturgical_Unmetrical_+_Organ.mscx b/share/templates/02-Choral/11-Liturgical_Unmetrical_+_Organ.mscx similarity index 100% rename from share/templates/02-Choral/10-Liturgical_Unmetrical_+_Organ.mscx rename to share/templates/02-Choral/11-Liturgical_Unmetrical_+_Organ.mscx diff --git a/share/templates/CMakeLists.txt b/share/templates/CMakeLists.txt index fef91a89ae123..871feb61992f6 100644 --- a/share/templates/CMakeLists.txt +++ b/share/templates/CMakeLists.txt @@ -38,10 +38,10 @@ install(FILES 02-Choral/05-SATB_Closed_Score_+_Organ.mscx 02-Choral/06-SATB_Closed_Score_+_Piano.mscx 02-Choral/07-Voice_+_Piano.mscx - 02-Choral/08-Barbershop_Quartet.mscx - 02-Choral/09-Liturgical_Unmetrical.mscx - 02-Choral/10-Liturgical_Unmetrical_+_Organ.mscx - 02-Choral/11-Barbershop_Quartet_\(Women\).mscx + 02-Choral/08-Barbershop_Quartet_\(Men\).mscx + 02-Choral/09-Barbershop_Quartet_\(Women\).mscx + 02-Choral/10-Liturgical_Unmetrical.mscx + 02-Choral/11-Liturgical_Unmetrical_+_Organ.mscx DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}templates/02-Choral ) From fdf1fef643052b2295328d092e8682c0ee184165 Mon Sep 17 00:00:00 2001 From: Daniel Flynn Date: Sat, 29 Feb 2020 17:28:43 -0600 Subject: [PATCH 27/49] fix #301753: figured bass under rests Altered condition within libmscore/figuredbass.cpp to allow for figures to be written under rests --- libmscore/figuredbass.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libmscore/figuredbass.cpp b/libmscore/figuredbass.cpp index 9f7418cbcc05a..c96337beecd56 100644 --- a/libmscore/figuredbass.cpp +++ b/libmscore/figuredbass.cpp @@ -1749,7 +1749,7 @@ void FiguredBass::writeMusicXML(XmlWriter& xml, bool isOriginalFigure, int crEnd FiguredBass* Score::addFiguredBass() { Element* el = selection().element(); - if (el == 0 || (el->type() != ElementType::NOTE && el->type() != ElementType::FIGURED_BASS)) { + if (!el || (!(el->isNote()) && !(el->isRest()) && !(el->isFiguredBass()))) { MScore::setError(NO_NOTE_FIGUREDBASS_SELECTED); return 0; } @@ -1760,6 +1760,10 @@ FiguredBass* Score::addFiguredBass() ChordRest * cr = toNote(el)->chord(); fb = FiguredBass::addFiguredBassToSegment(cr->segment(), cr->staffIdx() * VOICES, Fraction(0,1), &bNew); } + else if (el->isRest()) { + ChordRest* cr = toRest(el); + fb = FiguredBass::addFiguredBassToSegment(cr->segment(), cr->staffIdx() * VOICES, Fraction(0, 1), &bNew); + } else if (el->isFiguredBass()) { fb = toFiguredBass(el); bNew = false; From 01dd64584fede030175314ddd80007d9d96b5775 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sun, 1 Mar 2020 14:24:19 +0100 Subject: [PATCH 28/49] Make the remaining templates to fit one page for a better thumbnail --- .../04-Solo/02-Guitar_+_Tablature.mscx | 117 - share/templates/04-Solo/04-Piano.mscx | 99 - .../templates/05-Jazz/01-Jazz_Lead_Sheet.mscx | 1 + share/templates/05-Jazz/02-Big_Band.mscx | 432 ---- share/templates/05-Jazz/03-Jazz_Combo.mscx | 2102 +---------------- share/templates/06-Popular/01-Rock_Band.mscx | 2 +- 6 files changed, 45 insertions(+), 2708 deletions(-) diff --git a/share/templates/04-Solo/02-Guitar_+_Tablature.mscx b/share/templates/04-Solo/02-Guitar_+_Tablature.mscx index a26967f104448..3df60aa1a1a2f 100644 --- a/share/templates/04-Solo/02-Guitar_+_Tablature.mscx +++ b/share/templates/04-Solo/02-Guitar_+_Tablature.mscx @@ -415,63 +415,6 @@ - - - line - - - - - measure - 4/4 - - - - - - - - measure - 4/4 - - - - - - - - measure - 4/4 - - - - - - - - measure - 4/4 - - - - - - - - measure - 4/4 - - - - - - - - measure - 4/4 - - - @@ -787,66 +730,6 @@ - - - - - - measure - 4/4 - - - - - - - - - measure - 4/4 - - - - - - - - - measure - 4/4 - - - - - - - - - measure - 4/4 - - - - - - - - - measure - 4/4 - - - - - - - - - measure - 4/4 - - - diff --git a/share/templates/04-Solo/04-Piano.mscx b/share/templates/04-Solo/04-Piano.mscx index 96545f42bfe84..a65ba80b04117 100644 --- a/share/templates/04-Solo/04-Piano.mscx +++ b/share/templates/04-Solo/04-Piano.mscx @@ -353,57 +353,6 @@ - - - line - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -658,54 +607,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - diff --git a/share/templates/05-Jazz/01-Jazz_Lead_Sheet.mscx b/share/templates/05-Jazz/01-Jazz_Lead_Sheet.mscx index 8283e8ea4e078..e007d7353269d 100644 --- a/share/templates/05-Jazz/01-Jazz_Lead_Sheet.mscx +++ b/share/templates/05-Jazz/01-Jazz_Lead_Sheet.mscx @@ -24,6 +24,7 @@ 0.2 0.2 0.33 + 0.25 0.2 MuseJazz Text 0.2 diff --git a/share/templates/05-Jazz/02-Big_Band.mscx b/share/templates/05-Jazz/02-Big_Band.mscx index f6c0825069b98..2e995e2266531 100644 --- a/share/templates/05-Jazz/02-Big_Band.mscx +++ b/share/templates/05-Jazz/02-Big_Band.mscx @@ -1588,30 +1588,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -1853,30 +1829,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -2118,30 +2070,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -2383,30 +2311,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -2648,30 +2552,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -2913,30 +2793,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -3178,30 +3034,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -3443,30 +3275,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -3708,30 +3516,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -3970,30 +3754,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -4232,30 +3992,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -4494,30 +4230,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -4756,30 +4468,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -5018,30 +4706,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -5280,30 +4944,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -5542,30 +5182,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -5804,30 +5420,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - @@ -6066,30 +5658,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - diff --git a/share/templates/05-Jazz/03-Jazz_Combo.mscx b/share/templates/05-Jazz/03-Jazz_Combo.mscx index 41ff3a7065fae..48a6b5b9ff847 100644 --- a/share/templates/05-Jazz/03-Jazz_Combo.mscx +++ b/share/templates/05-Jazz/03-Jazz_Combo.mscx @@ -850,200 +850,17 @@ + + - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - + + 3 + + + 4 + 4 + measure 4/4 @@ -1075,11 +892,11 @@ - + - 3 + 2 4 @@ -1115,8 +932,14 @@ + + + + 4 + 4 + measure 4/4 @@ -1147,8 +970,14 @@ + + + + 4 + 4 + measure 4/4 @@ -1179,8 +1008,14 @@ + + + + 4 + 4 + measure 4/4 @@ -1211,8 +1046,14 @@ + + + + 4 + 4 + measure 4/4 @@ -1243,8 +1084,14 @@ + + + + 4 + 4 + measure 4/4 @@ -1275,1647 +1122,8 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - - - 2 - - - 4 - 4 - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - - - 4 - 4 - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - - - 4 - 4 - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - - - 4 - 4 - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - - - 4 - 4 - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - - - 4 - 4 - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - + + @@ -2952,230 +1160,6 @@ - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - - - - - measure - 4/4 - - - diff --git a/share/templates/06-Popular/01-Rock_Band.mscx b/share/templates/06-Popular/01-Rock_Band.mscx index ec96cb62a1edc..02bb6498e9bd7 100644 --- a/share/templates/06-Popular/01-Rock_Band.mscx +++ b/share/templates/06-Popular/01-Rock_Band.mscx @@ -9,7 +9,7 @@ 480 1 1 From df19bbd33c1ec31dc73f7a5aef69ffbf8168f8ba Mon Sep 17 00:00:00 2001 From: Leon Vinken Date: Sat, 28 Dec 2019 17:20:21 +0100 Subject: [PATCH 29/49] fix #299661 - [MusicXML export] breaks in horizontal frames not exported --- mscore/exportxml.cpp | 791 ++++--- mscore/musicxml.h | 7 - mtest/musicxml/io/testBreaksImplExpl.mscx | 234 +++ .../io/testBreaksImplExpl_all_ref.xml | 150 ++ .../io/testBreaksImplExpl_manual_ref.xml | 150 ++ .../musicxml/io/testBreaksImplExpl_no_ref.xml | 139 ++ mtest/musicxml/io/testBreaksMMRest.mscx | 260 +++ .../musicxml/io/testBreaksMMRest_all_ref.xml | 152 ++ .../io/testBreaksMMRest_manual_ref.xml | 152 ++ mtest/musicxml/io/testBreaksMMRest_no_ref.xml | 149 ++ mtest/musicxml/io/testBreaksManual.xml | 1804 ++++++++++++++++ .../musicxml/io/testBreaksManual_all_ref.xml | 1815 +++++++++++++++++ .../io/testBreaksManual_manual_ref.xml | 1804 ++++++++++++++++ mtest/musicxml/io/testBreaksManual_no_ref.xml | 1802 ++++++++++++++++ mtest/musicxml/io/testBreaksPage.mscx | 186 ++ mtest/musicxml/io/testBreaksPage_all_ref.xml | 119 ++ .../musicxml/io/testBreaksPage_manual_ref.xml | 119 ++ mtest/musicxml/io/testBreaksPage_no_ref.xml | 115 ++ mtest/musicxml/io/testBreaksSystem.mscx | 235 +++ .../musicxml/io/testBreaksSystem_all_ref.xml | 161 ++ .../io/testBreaksSystem_manual_ref.xml | 161 ++ mtest/musicxml/io/testBreaksSystem_no_ref.xml | 154 ++ mtest/musicxml/io/testManualBreaks.xml | 600 ------ mtest/musicxml/io/testTboxMultiPage1_ref.xml | 1 + mtest/musicxml/io/testTboxWords1_ref.xml | 2 + mtest/musicxml/io/tst_mxml_io.cpp | 66 +- 26 files changed, 10382 insertions(+), 946 deletions(-) create mode 100644 mtest/musicxml/io/testBreaksImplExpl.mscx create mode 100644 mtest/musicxml/io/testBreaksImplExpl_all_ref.xml create mode 100644 mtest/musicxml/io/testBreaksImplExpl_manual_ref.xml create mode 100644 mtest/musicxml/io/testBreaksImplExpl_no_ref.xml create mode 100644 mtest/musicxml/io/testBreaksMMRest.mscx create mode 100644 mtest/musicxml/io/testBreaksMMRest_all_ref.xml create mode 100644 mtest/musicxml/io/testBreaksMMRest_manual_ref.xml create mode 100644 mtest/musicxml/io/testBreaksMMRest_no_ref.xml create mode 100644 mtest/musicxml/io/testBreaksManual.xml create mode 100644 mtest/musicxml/io/testBreaksManual_all_ref.xml create mode 100644 mtest/musicxml/io/testBreaksManual_manual_ref.xml create mode 100644 mtest/musicxml/io/testBreaksManual_no_ref.xml create mode 100644 mtest/musicxml/io/testBreaksPage.mscx create mode 100644 mtest/musicxml/io/testBreaksPage_all_ref.xml create mode 100644 mtest/musicxml/io/testBreaksPage_manual_ref.xml create mode 100644 mtest/musicxml/io/testBreaksPage_no_ref.xml create mode 100644 mtest/musicxml/io/testBreaksSystem.mscx create mode 100644 mtest/musicxml/io/testBreaksSystem_all_ref.xml create mode 100644 mtest/musicxml/io/testBreaksSystem_manual_ref.xml create mode 100644 mtest/musicxml/io/testBreaksSystem_no_ref.xml delete mode 100644 mtest/musicxml/io/testManualBreaks.xml diff --git a/mscore/exportxml.cpp b/mscore/exportxml.cpp index d15b3e8443572..a143900e3553a 100644 --- a/mscore/exportxml.cpp +++ b/mscore/exportxml.cpp @@ -260,6 +260,45 @@ class GlissandoHandler { void doGlissandoStop(Glissando* gliss, Notations& notations, XmlWriter& xml); }; +//--------------------------------------------------------- +// MeasureNumberStateHandler +//--------------------------------------------------------- + +/** + State handler used to calculate measure number including implicit flag. + To be called once at the start of each measure in a part. + */ + +class MeasureNumberStateHandler final + { +public: + MeasureNumberStateHandler(); + void updateForMeasure(const Measure* const m); + QString measureNumber() const; + bool isFirstActualMeasure() const; +private: + void init(); + int _measureNo; // number of next regular measure + int _irregularMeasureNo; // number of next irregular measure + int _pickupMeasureNo; // number of next pickup measure + QString _cachedAttributes; // attributes calculated by updateForMeasure() + }; + +//--------------------------------------------------------- +// MeasurePrintContext +//--------------------------------------------------------- + +struct MeasurePrintContext final + { + void measureWritten(const Measure* m); + bool scoreStart = true; + bool pageStart = true; + bool systemStart = true; + const Measure* prevMeasure = nullptr; + const System* prevSystem = nullptr; + const System* lastSystemPrevPage = nullptr; + }; + //--------------------------------------------------------- // ExportMusicXml //--------------------------------------------------------- @@ -296,9 +335,9 @@ class ExportMusicXml { void clef(int staff, const ClefType ct, const QString& extraAttributes = ""); void timesig(TimeSig* tsig); void keysig(const KeySig* ks, ClefType ct, int staff = 0, bool visible = true); - void barlineLeft(Measure* m); + void barlineLeft(const Measure* const m); void barlineMiddle(const BarLine* bl); - void barlineRight(Measure* m); + void barlineRight(const Measure* const m); void lyrics(const std::vector* ll, const int trk); void work(const MeasureBase* measure); void calcDivMoveToTick(const Fraction& t); @@ -308,10 +347,13 @@ class ExportMusicXml { TrillHash& trillStart, TrillHash& trillStop); void wavyLineStartStop(Chord* chord, Notations& notations, Ornaments& ornaments, TrillHash& trillStart, TrillHash& trillStop); - void print(const Measure* const m, const int partNr, const int firstStaffOfPart, const int nrStavesInPart); - void findAndExportClef(Measure* m, const int staves, const int strack, const int etrack); + void print(const Measure* const m, const int partNr, const int firstStaffOfPart, const int nrStavesInPart, const MeasurePrintContext& mpc); + void findAndExportClef(const Measure* const m, const int staves, const int strack, const int etrack); void exportDefaultClef(const Part* const part, const Measure* const m); void writeElement(Element* el, const Measure* m, int sstaff, bool useDrumset); + void writeMeasureTracks(const Measure* const m, const int partIndex, const int strack, const int staves, const bool useDrumset, FigBassMap& fbMap); + void writeMeasure(const Measure* const m, const int idx, const int staffCount, MeasureNumberStateHandler& mnsh, FigBassMap& fbMap, const MeasurePrintContext& mpc); + void writeParts(); public: ExportMusicXml(Score* s) @@ -897,7 +939,7 @@ class DirectionsAnchor { // find all trills in this measure and this part -static void findTrills(Measure* measure, int strack, int etrack, TrillHash& trillStart, TrillHash& trillStop) +static void findTrills(const Measure* const measure, int strack, int etrack, TrillHash& trillStart, TrillHash& trillStop) { // loop over all spanners in this measure auto stick = measure->tick(); @@ -1446,7 +1488,7 @@ static QString tick2xml(const Fraction& ticks, int* dots) // findVolta -- find volta starting in measure m //--------------------------------------------------------- -static Volta* findVolta(Measure* m, bool left) +static Volta* findVolta(const Measure* const m, bool left) { Fraction stick = m->tick(); Fraction etick = m->tick() + m->ticks(); @@ -1502,7 +1544,7 @@ static void ending(XmlWriter& xml, Volta* v, bool left) // barlineLeft -- search for and handle barline left //--------------------------------------------------------- -void ExportMusicXml::barlineLeft(Measure* m) +void ExportMusicXml::barlineLeft(const Measure* const m) { bool rs = m->repeatStart(); Volta* volta = findVolta(m, true); @@ -1595,7 +1637,7 @@ void ExportMusicXml::barlineMiddle(const BarLine* bl) // barlineRight -- search for and handle barline right //--------------------------------------------------------- -void ExportMusicXml::barlineRight(Measure* m) +void ExportMusicXml::barlineRight(const Measure* const m) { const Measure* mmR1 = m->mmRest1(); // the multi measure rest this measure is covered by const Measure* mmRLst = mmR1->isMMRest() ? mmR1->mmRestLast() : 0; // last measure of replaced sequence of empty measures @@ -4342,7 +4384,7 @@ static int findTrackForAnnotations(int track, Segment* seg) // repeatAtMeasureStart -- write repeats at begin of measure //--------------------------------------------------------- -static void repeatAtMeasureStart(XmlWriter& xml, Attributes& attr, Measure* m, int strack, int etrack, int track) +static void repeatAtMeasureStart(XmlWriter& xml, Attributes& attr, const Measure* const m, int strack, int etrack, int track) { // loop over all segments for (Element* e : m->el()) { @@ -4386,7 +4428,7 @@ static void repeatAtMeasureStart(XmlWriter& xml, Attributes& attr, Measure* m, i // repeatAtMeasureStop -- write repeats at end of measure //--------------------------------------------------------- -static void repeatAtMeasureStop(XmlWriter& xml, Measure* m, int strack, int etrack, int track) +static void repeatAtMeasureStop(XmlWriter& xml, const Measure* const m, int strack, int etrack, int track) { for (Element* e : m->el()) { int wtrack = -1; // track to write jump @@ -4466,7 +4508,7 @@ static bool elementRighter(const Element* e1, const Element* e2) // note: for a normal measure, mmRest1 is the measure itself, // for a multi-meaure rest, it is the replacing measure -static void measureStyle(XmlWriter& xml, Attributes& attr, Measure* m) +static void measureStyle(XmlWriter& xml, Attributes& attr, const Measure* const m) { const Measure* mmR1 = m->mmRest1(); if (m != mmR1 && m == mmR1->mmRestFirst()) { @@ -4971,6 +5013,37 @@ static void initReverseInstrMap(MxmlReverseInstrumentMap& rim, const MxmlInstrum } } +//--------------------------------------------------------- +// hasPageBreak +//--------------------------------------------------------- + +static MeasureBase* lastMeasureBase(const System* const system) + { + MeasureBase* mb = nullptr; + if (system) { + const auto& measures = system->measures(); + Q_ASSERT(!(measures.empty())); + mb = measures.back(); + } + return mb; + } + +//--------------------------------------------------------- +// hasPageBreak +//--------------------------------------------------------- + +static bool hasPageBreak(const System* const system) + { + const MeasureBase* mb = nullptr; + if (system) { + const auto& measures = system->measures(); + Q_ASSERT(!(measures.empty())); + mb = measures.back(); + } + + return mb && mb->pageBreak(); + } + //--------------------------------------------------------- // print //--------------------------------------------------------- @@ -4978,144 +5051,113 @@ static void initReverseInstrMap(MxmlReverseInstrumentMap& rim, const MxmlInstrum /** Handle the element. When exporting layout and all breaks, a with layout information - is generated for the measure types TopSystem, NewSystem and newPage. + is generated for the first measure in the score, in a system or on a page. When exporting layout but only manual or no breaks, a with - layout information is generated only for the measure type TopSystem, + layout information is generated only for the first measure in the score, as it is assumed the system layout is broken by the importing application anyway and is thus useless. + + a page break is explicit (manual) if: + - the last system on the previous page has a page break + a system break is explicit (manual) if: + - the previous system in the score has a system or layout break + - if the previous system in the score does not have measures + (i.e. only has (a) frame(s)) */ -void ExportMusicXml::print(const Measure* const m, const int partNr, const int firstStaffOfPart, const int nrStavesInPart) +void ExportMusicXml::print(const Measure* const m, const int partNr, const int firstStaffOfPart, const int nrStavesInPart, const MeasurePrintContext& mpc) { - int currentSystem = NoSystem; - Measure* previousMeasure = 0; - - for (MeasureBase* currentMeasureB = m->prev(); currentMeasureB; currentMeasureB = currentMeasureB->prev()) { - if (currentMeasureB->type() == ElementType::MEASURE) { - previousMeasure = (Measure*) currentMeasureB; - break; - } - } - - if (!previousMeasure) - currentSystem = TopSystem; - else { - const auto mSystem = m->mmRest1()->system(); - const auto previousMeasureSystem = previousMeasure->mmRest1()->system(); - - if (mSystem && previousMeasureSystem) { - if (mSystem->page() != previousMeasureSystem->page()) - currentSystem = NewPage; - else if (mSystem != previousMeasureSystem) - currentSystem = NewSystem; - } - } - - bool prevMeasLineBreak = false; - bool prevMeasPageBreak = false; - bool prevMeasSectionBreak = false; - if (previousMeasure) { - prevMeasLineBreak = previousMeasure->lineBreak(); - prevMeasPageBreak = previousMeasure->pageBreak(); - prevMeasSectionBreak = previousMeasure->sectionBreak(); - } + const MeasureBase* const prevSysMB = lastMeasureBase(mpc.prevSystem); - if (currentSystem != NoSystem) { + const bool prevMeasLineBreak = prevSysMB ? prevSysMB->lineBreak() : false; + const bool prevMeasSectionBreak = prevSysMB ? prevSysMB->sectionBreak() : false; + const bool prevPageBreak = hasPageBreak(mpc.lastSystemPrevPage); - // determine if a new-system or new-page is required - QString newThing; // new-[system|page]="yes" or empty + QString newSystemOrPage; // new-[system|page]="yes" or empty + if (!mpc.scoreStart) { if (preferences.musicxmlExportBreaks() == MusicxmlExportBreaks::ALL) { - if (currentSystem == NewSystem) - newThing = " new-system=\"yes\""; - else if (currentSystem == NewPage) - newThing = " new-page=\"yes\""; + if (mpc.pageStart) newSystemOrPage = " new-page=\"yes\""; + else if (mpc.systemStart) newSystemOrPage = " new-system=\"yes\""; } else if (preferences.musicxmlExportBreaks() == MusicxmlExportBreaks::MANUAL) { - if (currentSystem == NewSystem && (prevMeasLineBreak || prevMeasSectionBreak)) - newThing = " new-system=\"yes\""; - else if (currentSystem == NewPage && prevMeasPageBreak) - newThing = " new-page=\"yes\""; + if (mpc.pageStart && prevPageBreak) + newSystemOrPage = " new-page=\"yes\""; + else if (mpc.systemStart && (prevMeasLineBreak || prevMeasSectionBreak)) + newSystemOrPage = " new-system=\"yes\""; } + } - // determine if break and layout information is required - bool doBreak = false; - if (currentSystem == TopSystem || newThing != "") { - doBreak = true; - } - bool doLayout = preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT); - - if (doBreak) { - if (doLayout) { - _xml.stag(QString("print%1").arg(newThing)); - const double pageWidth = getTenthsFromInches(score()->styleD(Sid::pageWidth)); - const double lm = getTenthsFromInches(score()->styleD(Sid::pageOddLeftMargin)); - const double rm = getTenthsFromInches(score()->styleD(Sid::pageWidth) - - score()->styleD(Sid::pagePrintableWidth) - score()->styleD(Sid::pageOddLeftMargin)); - const double tm = getTenthsFromInches(score()->styleD(Sid::pageOddTopMargin)); - - // System Layout - - // For a multi-meaure rest positioning is valid only - // in the replacing measure - // note: for a normal measure, mmRest1 is the measure itself, - // for a multi-meaure rest, it is the replacing measure - const Measure* mmR1 = m->mmRest1(); - const System* system = mmR1->system(); - - // Put the system print suggestions only for the first part in a score... - if (partNr == 0) { - - // Find the right margin of the system. - double systemLM = getTenthsFromDots(mmR1->pagePos().x() - system->page()->pagePos().x()) - lm; - double systemRM = pageWidth - rm - (getTenthsFromDots(system->bbox().width()) + lm); - - _xml.stag("system-layout"); - _xml.stag("system-margins"); - _xml.tag("left-margin", QString("%1").arg(QString::number(systemLM,'f',2))); - _xml.tag("right-margin", QString("%1").arg(QString::number(systemRM,'f',2)) ); - _xml.etag(); + bool doBreak = mpc.scoreStart || (newSystemOrPage != ""); + bool doLayout = preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT); - if (currentSystem == NewPage || currentSystem == TopSystem) { - const double topSysDist = getTenthsFromDots(mmR1->pagePos().y()) - tm; - _xml.tag("top-system-distance", QString("%1").arg(QString::number(topSysDist,'f',2)) ); - } - if (currentSystem == NewSystem) { - // see System::layout2() for the factor 2 * score()->spatium() - const double sysDist = getTenthsFromDots(mmR1->pagePos().y() - - previousMeasure->pagePos().y() - - previousMeasure->bbox().height() - + 2 * score()->spatium() - ); - _xml.tag("system-distance", - QString("%1").arg(QString::number(sysDist,'f',2))); - } + if (doBreak) { + if (doLayout) { + _xml.stag(QString("print%1").arg(newSystemOrPage)); + const double pageWidth = getTenthsFromInches(score()->styleD(Sid::pageWidth)); + const double lm = getTenthsFromInches(score()->styleD(Sid::pageOddLeftMargin)); + const double rm = getTenthsFromInches(score()->styleD(Sid::pageWidth) + - score()->styleD(Sid::pagePrintableWidth) - score()->styleD(Sid::pageOddLeftMargin)); + const double tm = getTenthsFromInches(score()->styleD(Sid::pageOddTopMargin)); - _xml.etag(); - } + // System Layout - // Staff layout elements. - for (int staffIdx = (firstStaffOfPart == 0) ? 1 : 0; staffIdx < nrStavesInPart; staffIdx++) { + // For a multi-meaure rest positioning is valid only + // in the replacing measure + // note: for a normal measure, mmRest1 is the measure itself, + // for a multi-meaure rest, it is the replacing measure + const Measure* mmR1 = m->mmRest1(); + const System* system = mmR1->system(); - // calculate distance between this and previous staff using the bounding boxes - const auto staffNr = firstStaffOfPart + staffIdx; - const auto prevBbox = system->staff(staffNr - 1)->bbox(); - const auto staffDist = system->staff(staffNr)->bbox().y() - prevBbox.y() - prevBbox.height(); + // Put the system print suggestions only for the first part in a score... + if (partNr == 0) { - _xml.stag(QString("staff-layout number=\"%1\"").arg(staffIdx + 1)); - _xml.tag("staff-distance", QString("%1").arg(QString::number(getTenthsFromDots(staffDist),'f',2))); - _xml.etag(); + // Find the right margin of the system. + double systemLM = getTenthsFromDots(mmR1->pagePos().x() - system->page()->pagePos().x()) - lm; + double systemRM = pageWidth - rm - (getTenthsFromDots(system->bbox().width()) + lm); + + _xml.stag("system-layout"); + _xml.stag("system-margins"); + _xml.tag("left-margin", QString("%1").arg(QString::number(systemLM,'f',2))); + _xml.tag("right-margin", QString("%1").arg(QString::number(systemRM,'f',2)) ); + _xml.etag(); + + if (mpc.pageStart || mpc.scoreStart) { + const double topSysDist = getTenthsFromDots(mmR1->pagePos().y()) - tm; + _xml.tag("top-system-distance", QString("%1").arg(QString::number(topSysDist,'f',2)) ); + } + if (mpc.systemStart && !mpc.scoreStart) { + // see System::layout2() for the factor 2 * score()->spatium() + const double sysDist = getTenthsFromDots(mmR1->pagePos().y() + - mpc.prevMeasure->pagePos().y() + - mpc.prevMeasure->bbox().height() + + 2 * score()->spatium() + ); + _xml.tag("system-distance", + QString("%1").arg(QString::number(sysDist,'f',2))); } _xml.etag(); } - else if (newThing != "") { - _xml.tagE(QString("print%1").arg(newThing)); - } - } // if (!doBreak) ... + // Staff layout elements. + for (int staffIdx = (firstStaffOfPart == 0) ? 1 : 0; staffIdx < nrStavesInPart; staffIdx++) { - } // if (currentSystem ... + // calculate distance between this and previous staff using the bounding boxes + const auto staffNr = firstStaffOfPart + staffIdx; + const auto prevBbox = system->staff(staffNr - 1)->bbox(); + const auto staffDist = system->staff(staffNr)->bbox().y() - prevBbox.y() - prevBbox.height(); + _xml.stag(QString("staff-layout number=\"%1\"").arg(staffIdx + 1)); + _xml.tag("staff-distance", QString("%1").arg(QString::number(getTenthsFromDots(staffDist),'f',2))); + _xml.etag(); + } + + _xml.etag(); + } + else if (newSystemOrPage != "") { + _xml.tagE(QString("print%1").arg(newSystemOrPage)); + } + } } //--------------------------------------------------------- @@ -5178,7 +5220,7 @@ void ExportMusicXml::exportDefaultClef(const Part* const part, const Measure* co Make sure clefs at end of measure get exported at start of next measure. */ -void ExportMusicXml::findAndExportClef(Measure* m, const int staves, const int strack, const int etrack) +void ExportMusicXml::findAndExportClef(const Measure* const m, const int staves, const int strack, const int etrack) { Measure* prevMeasure = m->prevMeasure(); Measure* mmR = m->mmRest(); // the replacing measure in a multi-measure rest @@ -5305,15 +5347,16 @@ static void findPitchesUsed(const Part* part, pitchSet& set) Write the part list to \a xml. */ -static void partList(XmlWriter& xml, Score* score, const QList& il, MxmlInstrumentMap& instrMap) +static void partList(XmlWriter& xml, Score* score, MxmlInstrumentMap& instrMap) { xml.stag("part-list"); int staffCount = 0; // count sum of # staves in parts + const auto& parts = score->parts(); int partGroupEnd[MAX_PART_GROUPS]; // staff where part group ends (bracketSpan is in staves, not parts) for (int i = 0; i < MAX_PART_GROUPS; i++) partGroupEnd[i] = -1; - for (int idx = 0; idx < il.size(); ++idx) { - Part* part = il.at(idx); + for (int idx = 0; idx < parts.size(); ++idx) { + const auto part = parts.at(idx); bool bracketFound = false; // handle brackets for (int i = 0; i < part->nstaves(); i++) { @@ -5589,26 +5632,6 @@ static void annotationsWithoutNote(ExportMusicXml* exp, const int strack, const // MeasureNumberStateHandler //--------------------------------------------------------- -/** - State handler used to calculate measure number including implicit flag. - To be called once at the start of each measure in a part. - */ - -class MeasureNumberStateHandler final - { -public: - MeasureNumberStateHandler(); - void updateForMeasure(const Measure* const m); - QString measureNumber() const; - bool isFirstActualMeasure() const; -private: - void init(); - int _measureNo; // number of next regular measure - int _irregularMeasureNo; // number of next irregular measure - int _pickupMeasureNo; // number of next pickup measure - QString _cachedAttributes; // attributes calculated by updateForMeasure() - }; - MeasureNumberStateHandler::MeasureNumberStateHandler() { init(); @@ -5764,246 +5787,342 @@ static std::vector findTextFramesToWriteAsWordsBelow(const Measure* const } //--------------------------------------------------------- -// write +// writeMeasureTracks //--------------------------------------------------------- /** - Write the score to \a dev in MusicXML format. + Write data contained in the measure's tracks. */ -void ExportMusicXml::write(QIODevice* dev) - { - // must export in transposed pitch to prevent - // losing the transposition information - // if necessary, switch concert pitch mode off - // before export and restore it after export - bool concertPitch = score()->styleB(Sid::concertPitch); - if (concertPitch) { - score()->startCmd(); - score()->undo(new ChangeStyleVal(score(), Sid::concertPitch, false)); - score()->doLayout(); // this is only allowed in a cmd context to not corrupt the undo/redo stack - } +void ExportMusicXml::writeMeasureTracks(const Measure* const m, + const int partIndex, + const int strack, const int staves, // TODO remove ?? + const bool useDrumset, + FigBassMap& fbMap) + { + bool tboxesAboveWritten = false; + const auto tboxesAbove = findTextFramesToWriteAsWordsAbove(m); + + bool tboxesBelowWritten = false; + const auto tboxesBelow = findTextFramesToWriteAsWordsBelow(m); + + const int etrack = strack + VOICES * staves; + // set of spanners already stopped in this measure + // required to prevent multiple spanner stops for the same spanner + QSet spannersStopped; + + for (int st = strack; st < etrack; ++st) { + // sstaff - xml staff number, counting from 1 for this + // instrument + // special number 0 -> don’t show staff number in + // xml output (because there is only one staff) + + int sstaff = (staves > 1) ? st - strack + VOICES : 0; + sstaff /= VOICES; + for (auto seg = m->first(); seg; seg = seg->next()) { + const auto el = seg->element(st); + if (!el) { + continue; + } + // must ignore start repeat to prevent spurious backup/forward + if (el->isBarLine() && toBarLine(el)->barLineType() == BarLineType::START_REPEAT) + continue; - calcDivisions(); + // generate backup or forward to the start time of the element + if (_tick != seg->tick()) { + _attr.doAttr(_xml, false); + moveToTick(seg->tick()); + } - for (int i = 0; i < MAX_NUMBER_LEVEL; ++i) { - brackets[i] = nullptr; - dashes[i] = nullptr; - hairpins[i] = nullptr; - ottavas[i] = nullptr; - trills[i] = nullptr; - } + // handle annotations and spanners (directions attached to this note or rest) + if (el->isChordRest()) { + _attr.doAttr(_xml, false); + const bool isFirstPart = (partIndex == 0); + const bool isLastPart = (partIndex == (_score->parts().size() - 1)); + if (!tboxesAboveWritten && isFirstPart) { + for (const auto tbox : tboxesAbove) { + // note: use mmRest1() to get at a possible multi-measure rest, + // as the covered measure would be positioned at 0,0. + tboxTextAsWords(tbox->text(), 0, tbox->text()->canvasPos() - m->mmRest1()->canvasPos()); + } + tboxesAboveWritten = true; + } + if (!tboxesBelowWritten && isLastPart && (etrack - VOICES) <= st) { + for (const auto tbox : tboxesBelow) { + const auto lastStaffNr = st / VOICES; + const auto sys = m->mmRest1()->system(); + auto textPos = tbox->text()->canvasPos() - m->mmRest1()->canvasPos(); + if (lastStaffNr < sys->staves()->size()) { + // convert to position relative to last staff of system + textPos.setY(textPos.y() - (sys->staffCanvasYpage(lastStaffNr) - sys->staffCanvasYpage(0))); + } + tboxTextAsWords(tbox->text(), sstaff, textPos); + } + tboxesBelowWritten = true; + } + annotations(this, strack, etrack, st, sstaff, seg); + // look for more harmony + for (auto seg1 = seg->next(); seg1; seg1 = seg1->next()) { + if (seg1->isChordRestType()) { + const auto el1 = seg1->element(st); + if (el1) // found a ChordRest, next harmony will be attach to this one + break; + for (auto annot : seg1->annotations()) { + if (annot->isHarmony() && annot->track() == st) + harmony(toHarmony(annot), 0, (seg1->tick() - seg->tick()).ticks() / div); + } + } + } + figuredBass(_xml, strack, etrack, st, static_cast(el), fbMap, div); + spannerStart(this, strack, etrack, st, sstaff, seg); + } - _xml.setDevice(dev); - _xml.setCodec("UTF-8"); - _xml << "\n"; - _xml << "\n"; - _xml.stag("score-partwise version=\"3.1\""); + // write element el if necessary + writeElement(el, m, sstaff, useDrumset); - work(_score->measures()->first()); + // handle annotations and spanners (directions attached to this note or rest) + if (el->isChordRest()) { + const int spannerStaff = st / VOICES; + const int starttrack = spannerStaff * VOICES; + const int endtrack = (spannerStaff + 1) * VOICES; + spannerStop(this, starttrack, endtrack, _tick, sstaff, spannersStopped); + } - identification(_xml, _score); + } // for (Segment* seg = ... + _attr.stop(_xml); + } // for (int st = ... + } - if (preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT)) { - defaults(_xml, _score, millimeters, tenths); - credits(_xml); - } +//--------------------------------------------------------- +// writeMeasure +//--------------------------------------------------------- - const auto& il = _score->parts(); - partList(_xml, _score, il, instrMap); +/** + Write a measure. + */ - int staffCount = 0; +void ExportMusicXml::writeMeasure(const Measure* const m, + const int partIndex, + const int staffCount, + MeasureNumberStateHandler& mnsh, + FigBassMap& fbMap, + const MeasurePrintContext& mpc) + { + const auto part = _score->parts().at(partIndex); + const int staves = part->nstaves(); + const int strack = part->startTrack(); + const int etrack = part->endTrack(); - for (int idx = 0; idx < il.size(); ++idx) { - const auto part = il.at(idx); - const bool isFirstPart = (idx == 0); - const bool isLastPart = (idx == (il.size() - 1)); - _tick = { 0,1 }; - _xml.stag(QString("part id=\"P%1\"").arg(idx+1)); + // pickup and other irregular measures need special care + QString measureTag = "measure"; + mnsh.updateForMeasure(m); + measureTag += mnsh.measureNumber(); + const bool isFirstActualMeasure = mnsh.isFirstActualMeasure(); - int staves = part->nstaves(); - int strack = part->startTrack(); - int etrack = part->endTrack(); + if (preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT)) + measureTag += QString(" width=\"%1\"").arg(QString::number(m->bbox().width() / DPMM / millimeters * tenths,'f',2)); - _trillStart.clear(); - _trillStop.clear(); - initInstrMap(instrMap, part->instruments(), _score); + _xml.stag(measureTag); - MeasureNumberStateHandler mnsh; + print(m, partIndex, staffCount, staves, mpc); - FigBassMap fbMap; // pending figured bass extends + _attr.start(); - for (auto mb = _score->measures()->first(); mb; mb = mb->next()) { + findTrills(m, strack, etrack, _trillStart, _trillStop); - if (!mb->isMeasure()) - continue; - const auto m = toMeasure(mb); + // barline left must be the first element in a measure + barlineLeft(m); - // pickup and other irregular measures need special care - QString measureTag = "measure"; - mnsh.updateForMeasure(m); - measureTag += mnsh.measureNumber(); - const bool isFirstActualMeasure = mnsh.isFirstActualMeasure(); + // output attributes with the first actual measure (pickup or regular) + if (isFirstActualMeasure) { + _attr.doAttr(_xml, true); + _xml.tag("divisions", MScore::division / div); + } - if (preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT)) - measureTag += QString(" width=\"%1\"").arg(QString::number(m->bbox().width() / DPMM / millimeters * tenths,'f',2)); + // output attributes at start of measure: key, time + keysigTimesig(m, part); - _xml.stag(measureTag); + // output attributes with the first actual measure (pickup or regular) only + if (isFirstActualMeasure) { + if (staves > 1) + _xml.tag("staves", staves); + if (instrMap.size() > 1) + _xml.tag("instruments", instrMap.size()); + } - print(m, idx, staffCount, staves); + // make sure clefs at end of measure get exported at start of next measure + findAndExportClef(m, staves, strack, etrack); - _attr.start(); + // make sure a clef gets exported if none is found + exportDefaultClef(part, m); - findTrills(m, strack, etrack, _trillStart, _trillStop); + // output attributes with the first actual measure (pickup or regular) only + if (isFirstActualMeasure) { + writeStaffDetails(_xml, part); + writeInstrumentDetails(part->instrument()); + } - // barline left must be the first element in a measure - barlineLeft(m); + // output attribute at start of measure: measure-style + measureStyle(_xml, _attr, m); - // output attributes with the first actual measure (pickup or regular) - if (isFirstActualMeasure) { - _attr.doAttr(_xml, true); - _xml.tag("divisions", MScore::division / div); - } + // MuseScore limitation: repeats are always in the first part + // and are implicitly placed at either measure start or stop + if (partIndex == 0) + repeatAtMeasureStart(_xml, _attr, m, strack, etrack, strack); - // output attributes at start of measure: key, time - keysigTimesig(m, part); + // write data in the tracks + writeMeasureTracks(m, partIndex, strack, staves, part->instrument()->useDrumset(), fbMap); - // output attributes with the first actual measure (pickup or regular) only - if (isFirstActualMeasure) { - if (staves > 1) - _xml.tag("staves", staves); - if (instrMap.size() > 1) - _xml.tag("instruments", instrMap.size()); - } + // write the annotations that could not be attached to notes + annotationsWithoutNote(this, strack, staves, m); - // make sure clefs at end of measure get exported at start of next measure - findAndExportClef(m, staves, strack, etrack); + // move to end of measure (in case of incomplete last voice) + #ifdef DEBUG_TICK + qDebug("end of measure"); + #endif + moveToTick(m->endTick()); + if (partIndex == 0) + repeatAtMeasureStop(_xml, m, strack, etrack, strack); + // note: don't use "m->repeatFlags() & Repeat::END" here, because more + // barline types need to be handled besides repeat end ("light-heavy") + barlineRight(m); + _xml.etag(); + } - // make sure a clef gets exported if none is found - exportDefaultClef(part, m); +//--------------------------------------------------------- +// measureWritten +//--------------------------------------------------------- - // output attributes with the first actual measure (pickup or regular) only - if (isFirstActualMeasure) { - writeStaffDetails(_xml, part); - writeInstrumentDetails(part->instrument()); - } +void MeasurePrintContext::measureWritten(const Measure* m) + { + scoreStart = false; + pageStart = false; + systemStart = false; + prevMeasure = m; + } - // output attribute at start of measure: measure-style - measureStyle(_xml, _attr, m); +//--------------------------------------------------------- +// writeParts +//--------------------------------------------------------- - // set of spanners already stopped in this measure - // required to prevent multiple spanner stops for the same spanner - QSet spannersStopped; +/** + Write all parts. + */ - // MuseScore limitation: repeats are always in the first part - // and are implicitly placed at either measure start or stop - if (idx == 0) - repeatAtMeasureStart(_xml, _attr, m, strack, etrack, strack); +void ExportMusicXml::writeParts() + { + int staffCount = 0; + const auto& parts = _score->parts(); - bool tboxesAboveWritten = false; - const auto tboxesAbove = findTextFramesToWriteAsWordsAbove(m); + for (int partIndex = 0; partIndex < parts.size(); ++partIndex) { + const auto part = parts.at(partIndex); + _tick = { 0,1 }; + _xml.stag(QString("part id=\"P%1\"").arg(partIndex+1)); - bool tboxesBelowWritten = false; - const auto tboxesBelow = findTextFramesToWriteAsWordsBelow(m); + _trillStart.clear(); + _trillStop.clear(); + initInstrMap(instrMap, part->instruments(), _score); - for (int st = strack; st < etrack; ++st) { - // sstaff - xml staff number, counting from 1 for this - // instrument - // special number 0 -> don’t show staff number in - // xml output (because there is only one staff) + MeasureNumberStateHandler mnsh; + FigBassMap fbMap; // pending figured bass extends - int sstaff = (staves > 1) ? st - strack + VOICES : 0; - sstaff /= VOICES; - for (auto seg = m->first(); seg; seg = seg->next()) { - const auto el = seg->element(st); - if (!el) { - continue; - } - // must ignore start repeat to prevent spurious backup/forward - if (el->isBarLine() && toBarLine(el)->barLineType() == BarLineType::START_REPEAT) - continue; + const auto& pages = _score->pages(); + MeasurePrintContext mpc; - // generate backup or forward to the start time of the element - if (_tick != seg->tick()) { - _attr.doAttr(_xml, false); - moveToTick(seg->tick()); - } + for (int pageIndex = 0; pageIndex < pages.size(); ++pageIndex) { + const auto page = pages.at(pageIndex); + mpc.pageStart = true; + const auto& systems = page->systems(); - // handle annotations and spanners (directions attached to this note or rest) - if (el->isChordRest()) { - _attr.doAttr(_xml, false); - if (!tboxesAboveWritten && isFirstPart) { - for (const auto tbox : tboxesAbove) { - // note: use mmRest1() to get at a possible multi-measure rest, - // as the covered measure would be positioned at 0,0. - tboxTextAsWords(tbox->text(), 0, tbox->text()->canvasPos() - m->mmRest1()->canvasPos()); - } - tboxesAboveWritten = true; - } - if (!tboxesBelowWritten && isLastPart && (etrack - VOICES) <= st) { - for (const auto tbox : tboxesBelow) { - const auto lastStaffNr = st / VOICES; - const auto sys = m->mmRest1()->system(); - auto textPos = tbox->text()->canvasPos() - m->mmRest1()->canvasPos(); - if (lastStaffNr < sys->staves()->size()) { - // convert to position relative to last staff of system - textPos.setY(textPos.y() - (sys->staffCanvasYpage(lastStaffNr) - sys->staffCanvasYpage(0))); - } - tboxTextAsWords(tbox->text(), sstaff, textPos); - } - tboxesBelowWritten = true; - } - annotations(this, strack, etrack, st, sstaff, seg); - // look for more harmony - for (auto seg1 = seg->next(); seg1; seg1 = seg1->next()) { - if (seg1->isChordRestType()) { - const auto el1 = seg1->element(st); - if (el1) // found a ChordRest, next harmony will be attach to this one - break; - for (auto annot : seg1->annotations()) { - if (annot->isHarmony() && annot->track() == st) - harmony(toHarmony(annot), 0, (seg1->tick() - seg->tick()).ticks() / div); - } + for (int systemIndex = 0; systemIndex < systems.size(); ++systemIndex) { + const auto system = systems.at(systemIndex); + mpc.systemStart = true; + + for (const auto mb : system->measures()) { + if (!mb->isMeasure()) + continue; + const auto m = toMeasure(mb); + + // write the measure or, in case of a multi measure rest, + // the measure range it replaces + if (m->isMMRest()) { + auto m1 = m->mmRestFirst(); + const auto m2 = m->mmRestLast(); + for (;; ) { + if (m1->isMeasure()) { + writeMeasure(m1, partIndex, staffCount, mnsh, fbMap, mpc); + mpc.measureWritten(m1); } + if (m1 == m2) + break; + m1 = m1->nextMeasure(); } - figuredBass(_xml, strack, etrack, st, static_cast(el), fbMap, div); - spannerStart(this, strack, etrack, st, sstaff, seg); + } + else { + writeMeasure(m, partIndex, staffCount, mnsh, fbMap, mpc); + mpc.measureWritten(m); } - // write element el if necessary - writeElement(el, m, sstaff, part->instrument()->useDrumset()); + } + mpc.prevSystem = system; + } + mpc.lastSystemPrevPage = mpc.prevSystem; + } - // handle annotations and spanners (directions attached to this note or rest) - if (el->isChordRest()) { - const int spannerStaff = st / VOICES; - const int starttrack = spannerStaff * VOICES; - const int endtrack = (spannerStaff + 1) * VOICES; - spannerStop(this, starttrack, endtrack, _tick, sstaff, spannersStopped); - } + staffCount += part->nstaves(); + _xml.etag(); + } + } - } // for (Segment* seg = ... - _attr.stop(_xml); - } // for (int st = ... +//--------------------------------------------------------- +// write +//--------------------------------------------------------- - // write the annotations that could not be attached to notes - annotationsWithoutNote(this, strack, staves, m); +/** + Write the score to \a dev in MusicXML format. + */ - // move to end of measure (in case of incomplete last voice) -#ifdef DEBUG_TICK - qDebug("end of measure"); -#endif - moveToTick(m->endTick()); - if (idx == 0) - repeatAtMeasureStop(_xml, m, strack, etrack, strack); - // note: don't use "m->repeatFlags() & Repeat::END" here, because more - // barline types need to be handled besides repeat end ("light-heavy") - barlineRight(m); - _xml.etag(); - } - staffCount += staves; - _xml.etag(); +void ExportMusicXml::write(QIODevice* dev) + { + // must export in transposed pitch to prevent + // losing the transposition information + // if necessary, switch concert pitch mode off + // before export and restore it after export + bool concertPitch = score()->styleB(Sid::concertPitch); + if (concertPitch) { + score()->startCmd(); + score()->undo(new ChangeStyleVal(score(), Sid::concertPitch, false)); + score()->doLayout(); // this is only allowed in a cmd context to not corrupt the undo/redo stack + } + + calcDivisions(); + + for (int i = 0; i < MAX_NUMBER_LEVEL; ++i) { + brackets[i] = nullptr; + dashes[i] = nullptr; + hairpins[i] = nullptr; + ottavas[i] = nullptr; + trills[i] = nullptr; } + _xml.setDevice(dev); + _xml.setCodec("UTF-8"); + _xml << "\n"; + _xml << "\n"; + + _xml.stag("score-partwise version=\"3.1\""); + + work(_score->measures()->first()); + identification(_xml, _score); + + if (preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT)) { + defaults(_xml, _score, millimeters, tenths); + credits(_xml); + } + + partList(_xml, _score, instrMap); + writeParts(); + _xml.etag(); if (concertPitch) { diff --git a/mscore/musicxml.h b/mscore/musicxml.h index d63cb49f3ea6e..c43be7bae45c6 100644 --- a/mscore/musicxml.h +++ b/mscore/musicxml.h @@ -127,12 +127,5 @@ class SlurDesc { typedef std::vector MusicXmlPartGroupList; typedef QMap > MusicXmlSpannerMap; -enum { - NoSystem = 0, - TopSystem = 1, - NewSystem = 2, - NewPage = 3 - }; - } // namespace Ms #endif diff --git a/mtest/musicxml/io/testBreaksImplExpl.mscx b/mtest/musicxml/io/testBreaksImplExpl.mscx new file mode 100644 index 0000000000000..35c34d0dcd5a7 --- /dev/null +++ b/mtest/musicxml/io/testBreaksImplExpl.mscx @@ -0,0 +1,234 @@ + + + 3.5.0 + 3543170 + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + 2020-02-24 + + + + Apple Macintosh + + + + + + + + + stdNormal + + + Voice + + Voice + Vo. + Voice + 36 + 94 + 40 + 79 + voice.vocals + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + Fluid + + + + + + + line + + + + 4 + 4 + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + line + + + + measure + 4/4 + + + + + + + After system break + + + measure + 4/4 + + + + + + diff --git a/mtest/musicxml/io/testBreaksImplExpl_all_ref.xml b/mtest/musicxml/io/testBreaksImplExpl_all_ref.xml new file mode 100644 index 0000000000000..6c6d01950a256 --- /dev/null +++ b/mtest/musicxml/io/testBreaksImplExpl_all_ref.xml @@ -0,0 +1,150 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + After system break + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksImplExpl_manual_ref.xml b/mtest/musicxml/io/testBreaksImplExpl_manual_ref.xml new file mode 100644 index 0000000000000..70c0137876775 --- /dev/null +++ b/mtest/musicxml/io/testBreaksImplExpl_manual_ref.xml @@ -0,0 +1,150 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + + After system break + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksImplExpl_no_ref.xml b/mtest/musicxml/io/testBreaksImplExpl_no_ref.xml new file mode 100644 index 0000000000000..c0433687fb449 --- /dev/null +++ b/mtest/musicxml/io/testBreaksImplExpl_no_ref.xml @@ -0,0 +1,139 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + After system break + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksMMRest.mscx b/mtest/musicxml/io/testBreaksMMRest.mscx new file mode 100644 index 0000000000000..987d97edb3f44 --- /dev/null +++ b/mtest/musicxml/io/testBreaksMMRest.mscx @@ -0,0 +1,260 @@ + + + 3.5.0 + 3543170 + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + 2020-02-29 + + + + Apple Macintosh + + + + + + + + + stdNormal + + + Voice + + Voice + Vo. + Voice + 36 + 94 + 40 + 79 + voice.vocals + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + Fluid + + + + + + + + + 1 + + 4 + 4 + + + measure + 4/4 + + + + + + 2 + + + 1 + + -1 + + 4 + 4 + + + measure + 8/4 + + + + + + + + measure + 4/4 + + + + + + + line + + + + whole + + 67 + 15 + + + + + + + + + whole + + 67 + 15 + + + + + + + + + measure + 4/4 + + + + + + 2 + + line + + + + measure + 8/4 + + + + + + + line + + + + measure + 4/4 + + + + + + + + whole + + 67 + 15 + + + + + + + + + measure + 4/4 + + + + + + 2 + + page + + + + measure + 8/4 + + + + + + + page + + + + measure + 4/4 + + + + + + + + whole + + 67 + 15 + + + + + + + diff --git a/mtest/musicxml/io/testBreaksMMRest_all_ref.xml b/mtest/musicxml/io/testBreaksMMRest_all_ref.xml new file mode 100644 index 0000000000000..0cb5c65c82e00 --- /dev/null +++ b/mtest/musicxml/io/testBreaksMMRest_all_ref.xml @@ -0,0 +1,152 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + G + 4 + + 4 + 1 + whole + + + + + + + G + 4 + + 4 + 1 + whole + + + + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + G + 4 + + 4 + 1 + whole + + + + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + G + 4 + + 4 + 1 + whole + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksMMRest_manual_ref.xml b/mtest/musicxml/io/testBreaksMMRest_manual_ref.xml new file mode 100644 index 0000000000000..0cb5c65c82e00 --- /dev/null +++ b/mtest/musicxml/io/testBreaksMMRest_manual_ref.xml @@ -0,0 +1,152 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + G + 4 + + 4 + 1 + whole + + + + + + + G + 4 + + 4 + 1 + whole + + + + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + G + 4 + + 4 + 1 + whole + + + + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + G + 4 + + 4 + 1 + whole + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksMMRest_no_ref.xml b/mtest/musicxml/io/testBreaksMMRest_no_ref.xml new file mode 100644 index 0000000000000..e883d9eea7690 --- /dev/null +++ b/mtest/musicxml/io/testBreaksMMRest_no_ref.xml @@ -0,0 +1,149 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + G + 4 + + 4 + 1 + whole + + + + + + 2 + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + G + 4 + + 4 + 1 + whole + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksManual.xml b/mtest/musicxml/io/testBreaksManual.xml new file mode 100644 index 0000000000000..8eeec4fdbdb93 --- /dev/null +++ b/mtest/musicxml/io/testBreaksManual.xml @@ -0,0 +1,1804 @@ + + + + + MuseScore testfile + Manual Breaks + + + Leon Vinken + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Flute + Fl. + + Flute + + + + 1 + 74 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + + B + -1 + 4 + + 4 + 1 + whole + flat + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + + C + 1 + 5 + + 4 + 1 + whole + sharp + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksManual_all_ref.xml b/mtest/musicxml/io/testBreaksManual_all_ref.xml new file mode 100644 index 0000000000000..52f13c4130426 --- /dev/null +++ b/mtest/musicxml/io/testBreaksManual_all_ref.xml @@ -0,0 +1,1815 @@ + + + + + MuseScore testfile + Manual Breaks + + + Leon Vinken + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Flute + Fl. + + Flute + + + + 1 + 74 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + + B + -1 + 4 + + 4 + 1 + whole + flat + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + + C + 1 + 5 + + 4 + 1 + whole + sharp + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksManual_manual_ref.xml b/mtest/musicxml/io/testBreaksManual_manual_ref.xml new file mode 100644 index 0000000000000..8eeec4fdbdb93 --- /dev/null +++ b/mtest/musicxml/io/testBreaksManual_manual_ref.xml @@ -0,0 +1,1804 @@ + + + + + MuseScore testfile + Manual Breaks + + + Leon Vinken + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Flute + Fl. + + Flute + + + + 1 + 74 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + + B + -1 + 4 + + 4 + 1 + whole + flat + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + + C + 1 + 5 + + 4 + 1 + whole + sharp + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksManual_no_ref.xml b/mtest/musicxml/io/testBreaksManual_no_ref.xml new file mode 100644 index 0000000000000..9425bf5b6a51a --- /dev/null +++ b/mtest/musicxml/io/testBreaksManual_no_ref.xml @@ -0,0 +1,1802 @@ + + + + + MuseScore testfile + Manual Breaks + + + Leon Vinken + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Flute + Fl. + + Flute + + + + 1 + 74 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + G + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + A + 4 + + 4 + 1 + whole + + + + + + B + -1 + 4 + + 4 + 1 + whole + flat + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + C + 1 + 5 + + 4 + 1 + whole + sharp + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + B + 4 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + C + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + D + 5 + + 4 + 1 + whole + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksPage.mscx b/mtest/musicxml/io/testBreaksPage.mscx new file mode 100644 index 0000000000000..e59925b175a1c --- /dev/null +++ b/mtest/musicxml/io/testBreaksPage.mscx @@ -0,0 +1,186 @@ + + + 3.5.0 + 3543170 + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + 2020-02-24 + + + + Apple Macintosh + + + + + + + + + stdNormal + + + Voice + + Voice + Vo. + Voice + 36 + 94 + 40 + 79 + voice.vocals + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + Fluid + + + + + + + page + + + + 4 + 4 + + + First system (no frames above) + + + measure + 4/4 + + + + + + + After page break + + + measure + 4/4 + + + + + 10 + + + Vframe + + + page + + + + + + After page break in vframe + + + measure + 4/4 + + + + + 1 + + page + + + + Tframe + + + + + + After page break in tframe + + + measure + 4/4 + + + + + 5 + + page + + + + + + After page break in hframe + + + measure + 4/4 + + + + + + diff --git a/mtest/musicxml/io/testBreaksPage_all_ref.xml b/mtest/musicxml/io/testBreaksPage_all_ref.xml new file mode 100644 index 0000000000000..6f46c16a7b5e9 --- /dev/null +++ b/mtest/musicxml/io/testBreaksPage_all_ref.xml @@ -0,0 +1,119 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + First system (no frames above) + + + + + 4 + 1 + + + + + + + After page break + + + + + 4 + 1 + + + + + + + Tframe + + + + + After page break in vframe + + + + + 4 + 1 + + + + + + + After page break in tframe + + + + + 4 + 1 + + + + + + + After page break in hframe + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksPage_manual_ref.xml b/mtest/musicxml/io/testBreaksPage_manual_ref.xml new file mode 100644 index 0000000000000..6f46c16a7b5e9 --- /dev/null +++ b/mtest/musicxml/io/testBreaksPage_manual_ref.xml @@ -0,0 +1,119 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + First system (no frames above) + + + + + 4 + 1 + + + + + + + After page break + + + + + 4 + 1 + + + + + + + Tframe + + + + + After page break in vframe + + + + + 4 + 1 + + + + + + + After page break in tframe + + + + + 4 + 1 + + + + + + + After page break in hframe + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksPage_no_ref.xml b/mtest/musicxml/io/testBreaksPage_no_ref.xml new file mode 100644 index 0000000000000..f0de812161bd0 --- /dev/null +++ b/mtest/musicxml/io/testBreaksPage_no_ref.xml @@ -0,0 +1,115 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + First system (no frames above) + + + + + 4 + 1 + + + + + + After page break + + + + + 4 + 1 + + + + + + Tframe + + + + + After page break in vframe + + + + + 4 + 1 + + + + + + After page break in tframe + + + + + 4 + 1 + + + + + + After page break in hframe + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksSystem.mscx b/mtest/musicxml/io/testBreaksSystem.mscx new file mode 100644 index 0000000000000..cec434b8eb01b --- /dev/null +++ b/mtest/musicxml/io/testBreaksSystem.mscx @@ -0,0 +1,235 @@ + + + 3.5.0 + 3543170 + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + 2020-01-14 + + + + Apple Macintosh + + + + + + + + + stdNormal + + + Voice + + Voice + Vo. + Voice + 36 + 94 + 40 + 79 + voice.vocals + + 100 + 100 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + + Fluid + + + + + + + section + + + + 4 + 4 + + + First system (no frames above) + + + measure + 4/4 + + + + + + + After section break + + + measure + 4/4 + + + + + 5 + + line + + + + + + After system break in horizontal frame + + + measure + 4/4 + + + + + 5 + + section + + + + + + After section break in horizontal frame + + + measure + 4/4 + + + + + 5 + + page + + + + + + After page break in horizontal frame + + + measure + 4/4 + + + + + 10 + + + Vframe + + + + + + After vframe + + + measure + 4/4 + + + + + 1 + + + Tframe + + + + + line + + + + After tframe + + + measure + 4/4 + + + + + 5 + + line + + + + + + After system break in hframe + + + measure + 4/4 + + + + + + diff --git a/mtest/musicxml/io/testBreaksSystem_all_ref.xml b/mtest/musicxml/io/testBreaksSystem_all_ref.xml new file mode 100644 index 0000000000000..22fb229a86788 --- /dev/null +++ b/mtest/musicxml/io/testBreaksSystem_all_ref.xml @@ -0,0 +1,161 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + First system (no frames above) + + + + + 4 + 1 + + + + + + 1 + + + + After section break + + + + + 4 + 1 + + + + + + + After system break in horizontal frame + + + + + 4 + 1 + + + + + + + After section break in horizontal frame + + + + + 4 + 1 + + + + + + + After page break in horizontal frame + + + + + 4 + 1 + + + + + + + After vframe + + + + + 4 + 1 + + + + + + + Tframe + + + + + After tframe + + + + + 4 + 1 + + + + + + + After system break in hframe + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksSystem_manual_ref.xml b/mtest/musicxml/io/testBreaksSystem_manual_ref.xml new file mode 100644 index 0000000000000..22fb229a86788 --- /dev/null +++ b/mtest/musicxml/io/testBreaksSystem_manual_ref.xml @@ -0,0 +1,161 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + First system (no frames above) + + + + + 4 + 1 + + + + + + 1 + + + + After section break + + + + + 4 + 1 + + + + + + + After system break in horizontal frame + + + + + 4 + 1 + + + + + + + After section break in horizontal frame + + + + + 4 + 1 + + + + + + + After page break in horizontal frame + + + + + 4 + 1 + + + + + + + After vframe + + + + + 4 + 1 + + + + + + + Tframe + + + + + After tframe + + + + + 4 + 1 + + + + + + + After system break in hframe + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testBreaksSystem_no_ref.xml b/mtest/musicxml/io/testBreaksSystem_no_ref.xml new file mode 100644 index 0000000000000..0ea4d320cf0e8 --- /dev/null +++ b/mtest/musicxml/io/testBreaksSystem_no_ref.xml @@ -0,0 +1,154 @@ + + + + + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Voice + Vo. + + Voice + + + + 1 + 53 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + First system (no frames above) + + + + + 4 + 1 + + + + + 1 + + + + After section break + + + + + 4 + 1 + + + + + + After system break in horizontal frame + + + + + 4 + 1 + + + + + + After section break in horizontal frame + + + + + 4 + 1 + + + + + + After page break in horizontal frame + + + + + 4 + 1 + + + + + + After vframe + + + + + 4 + 1 + + + + + + Tframe + + + + + After tframe + + + + + 4 + 1 + + + + + + After system break in hframe + + + + + 4 + 1 + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testManualBreaks.xml b/mtest/musicxml/io/testManualBreaks.xml deleted file mode 100644 index 62f5dbf25a95a..0000000000000 --- a/mtest/musicxml/io/testManualBreaks.xml +++ /dev/null @@ -1,600 +0,0 @@ - - - - - MuseScore testfile - Manual Breaks - - - Leon Vinken - - MuseScore 0.7.0 - 2007-09-10 - - - - - - - - - - Flute - Fl. - - Flute - - - - 1 - 74 - 78.7402 - 0 - - - - - - - 1 - - 0 - - - - G - 2 - - - - - G - 4 - - 4 - 1 - whole - - - - - - G - 4 - - 4 - 1 - whole - - - - - - G - 4 - - 4 - 1 - whole - - - - - - G - 4 - - 4 - 1 - whole - - - - - - G - 4 - - 4 - 1 - whole - - - - - - G - 4 - - 4 - 1 - whole - - - - - - G - 4 - - 4 - 1 - whole - - - - - - A - 4 - - 4 - 1 - whole - - - - - - A - 4 - - 4 - 1 - whole - - - - - - A - 4 - - 4 - 1 - whole - - - - - - A - 4 - - 4 - 1 - whole - - - - - - A - 4 - - 4 - 1 - whole - - - - - - A - 4 - - 4 - 1 - whole - - - - - - - B - -1 - 4 - - 4 - 1 - whole - flat - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - - C - 1 - 5 - - 4 - 1 - whole - sharp - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - B - 4 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - C - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - - - - D - 5 - - 4 - 1 - whole - - - light-heavy - - - - diff --git a/mtest/musicxml/io/testTboxMultiPage1_ref.xml b/mtest/musicxml/io/testTboxMultiPage1_ref.xml index fa4dd029df7da..5c55cab9d7944 100644 --- a/mtest/musicxml/io/testTboxMultiPage1_ref.xml +++ b/mtest/musicxml/io/testTboxMultiPage1_ref.xml @@ -108,6 +108,7 @@ + Tbox 5 diff --git a/mtest/musicxml/io/testTboxWords1_ref.xml b/mtest/musicxml/io/testTboxWords1_ref.xml index ce92c5e4da1a4..62024ebd1b96d 100644 --- a/mtest/musicxml/io/testTboxWords1_ref.xml +++ b/mtest/musicxml/io/testTboxWords1_ref.xml @@ -65,6 +65,7 @@ + 2 @@ -94,6 +95,7 @@ + Staff Text diff --git a/mtest/musicxml/io/tst_mxml_io.cpp b/mtest/musicxml/io/tst_mxml_io.cpp index 64b0fa4bc6fc8..d2ee18b49f0bc 100644 --- a/mtest/musicxml/io/tst_mxml_io.cpp +++ b/mtest/musicxml/io/tst_mxml_io.cpp @@ -21,8 +21,8 @@ // end includes required for fixupScore() namespace Ms { - extern bool saveMxl(Score*, const QString&); - } +extern bool saveMxl(Score*, const QString&); +} #define DIR QString("musicxml/io/") @@ -38,7 +38,9 @@ class TestMxmlIO : public QObject, public MTest void mxmlIoTest(const char* file); void mxmlIoTestRef(const char* file); + void mxmlIoTestRefBreaks(const char* file); void mxmlMscxExportTestRef(const char* file); + void mxmlMscxExportTestRefBreaks(const char* file); void mxmlReadTestCompr(const char* file); void mxmlReadWriteTestCompr(const char* file); @@ -61,6 +63,11 @@ private slots: void barStyles() { mxmlIoTest("testBarStyles"); } void barStyles2() { mxmlIoTest("testBarStyles2"); } void barStyles3() { mxmlIoTest("testBarStyles3"); } + void breaksImplExpl() { mxmlMscxExportTestRefBreaks("testBreaksImplExpl"); } + void breaksMMRest() { mxmlMscxExportTestRefBreaks("testBreaksMMRest"); } + void breaksManual() { mxmlIoTestRefBreaks("testBreaksManual"); } + void breaksPage() { mxmlMscxExportTestRefBreaks("testBreaksPage"); } + void breaksSystem() { mxmlMscxExportTestRefBreaks("testBreaksSystem"); } void chordDiagrams1() { mxmlIoTest("testChordDiagrams1"); } void chordNoVoice() { mxmlIoTestRef("testChordNoVoice"); } void clefs1() { mxmlIoTest("testClefs1"); } @@ -115,7 +122,6 @@ private slots: void lyrics1() { mxmlIoTestRef("testLyrics1"); } void lyricsVoice2a() { mxmlIoTest("testLyricsVoice2a"); } void lyricsVoice2b() { mxmlIoTestRef("testLyricsVoice2b"); } - void manualBreaks() { mxmlIoTest("testManualBreaks"); } void measureLength() { mxmlIoTestRef("testMeasureLength"); } void midiPortExport() { mxmlMscxExportTestRef("testMidiPortExport"); } void multiInstrumentPart1() { mxmlIoTest("testMultiInstrumentPart1"); } @@ -258,6 +264,33 @@ void TestMxmlIO::mxmlIoTestRef(const char* file) delete score; } +//--------------------------------------------------------- +// mxmlIoTestRefBreaks +// read a MusicXML file, write to a new file and verify against reference +// using all possible settings for PREF_EXPORT_MUSICXML_EXPORTBREAKS +//--------------------------------------------------------- + +void TestMxmlIO::mxmlIoTestRefBreaks(const char* file) + { + MScore::debugMode = true; + preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, true); + preferences.setPreference(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, false); + MasterScore* score = readScore(DIR + file + ".xml"); + QVERIFY(score); + fixupScore(score); + score->doLayout(); + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::NO); + QVERIFY(saveMusicXml(score, QString(file) + ".xml")); + QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_no_ref.xml")); + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL); + QVERIFY(saveMusicXml(score, QString(file) + ".xml")); + QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_manual_ref.xml")); + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::ALL); + QVERIFY(saveMusicXml(score, QString(file) + ".xml")); + QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_all_ref.xml")); + delete score; + } + //--------------------------------------------------------- // mxmlMscxExportTestRef // read a MuseScore mscx file, write to a MusicXML file and verify against reference @@ -277,6 +310,33 @@ void TestMxmlIO::mxmlMscxExportTestRef(const char* file) delete score; } +//--------------------------------------------------------- +// mxmlMscxExportTestRefBreaks +// read a MuseScore mscx file, write to a MusicXML file and verify against reference +// using all possible settings for PREF_EXPORT_MUSICXML_EXPORTBREAKS +//--------------------------------------------------------- + +void TestMxmlIO::mxmlMscxExportTestRefBreaks(const char* file) + { + MScore::debugMode = true; + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL); + preferences.setPreference(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, false); + MasterScore* score = readScore(DIR + file + ".mscx"); + QVERIFY(score); + fixupScore(score); + score->doLayout(); + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::NO); + QVERIFY(saveMusicXml(score, QString(file) + ".xml")); + QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_no_ref.xml")); + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL); + QVERIFY(saveMusicXml(score, QString(file) + ".xml")); + QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_manual_ref.xml")); + preferences.setCustomPreference(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::ALL); + QVERIFY(saveMusicXml(score, QString(file) + ".xml")); + QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_all_ref.xml")); + delete score; + } + //--------------------------------------------------------- // mxmlReadTestCompr // read a compressed MusicXML file, write to a new file and verify against reference From cb10c918c470699a23d0ba9f5690520564935d8d Mon Sep 17 00:00:00 2001 From: Leon Vinken Date: Sun, 1 Mar 2020 10:31:01 +0100 Subject: [PATCH 30/49] fix #301671 - [MusicXML export] section breaks in horizontal frames do not reset measure numbers --- mscore/exportxml.cpp | 7 ++++--- mtest/musicxml/io/testBreaksSystem_all_ref.xml | 13 ++++++++----- mtest/musicxml/io/testBreaksSystem_manual_ref.xml | 13 ++++++++----- mtest/musicxml/io/testBreaksSystem_no_ref.xml | 13 ++++++++----- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/mscore/exportxml.cpp b/mscore/exportxml.cpp index a143900e3553a..f7bbd27183628 100644 --- a/mscore/exportxml.cpp +++ b/mscore/exportxml.cpp @@ -5648,9 +5648,10 @@ void MeasureNumberStateHandler::init() void MeasureNumberStateHandler::updateForMeasure(const Measure* const m) { // restart measure numbering after a section break if startWithMeasureOne is set - const auto previousMeasure = m->prevMeasure(); - if (previousMeasure) { - const auto layoutSectionBreak = previousMeasure->sectionBreakElement(); + // check the previous MeasureBase instead of Measure to catch breaks in frames too + const auto previousMB = m->prev(); + if (previousMB) { + const auto layoutSectionBreak = previousMB->sectionBreakElement(); if (layoutSectionBreak && layoutSectionBreak->startWithMeasureOne()) init(); } diff --git a/mtest/musicxml/io/testBreaksSystem_all_ref.xml b/mtest/musicxml/io/testBreaksSystem_all_ref.xml index 22fb229a86788..bf8ca360565d1 100644 --- a/mtest/musicxml/io/testBreaksSystem_all_ref.xml +++ b/mtest/musicxml/io/testBreaksSystem_all_ref.xml @@ -84,8 +84,11 @@ 1 - + + + 1 + After section break in horizontal frame @@ -97,7 +100,7 @@ 1 - + @@ -110,7 +113,7 @@ 1 - + @@ -123,7 +126,7 @@ 1 - + @@ -141,7 +144,7 @@ 1 - + diff --git a/mtest/musicxml/io/testBreaksSystem_manual_ref.xml b/mtest/musicxml/io/testBreaksSystem_manual_ref.xml index 22fb229a86788..bf8ca360565d1 100644 --- a/mtest/musicxml/io/testBreaksSystem_manual_ref.xml +++ b/mtest/musicxml/io/testBreaksSystem_manual_ref.xml @@ -84,8 +84,11 @@ 1 - + + + 1 + After section break in horizontal frame @@ -97,7 +100,7 @@ 1 - + @@ -110,7 +113,7 @@ 1 - + @@ -123,7 +126,7 @@ 1 - + @@ -141,7 +144,7 @@ 1 - + diff --git a/mtest/musicxml/io/testBreaksSystem_no_ref.xml b/mtest/musicxml/io/testBreaksSystem_no_ref.xml index 0ea4d320cf0e8..1fa244f17f181 100644 --- a/mtest/musicxml/io/testBreaksSystem_no_ref.xml +++ b/mtest/musicxml/io/testBreaksSystem_no_ref.xml @@ -82,7 +82,10 @@ 1 - + + + 1 + After section break in horizontal frame @@ -94,7 +97,7 @@ 1 - + After page break in horizontal frame @@ -106,7 +109,7 @@ 1 - + After vframe @@ -118,7 +121,7 @@ 1 - + Tframe @@ -135,7 +138,7 @@ 1 - + After system break in hframe From f84c64d6c91bbf73a60dc11158d137bdac8bcc0d Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Mon, 2 Mar 2020 15:38:51 +0100 Subject: [PATCH 31/49] fix #283111: Add octobass and add some comments to the bowed instruments reg. their sound. Revealed a wrong pizzicato sound for Baryton (dulcimer), corrected in the due course --- share/instruments/instruments.xml | 48 ++++++++++++++++++++++-------- share/instruments/instrumentsxml.h | 5 ++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/share/instruments/instruments.xml b/share/instruments/instruments.xml index 7c4e20f3a2142..660c1ab2d88fa 100644 --- a/share/instruments/instruments.xml +++ b/share/instruments/instruments.xml @@ -10698,13 +10698,13 @@ 24-108 24-108 - + - + - + @@ -10742,13 +10742,13 @@ 48-79 48-93 - + - + - + world @@ -10852,8 +10852,8 @@ 1 36-67 36-90 - - + + @@ -10901,8 +10901,8 @@ 24-67 -7 -12 - - + + @@ -10946,6 +10946,28 @@ Double Bass Db. + + Octobass + Otb. + Octobass + strings.octobass + F + F15mb + 1 + 21-31 + 12-33 + -14 + -24 + + + + + + + + + + Pardessus de viole Pds. v. @@ -11112,13 +11134,13 @@ 33-74 33-79 - + - + - + earlymusic diff --git a/share/instruments/instrumentsxml.h b/share/instruments/instrumentsxml.h index 12ac7dc3b364e..3e37959f2785f 100644 --- a/share/instruments/instrumentsxml.h +++ b/share/instruments/instrumentsxml.h @@ -1366,6 +1366,11 @@ QT_TRANSLATE_NOOP("InstrumentsXML", "pizzicato"), QT_TRANSLATE_NOOP("InstrumentsXML", "tremolo"), QT_TRANSLATE_NOOP("InstrumentsXML", "Double Bass"), QT_TRANSLATE_NOOP3("InstrumentsXML", "Db.", "Double Bass"), +QT_TRANSLATE_NOOP("InstrumentsXML", "Octobass"), +QT_TRANSLATE_NOOP3("InstrumentsXML", "Otb.", "Octobass"), +QT_TRANSLATE_NOOP("InstrumentsXML", "arco"), +QT_TRANSLATE_NOOP("InstrumentsXML", "pizzicato"), +QT_TRANSLATE_NOOP("InstrumentsXML", "tremolo"), QT_TRANSLATE_NOOP("InstrumentsXML", "Pardessus de viole"), QT_TRANSLATE_NOOP3("InstrumentsXML", "Pds. v.", "Pardessus de viole"), QT_TRANSLATE_NOOP("InstrumentsXML", "arco"), From 5daa2a0ced7d6f85e58cf7562539046fa6b61627 Mon Sep 17 00:00:00 2001 From: AntonioBL Date: Mon, 2 Mar 2020 22:22:45 +0100 Subject: [PATCH 32/49] fix #298108 : Sporadic Crash when dragging a Brace from palette to score using Bravura --- libmscore/bracket.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libmscore/bracket.cpp b/libmscore/bracket.cpp index c3a3a7d78b850..83f75d32e8d5e 100644 --- a/libmscore/bracket.cpp +++ b/libmscore/bracket.cpp @@ -34,6 +34,7 @@ Bracket::Bracket(Score* s) _firstStaff = 0; _lastStaff = 0; _bi = 0; + _braceSymbol = SymId::noSym; setGenerated(true); // brackets are not saved } @@ -152,6 +153,8 @@ void Bracket::layout() _shape.add(bbox()); } else { + if (_braceSymbol == SymId::noSym) + _braceSymbol = SymId::brace; qreal h = h2 * 2; qreal w = symWidth(_braceSymbol) * _magx; bbox().setRect(0, 0, w, h); From 58d603b499ba6d89455a98af382f4150fc4efd5b Mon Sep 17 00:00:00 2001 From: Matt McClinch Date: Tue, 3 Mar 2020 01:10:40 -0500 Subject: [PATCH 33/49] fix #290987: B# and Cb octave change Resolves: https://musescore.org/en/node/290987. Make sure that B#, B##, Cb, and Cbb describe themselves as being in the correct octave. This is accomplished by calculating the octave based on what the pitch would be if there were no accidental. Thus, there is no need to special-case certain tpcs. --- libmscore/note.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmscore/note.cpp b/libmscore/note.cpp index 9a2407399d63f..782cb25d0cc23 100644 --- a/libmscore/note.cpp +++ b/libmscore/note.cpp @@ -763,7 +763,7 @@ int Note::tpc() const QString Note::tpcUserName(bool explicitAccidental) const { QString pitchName = tpc2name(tpc(), NoteSpellingType::STANDARD, NoteCaseType::AUTO, explicitAccidental); - QString octaveName = QString::number(((epitch() + ottaveCapoFret()) / 12) - 1); + QString octaveName = QString::number(((epitch() + ottaveCapoFret() - int(tpc2alter(tpc()))) / 12) - 1); return pitchName + (explicitAccidental ? " " : "") + octaveName; } From 684df202c65f9a0a680605003ae72c68f2c9d08c Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Tue, 3 Mar 2020 15:28:42 +0200 Subject: [PATCH 34/49] fix #286842: fix assertion failure on adding instrument change to score with parts Ensure that MIDI mapping gets rebuilt after the correct structure of instruments has been established for all parts. --- libmscore/layout.cpp | 4 ++++ libmscore/score.cpp | 4 ++-- libmscore/score.h | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 629252b85250b..5b210558eb2be 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -4385,6 +4385,10 @@ void Score::doLayoutRange(const Fraction& st, const Fraction& et) _scoreFont = ScoreFont::fontFactory(style().value(Sid::MusicalSymbolFont).toString()); _noteHeadWidth = _scoreFont->width(SymId::noteheadBlack, spatium() / SPATIUM20); + if (cmdState().layoutFlags & LayoutFlag::REBUILD_MIDI_MAPPING) { + if (isMaster()) + masterScore()->rebuildMidiMapping(); + } if (cmdState().layoutFlags & LayoutFlag::FIX_PITCH_VELO) updateVelo(); #if 0 // TODO: needed? It was introduced in ab9774ec4098512068b8ef708167d9aa6e702c50 diff --git a/libmscore/score.cpp b/libmscore/score.cpp index 99a6efe2fb00d..ae6e0cb55014c 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -1469,7 +1469,7 @@ void Score::addElement(Element* element) ic->part()->setInstrument(ic->instrument(), tickStart); transpositionChanged(ic->part(), oldV, tickStart, tickEnd); #endif - masterScore()->rebuildMidiMapping(); + addLayoutFlags(LayoutFlag::REBUILD_MIDI_MAPPING); cmdState()._instrumentsChanged = true; } break; @@ -1637,7 +1637,7 @@ void Score::removeElement(Element* element) ic->part()->removeInstrument(tickStart); transpositionChanged(ic->part(), oldV, tickStart, tickEnd); #endif - masterScore()->rebuildMidiMapping(); + addLayoutFlags(LayoutFlag::REBUILD_MIDI_MAPPING); cmdState()._instrumentsChanged = true; } break; diff --git a/libmscore/score.h b/libmscore/score.h index 1ab3f82561b7a..c93f4900ed3a3 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -208,7 +208,8 @@ struct Position { enum class LayoutFlag : char { NO_FLAGS = 0, FIX_PITCH_VELO = 1, - PLAY_EVENTS = 2 + PLAY_EVENTS = 2, + REBUILD_MIDI_MAPPING = 4, }; typedef QFlags LayoutFlags; From f215d00c98305c3ea50ced0f8fdf80e22ba0de0c Mon Sep 17 00:00:00 2001 From: Matt McClinch Date: Thu, 5 Mar 2020 08:07:26 -0500 Subject: [PATCH 35/49] fix #301488: Changing instruments from a tablature crashes the program Resolves: https://musescore.org/en/node/301488. When the user chooses a different instrument in the "Edit Staff" dialog box, it is important to make sure that the new instrument is not incompatible with the staff type. This is accomplished by setting the staff type to the preset staff type for the chosen instrument. --- mscore/editstaff.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mscore/editstaff.cpp b/mscore/editstaff.cpp index 15922767b9021..337299711d311 100644 --- a/mscore/editstaff.cpp +++ b/mscore/editstaff.cpp @@ -497,6 +497,11 @@ void EditStaff::showInstrumentDialog() si.setWindowModality(Qt::WindowModal); if (si.exec()) { instrument = Instrument::fromTemplate(si.instrTemplate()); + const StaffType* staffType = si.instrTemplate()->staffTypePreset; + if (!staffType) + staffType = StaffType::getDefaultPreset(StaffGroup::STANDARD); + staff->setStaffType(Fraction(0,1), *staffType); + updateStaffType(); updateInstrument(); } } From f32f3ea41edb0c8326c58e4cccad49b052fce548 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Fri, 6 Mar 2020 09:39:53 +0200 Subject: [PATCH 36/49] fix #300912: fix grips remaining after undoing adding a slur Handle the remaining unhandled case in updateEditElement() to dismiss edit grips in case of list selection --- mscore/scoreview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 54977d254ac0e..eec9b2e0f6c02 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -4979,6 +4979,9 @@ void ScoreView::updateEditElement() else setEditElement(e); } + else { + setEditElement(nullptr); + } break; } } From abc4f7fa95cfb2f2eddaf65c2bf98c07a689fc50 Mon Sep 17 00:00:00 2001 From: Kumar Kartikay Date: Fri, 6 Mar 2020 13:52:54 +0530 Subject: [PATCH 37/49] fix #290034: play repeats button not respected in new score --- libmscore/score.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmscore/score.h b/libmscore/score.h index c93f4900ed3a3..fe0c6a9e3d035 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -1230,7 +1230,7 @@ class MasterScore : public Score { TimeSigMap* _sigmap; TempoMap* _tempomap; RepeatList* _repeatList; - bool _expandRepeats { true }; + bool _expandRepeats { MScore::playRepeats }; bool _playlistDirty { true }; QList _excerpts; std::vector _playbackSettingsLinks; From 8f6934f1e6dfd922b62d5279e078ccffbadfcdbf Mon Sep 17 00:00:00 2001 From: MarcSabatella Date: Fri, 6 Mar 2020 15:11:56 -0700 Subject: [PATCH 38/49] fix #300693: fb continuation not drawn when ending in voice 2 Resolves: https://musescore.org/en/node/300693 Continuation lines are drawn to the right edge of the last note that starts before the end of the figure's duration. The code that finds this note was only looking in voice 1. That resulted in continuation lines ending short, or disappearing, if the last note was in another voice. Fix is to be sure to check all voices when searchiing for the end CR. --- libmscore/figuredbass.cpp | 17 +- vtest/figured-bass-1.mscx | 435 ++++++++++++++++++++++++++++++++++++++ vtest/figured-bass-1.png | Bin 0 -> 9205 bytes vtest/gen | 1 + vtest/gen.bat | 1 + 5 files changed, 452 insertions(+), 2 deletions(-) create mode 100644 vtest/figured-bass-1.mscx create mode 100644 vtest/figured-bass-1.png diff --git a/libmscore/figuredbass.cpp b/libmscore/figuredbass.cpp index 9f7418cbcc05a..fbddb3748b1e8 100644 --- a/libmscore/figuredbass.cpp +++ b/libmscore/figuredbass.cpp @@ -1174,8 +1174,21 @@ void FiguredBass::layoutLines() break; } // locate the last ChordRest of this - if (nextSegm) - lastCR = nextSegm->prev1()->nextChordRest(track(), true); + if (nextSegm) { + int startTrack = trackZeroVoice(track()); + int endTrack = startTrack + VOICES; + for (const Segment* seg = nextSegm->prev1(); seg; seg = seg->prev1()) { + for (int t = startTrack; t < endTrack; ++t) { + Element* el = seg->element(t); + if (el && el->isChordRest()) { + lastCR = toChordRest(el); + break; + } + } + if (lastCR) + break; + } + } } if (!m || !nextSegm) { qDebug("FiguredBass layout: no segment found for tick %d", nextTick.ticks()); diff --git a/vtest/figured-bass-1.mscx b/vtest/figured-bass-1.mscx new file mode 100644 index 0000000000000..70476328df59e --- /dev/null +++ b/vtest/figured-bass-1.mscx @@ -0,0 +1,435 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + Standard + + + + + Standard + + F + + Piano + + Pno. + Piano + 21 + 108 + 21 + 108 + + 100 + 70 + + + 100 + 40 + + + 100 + 100 + + + 120 + 100 + + + + + + + + + + + 4 + 4 + + + 2/4 + + + 6 + 1 + + + + half + + 72 + 14 + + + + 1/4 + + + 5 + + + + half + + 72 + 14 + + + + -1/4 + + + 1/4 + + + 1 + + + + + + quarter + + 64 + 18 + + + + quarter + + 64 + 18 + + + + quarter + + 64 + 18 + + + + quarter + + 64 + 18 + + + + + + + + 2/4 + + + 6 + 1 + + + + quarter + + 72 + 14 + + + + quarter + + 72 + 14 + + + + 1/4 + + + 5 + + + + quarter + + 72 + 14 + + + + 1/4 + + + 1 + + + + quarter + + 72 + 14 + + + + end + + + + + quarter + + 64 + 18 + + + + quarter + + 64 + 18 + + + + quarter + + 64 + 18 + + + + quarter + + 64 + 18 + + + + + + + + + + 4 + 4 + + + 2/4 + + + 6 + 1 + + + + quarter + + 48 + 14 + + + + quarter + + 48 + 14 + + + + 1/4 + + + 5 + + + + quarter + + 48 + 14 + + + + 1/4 + + + 1 + + + + quarter + + 48 + 14 + + + + + + + + 2/4 + + + 6 + 1 + + + + whole + + 55 + 15 + + + + -1/2 + + + 1/4 + + + 5 + + + + 1/4 + + + 1/4 + + + 1 + + + + 1/4 + + + end + + + + + quarter + + 48 + 14 + + + + quarter + + 48 + 14 + + + + quarter + + 48 + 14 + + + + quarter + + 48 + 14 + + + + + + + diff --git a/vtest/figured-bass-1.png b/vtest/figured-bass-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7155d9f5065dd311fc86fca2e08907051eaed6 GIT binary patch literal 9205 zcmdU#cTiK^xA#w|QlyF^BE46s(u)QmRB2KLr1y?=2*LviB1n-Ypi-oFq?h;*N~8-C zq(-{Zi-Z!$8}D;}zdLv4zVFoqaOrq#(wziJ$5{4hcu#S zmqUBs6LSHS;ZB9d>NkjI2oIUH*O7$r zm(XwNb7sV)&TP@tA#rkNd&HA|fe#jL(wNKIfo^#WCb z*fTspbt=AAeRJQ*vJEb(4PNioqrDF%YEBDF~mBblKIfjD34BjeP{uZJm>vLD4TLRIORvLx&WyeT8#r*vBl znhZKQYo-#4L>@m>1m=t|z8J>}uWxe&W#E=b{LZ7{#Mu-7ZAwq@#ZW!>#Qkdc+6-j~ zuSELx0;-+ywrbqf1>%E~Pl&vf;u*0ufa7ZPX4|(?Fea{b#KB@DMRvmQyFD!#o%uPZ z?1+*ea*1UdGHcslx`&&8A^n>5`sP9{7BF~=3f*iIANOCJ~|_#gvLYJa3XHX9iL zcktM#3BpQU;ZES4KC)%HP&AuFCdogiS;Je-lnt~S3+{smj+8`Z3Tn-8b=UI{ z?Evt?M|mkv>K3-Ge=PC4m%rOS$R>D-1Hn_M($^Yc$#JDpSGj#=P+{Sj-R`F?wLmgQ zO&7c7-ZWvRM-NiLX>C<+ytm{zQ-wd5V51GE@bxGZg(#Q(r}#L>3r9Us}q)}X`D+-Y|cj; z!=9z+Lrva^!mR0cWBt8yM6!&o#uvArKPkGr@ChjN`Qsjf6W=>_)@ESYea(a?C1fF1 zauge;zb@~w9@)sn1Py}Iu9XqhLTrP1RunI*c@8OYUZ1gF9K`k&xb_f43J1LFEzh zx;VRcfWDA&yD#0o)Uuh)^m`%TEr51v{{0RdhVnK8T1;;AmJM~#iWTM3loiz^Q6h-A zd^BstH+Os9L~2-eb*{Dc)BpirtdbRfQQj-cSPAV&i_O&t9IYD^s;vY}1 zML@GZZ=Nu;v@wJ*o<#>$aXj~*%`lJe+B6A^BI(S8^Jn*gXIHMnM-zq6yQ@p&cch{e z++}(zQK~tR=gFyjf=0&-CI;SU(MhQ`kvi)cfy4@*o?zxXJXO*loLd z7+gy~`z5Qqvt!6ws9PBaiNSv6H86LewA&bZ36Q zS~97N>>D@2s&}1N1G>}l!WY4^Bcs3Evzf5dWBBZ2Za5;Ur{@trj9*#mQ)hEtneQDLFJD()&1hRsl51 zuadn}8ZtT{i8bJLfBGGbqYR;+Fu*t$Zn!e#YmV|T@Xtd`>~?wdad#N<_f_-*pG5Gk zQImJ%XS?m+;2J;}1~S|SaGBY^edUd#lXKfT{Me^<1X2DJQd=&^G8iO;?GCr)ZPf?X z-v7GlNctLsLL|E3_Ve&pFSg3Hqz0~ocb3W1mAW}6rV83$x;oo_`{YfGsfCHJde-8? zVSWc@jQl?(hskZ;bz+H;`Zft#8NOtG4cTwt^-DWD>O8-*AM#|HL#D>P`NN7UEq7zj zz4QW`&u>gn$}uW3RwryR*!t3fqIu4}n%vkelbzkd<(mN;ZC&@QE7vIQgRU%vml51| zDRXui5FN}*)CX0=D?Z%aNu?ey&P3}TLL|iV9q;%E{=DSXGkL5grQn``eB3P!C($E{t#D0>8q#V95_``EoC7cfxj-B>Y&GI@g_> zFaLI2$a33dHXvl~!eL6aT*b3r!{@xHL*k@&A#2`+*fpD{TUX#?8{H%O+J592$)Q4A zYur9vYQDQpq3z%LQW2_D7SdxNx_dH8g?M_`ZxSpbTA|O zM~9bo;I#;^6l{l5==LS)3hv&%9^chrNcI7Wf##7B(-&P5p7Nr4IFyaof2&qwb=qJ- zNBT&db7^1J!c1HWyGH;vYIuEH@?m9=tEo3EM*r^YLj}es`Fwgh`55%f&~n z!twH-G_ni|B#+y1Q#ZU8$en(J292*S&*%F&Rs{zd{>fk`HKOgf!wiRyy=V>&q*vXwI|EBi{US?VZwAMH>0=ql$pGG zY(rP@PoIL;U$;=R*9arrnnKw#3_*idS6kLkU)=)`r^y%>pHrTY`A^I8uxIJ9q%PA9wpFBd-dSxi!aB{BDvewYQ3CnoNx-) z#U4$r*%cu<;ov_61|q37<=KjJ*0lKR=Q1{VXc;w+oQ{ZeE3`6eRC$J?+(Q~++Te34 zyu@-AUIL+ks67waLp8Tl#BJO-U^pC;4&htb&~$yVk&0)>D=8Go=N1pDoYF9+KmN7@ z9OA>gmsMt9t;NA7)V8*c_Z*8vhn3Mgt5rkRTm(x7vh72ntr9jWE$Z)x*yhk2| zMMlr3d%P+D@fI8J>+J5zWYm& z9xM2dY_C^%Q-o<#IJ-4@MD9udQc4pkhTS#zZ1N`b{^YKIu_#bmw6Hdl&?-H%zW0~q zS~Y+pPrqNwI?1Dl~T=JY{%n!>zh$9#4Aa)8YrGMkKcmj9KX*$z;Y9Q z8V9v}!nu)h+?|-3_Ah3FN}n`m{u!UOOg1t-0C~#vIdp|(`DBT_oegMWH~q-W7S}vL zyCeQ^ZeuTJISXqFMEL*;;XR0%NXnvx&$6bE|`f4I=7iOjwZ7q&KpL0 zhz$VvYZ1xo8!4GQZe=Fls1A7wdzbFSc)*@H-J)9&&LXPiUB7lpGZA1z0NTfIdO4E0 zKmLwXWpuIbNN5$=r}(Hp$^l6edi+~%u$IV{_&I<4#RxBhxOIH*Jpvhza4>LIaWOPn z%PcVRLcZFW$lM}G1Mc^P0YdEL_+KC2%aay_Q}18ff0bx|n=Azgreoyz^o`kc$-Ab8ANndw;+F2OhfNR=S zn{}7puWpZh%>%hSVjx(=JxKXKA6>l{K-6tJF-1@r=p0m>2>Xp?V$+qtBpyoi{?R&D=4+)e0Y^uPg4)euO$eo^I{-NMM8!voif9 z_DadQpI6+F7N9{NDy{=0FY1!cm2eq-fYO2Rfe_d2Ayts#G)rpYp`1HSN-5_m zFVsCxOWJHPZ@wpQ&|Q|QwV~$yqwyhlRlGZYN|EzH2#e$spyJ?#aVyB96Lr`KYF<&jYjp*4lN0twy9a%{qcYjAbLG6sh1T&7j>6kd}rt-?O@e)N6D%K^iq5T#f5E`ZfWmi(;@Eb$y*z{^M8R?u2g{!5hXX3)Yr;(5L8 ztT8l0YT~|}`^}V6dKXfTo(nkf%6v_bs?K!ehfLU`v4~}~JvJ$82p;KcB}!i|kW#e1 zAHwp$hN!IH3FWVWZV#M4+$BzSGI@H<`g-2wTwth_S1a%0jOv1n5fF(g8?^`BZ8v(=Lu+tGo_@VX~E$ zF7zYmZ~3t;oM9466rNUQkA;vcW%5b|@#9rQV^8&`+G#5VGM_cl$-y^=n*j5>r_8>7 z4ZF3!sHy{L8AoFE8h{YuIx0WWPy>ttCKj3X#Mn!%xH}*Ia)`Q^^P@uYbF%4j@g{8? z#p%-p_2cpB6+xLv{F{%vDMs1k?-hh$&!oDluCpq)J{H1i=9+;*sO3s_Ih^f;ov(UQ zpTEAtXM9(aoQ}WvnLovd(vPO!A=)Fy(Iw><4wz074#?Nnb&T)-AHMl7pH+)&CY~m! z87jjcFHuR&M6wls`a}gb!E|Y}C`z?R{f`SM=yNi$KjV==h%v#`X94zqv+_Hnnq)IU z&xfDkc=)|0PfkBvI%zpzXB*;g9*z_uqsMbPF_j9XY9pAoyL@;gy zp@*=g>_qF1*e~BGKY|XB*X@*hQf{l)k2OM?c~s__`)TV)CB`DGhU%U*MBJ8m>S0_( zBVn8Vfr!VA@YUouKy|Nfu_NWh*DH(1B!NLm@p)$_K)L#6yAZ8TWNOBwjL8btM) zQ!m4HNauupd17{g$R`q%VUaV=w*3B}rf&?(_|WRymBBDhdbBL5Z41kO3b^DM(?QV+ zbhX|BA&GHGQqA1s?51=1efQH;#2D|@UhuAEua76eBcvA<8}JUT*RDUi43`Vh9nOM77p z=LkVW%WeE6ryGlt8E_?TC?%hB`j_IHbhr*s{*W2(vE7LL9L+1$^QgmR{R&GE@&0g< zQRLMdczKEV)KhA?T&`=g?W@z0NYI4g z2Cs4F`T%$XG3AbguoOaQ3k&Z(^>`p25EGj|*TTS**oMeD2>UQ4-KB82qtJI0J?W6o zO;Swsr3zpjcUTAm`ylV~g^r{nN^*kS20pJqUFa_Oj2PYGgK;r#=Hn0)7b zo3x7GKiRfy$g7l5N8x(V*OT$`d1X6xcDL~J`Df@pQ zWWXtVSr>z2N#rV2L*!hjx zaP9T0eq*KkwUMyt*fF}E8#cL}J}pjDim!h4ga0aCYM6EsUN+JuIH#7kOx8&z=gxq? zz=$@xAd#tB%TDKjvsK?nKpa7r7^|T@Tvr=3Jm<{n)|7JjgEC*IF9p`#uo;lk zp_=WMH?yuEc3Y$p;PReR7lf?`jvBaJRP5WDM$JdtCvL1u(1wUk^kA}#JJGX|-leuj zFiNd_iDQRn4W1r2I{X-wtIzG5yhA~5PbBl2zDIHPNrA4CM;{~fV0#HNFv`z2kwI5X z$g&tkD0w>iQxLnhM)ANjmz|Tp;#_Iu?>iVErSUOpJ>o;qEQ2?xe1SFioWHy_H|w z3S7?mO&+dPu%i_yGC_Io5f5*>Q!X}($IaEmzZ&X#GPc6e|1NuvtUGI7U-5XDOMytw z3}jBx3CE2j3&S$urcFJ9R%yi#Dk^~0-?TXw?1fSq`xamq73h(F_mZO&hbUM4?I1<= zQ=?Jr8^U@iL;02(eF9xCv2hE107bElL14%XN56lI&R_y8~tK&!kTOKMjJ`p>&+ST7CO*yU^3^JoNEtn4%u7SxxqCt z-i25Lv&Tx<5AXLQrx5JiVjA;?hs~vpoDzS3*p{UIG7ZKj{fVr%cf=m%UfZFVkZcP%@(mQ-Zui#*v%iJp5hU95txT=U|V^ck=TS@d}P0;sD+?lCoNIO_9 zlvU4>Oo#Di#4C42E-@#2`$AKMmC(GiyX?N$GRdTHyac8ggp@Fz?8B4vHFjRNEQlQU zV95PA*hm{MPd^^G7M-WBjo}+IPIe;jt!;t-_EW3Cvo*m1n@<||KN&HCm?nHkG2msY z`COTBF@7matAUHa64%mmWFzo?; z_ynoxnb;&gwwmiO=f2_MX{pY!Nol9kDYl&`?@?;xYrXKNEs{b&=uq_2f2J2J|7ZHV zf2Ke8+NsfYFa}{8I1gz3to`wC5&8&P;YDxvrJ6Z2K$9+CAh{?&w8XQP&)H>YB|g!9 zb6|*op{Ax}UlX`4Fy}(VIUjBrda_ql+{;wB@jW`aO!Bn~li&cma8i-2#uvYUH!;WM zTJql2lCNcjW{G_1CQ|L0B=R?2R$OzZ42Zc%+gW;Wd};&M6>LxZbqH8L>SkFN$_>r` zDRMXv4c3#;FCA2wDgDS?dKfg@MSJcAYR$y0sdg^e37ZtNikA!a{~RtfmoKn2$ezr7 zSntnjPUyJfcnO67=Wq2qb$Ap~2^Z@taPX`Oc+PD}T=U_G)6^7{UF85d+4Iar2U1N4 zO{^2v9~T(^*}KuIOwezGc;1Dn!-vCA1?sh#Oae+z63|h)oyeER_trkJZ)0C(^)!>Q zt9X*}QZEVrn()fbj~?UgZcXH%+uUl37Y-g?U_X;KDPBbh0aSxn-i6geV$Z(`0VSNZTp4%xoGz%)I_Pn=P%c$L-{sDzeJoL5b;J5n&)*BZKL%bEDY zhfQ(%C8BHQN+T;?f&(;QQoB)}l$H|KpY@-pXO!CVl~W9`J=i6J=CaPn1hvWOlI6}t z8*oPjp>xcg*izm0BQTE$wGu@oF+L$dr;g0*j7@oPiNnnaE`Q|-AwT}Uo*U#p$!71W zHbt|~>vpUd^kg>^O^ct-9xMJN2RC}%8KTX%O?6@5&md6e<&QuzLqRVO`DPydLobz@ z_W|Auxmv^IjKVS=k7FbmK-d3HfKQNp_mHEN%GLoEoQ?P5bS~Y)apPB#O%hjWFGcZhd!sug9^X(CDj@iRUo<%O_N^qTxTAVb4pnJ@S& zC<(PqK9-M^0HHu8{u0(k-kwhzQU2AHz>#IL&tGK2ZH~HV3;(Q?UrAFkL6u>tAPaH+ zkNp1%t~Vu`cA<&(<$w3kuUzhtMHPq)z`zu5L8S~*hh1+5+4#$&JNSnpVb*{~aemM{ zkcgo0dzPv!5iBuVmDFpM5;*jPyx>o7M+=AXnmnt_BB-j}h>t^|g+Ty7{PxdY0MyQQ zs8TT5BBAs(1S>e{Fu)?o&O|0@$@4UZEnA=c{-MSFOw|77cq!e=kC$3K>CcN71{`y* zxw=$9Ge7Cv%$5d^CIU>Wj8a*oq;1)pXTa)UaY^9fY z<232x=N!)79vydo(Yz;Vgzjw76p}Q??EIp6@ZWbLl;7wbpKL}olP42R1Kz~l*XGSU zz(o$X_a&DDqM^)Rn&@V(wZ_ccawktIIuBKXkp7#IDO!omjU04~RzvK!{jp2T`%HE_ zEGtG51X9Hu@T@hF)-km5v_*5}$FAoGk;>R7^GEU8kmg;-G1fU${})RJY|+?h<^P+I zul<{lV~z;MO0D}%iLe9VLEyur08oaHY@MlpcmQSr9I)mc7=?1ZmrN{6DD8Z0ut}R={4Yd?Oq#zM4f=8s z;{`1xN&%r6(K4o8eTYIrxd_?;zdSs%fNG9H7Sm_5f?^^cwHQ;{Q5hyy8RVH>I-2~xT7`k1tdZok_ ziek<$7^#@H03WTcqb|K*Hp9V0bJI*2ln4LF4UR&XUm_&>TnbX6z!P#6GHcz4)Ey&R z*OG9OQ@sUsM-gCAEn*Z)98QD=vGa5{<+|Th=vsQo(qDf-09uy3W;TP|7fjGFPavX` zu(RWs9HUIA$n%_l7L|I@Y#KNPHYS3qM8V8w2DnV!MbhQ|#D96bM@x`{X5D@4C3Bzo vQ|0Th361IE&F0zvyQlr{x4?W_!jmsaRywb!|0e9;0RV`GKDg$A-HZPNWA}q? literal 0 HcmV?d00001 diff --git a/vtest/gen b/vtest/gen index f5ae275ce6507..9e27acd8405d1 100755 --- a/vtest/gen +++ b/vtest/gen @@ -54,6 +54,7 @@ else tuplets-1 tuplets-2 tuplets-3 tuplets-4 breath-1\ harmony-1 harmony-2 harmony-3 harmony-4 harmony-5 harmony-6 harmony-7\ harmony-8 harmony-9 harmony-10 harmony-11 harmony-12 harmony-13 harmony-14\ + figured-bass-1\ beams-1 beams-2 beams-3 beams-4 beams-5 beams-6 beams-7 beams-8 beams-9 beams-10\ beams-11 beams-12 beams-13 beams-14 beams-15 beams-16 beams-17\ user-offset-1 user-offset-2 chord-space-1 chord-space-2 tablature-1 image-1\ diff --git a/vtest/gen.bat b/vtest/gen.bat index 05c97f596690b..e995a00d208cc 100644 --- a/vtest/gen.bat +++ b/vtest/gen.bat @@ -32,6 +32,7 @@ set SRC=mmrest-1,bravura-mmrest,gonville-mmrest,mmrest-2,mmrest-4,mmrest-5,mmres tuplets-1,tuplets-2,tuplets-3,tuplets-4,breath-1, ^ harmony-1,harmony-2,harmony-3,harmony-4,harmony-5,harmony-6,harmony-7, ^ harmony-8,harmony-9,harmony-10,harmony-11,harmony-12,harmony-13,harmony-14, ^ + figured-bass-1, ^ beams-1,beams-2,beams-3,beams-4,beams-5,beams-6,beams-7,beams-8,beams-9,beams-10, ^ beams-11,beams-12,beams-13,beams-14,beams-15,beams-16,beams-17, ^ user-offset-1,user-offset-2,chord-space-1,chord-space-2,tablature-1,image-1, ^ From 008814b2f0ee872acee34d477946cd6d45668a89 Mon Sep 17 00:00:00 2001 From: Matt McClinch Date: Sat, 7 Mar 2020 01:38:01 -0500 Subject: [PATCH 39/49] fix #302011: Grace note tie crash Resolves: https://musescore.org/en/node/302011. When creating a tie from a grace note to its main note, make sure not to overwrite the main note's chord, thus destroying the grace note and creating a tie from a note to itself. --- libmscore/edit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libmscore/edit.cpp b/libmscore/edit.cpp index 2125edab12657..9584957cfca2e 100644 --- a/libmscore/edit.cpp +++ b/libmscore/edit.cpp @@ -1254,6 +1254,7 @@ void Score::cmdAddTie(bool addToChord) if (c->isGraceBefore()) { // tie grace note before to main note cr = toChord(c->parent()); + addToChord = true; } else { _is.setSegment(note->chord()->segment()); From 3bc26748ea3e50484aa340d9355a1d5e5becb9d2 Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 25 Feb 2020 21:52:11 +0800 Subject: [PATCH 40/49] fix #301555 part 2: invisible glissandi occupy space --- libmscore/chord.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index 2c8c8873f4adf..c9de7a8104aa5 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -1980,10 +1980,20 @@ void Chord::layoutPitched() // allocate enough room for glissandi if (_endsGlissando) { - if (!rtick().isZero() // if not at beginning of measure - || graceNotesBefore.size() > 0) // or there are graces before - lll += _spatium * 0.5 + minTieLength; - // special case of system-initial glissando final note is handled in Glissando::layout() itself + for (const Note* note : notes()) { + for (const Spanner* sp : note->spannerBack()) { + if (sp->isGlissando()) { + if (toGlissando(sp)->visible()) { + if (!rtick().isZero() // if not at beginning of measure + || graceNotesBefore.size() > 0) { // or there are graces before + lll += _spatium * 0.5 + minTieLength; + break; + } + } + } + } + } + // special case of system-initial glissando final note is handled in Glissando::layout() itself } if (dots()) { From a5e264dcb59b1cde8698ee275411126d6df5eb9a Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sat, 7 Mar 2020 12:42:06 +0100 Subject: [PATCH 41/49] follow up fix for Barbershop-Women template, #5770 --- share/instruments/instrumentsxml.h | 3 ++- share/templates/CMakeLists.txt | 4 ++++ share/templates/convert.json | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/share/instruments/instrumentsxml.h b/share/instruments/instrumentsxml.h index 3e37959f2785f..82d998f68c335 100644 --- a/share/instruments/instrumentsxml.h +++ b/share/instruments/instrumentsxml.h @@ -11,7 +11,8 @@ QT_TRANSLATE_NOOP("Templates", "SATB Closed Score"), QT_TRANSLATE_NOOP("Templates", "SATB Closed Score + Organ"), QT_TRANSLATE_NOOP("Templates", "SATB Closed Score + Piano"), QT_TRANSLATE_NOOP("Templates", "Voice + Piano"), -QT_TRANSLATE_NOOP("Templates", "Barbershop Quartet"), +QT_TRANSLATE_NOOP("Templates", "Barbershop Quartet (Men)"), +QT_TRANSLATE_NOOP("Templates", "Barbershop Quartet (Women)"), QT_TRANSLATE_NOOP("Templates", "Liturgical Unmetrical"), QT_TRANSLATE_NOOP("Templates", "Liturgical Unmetrical + Organ"), QT_TRANSLATE_NOOP("Templates", "Chamber Music"), diff --git a/share/templates/CMakeLists.txt b/share/templates/CMakeLists.txt index 871feb61992f6..6e38cb16a88a4 100644 --- a/share/templates/CMakeLists.txt +++ b/share/templates/CMakeLists.txt @@ -17,6 +17,10 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #============================================================================= +# adding or renaming templates here should also better be done in convert.json, +# but definitely need to get reflected in ../instruments/instrumentsxml.h, +# like by running ../instruments/generateTs.py + install(FILES drumset_fr.drm orchestral.drm diff --git a/share/templates/convert.json b/share/templates/convert.json index 104466727d5c3..4dee2ca004aca 100644 --- a/share/templates/convert.json +++ b/share/templates/convert.json @@ -10,9 +10,10 @@ { "in": "02-Choral/05-SATB_Closed_Score_+_Organ.mscx", "out": "02-Choral/05-SATB_Closed_Score_+_Organ.mscz"}, { "in": "02-Choral/06-SATB_Closed_Score_+_Piano.mscx", "out": "02-Choral/06-SATB_Closed_Score_+_Piano.mscz"}, { "in": "02-Choral/07-Voice_+_Piano.mscx", "out": "02-Choral/07-Voice_+_Piano.mscz"}, -{ "in": "02-Choral/08-Barbershop_Quartet.mscx", "out": "02-Choral/08-Barbershop_Quartet.mscz"}, -{ "in": "02-Choral/09-Liturgical_Unmetrical.mscx", "out": "02-Choral/09-Liturgical_Unmetrical.mscz"}, -{ "in": "02-Choral/10-Liturgical_Unmetrical_+_Organ.mscx", "out": "02-Choral/10-Liturgical_Unmetrical_+_Organ.mscz"}, +{ "in": "02-Choral/08-Barbershop_Quartet_(Men).mscx", "out": "02-Choral/08-Barbershop_Quartet_(Men).mscz"}, +{ "in": "02-Choral/09-Barbershop_Quartet_(Women).mscx", "out": "02-Choral/09-Barbershop_Quartet_(Women).mscz"}, +{ "in": "02-Choral/10-Liturgical_Unmetrical.mscx", "out": "02-Choral/10-Liturgical_Unmetrical.mscz"}, +{ "in": "02-Choral/11-Liturgical_Unmetrical_+_Organ.mscx", "out": "02-Choral/11-Liturgical_Unmetrical_+_Organ.mscz"}, { "in": "03-Chamber_Music/01-String_Quartet.mscx", "out": "03-Chamber_Music/01-String_Quartet.mscz"}, { "in": "03-Chamber_Music/02-Wind_Quartet.mscx", "out": "03-Chamber_Music/02-Wind_Quartet.mscz"}, { "in": "03-Chamber_Music/03-Wind_Quintet.mscx", "out": "03-Chamber_Music/03-Wind_Quintet.mscz"}, From cc03d0d03f50d9f9d406707609e103b9a6f6649e Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sun, 8 Mar 2020 13:29:52 +0100 Subject: [PATCH 42/49] Fix #302118: Need 24 and 32 bit WAV and FLAC audio exports and while at it, signed 8 bit too (unsigned 8 bit won't work for FLAC) --- global/settings/types/preferencekeys.h | 1 + mscore/exportaudio.cpp | 15 ++++++++++++--- mscore/preferences.cpp | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/global/settings/types/preferencekeys.h b/global/settings/types/preferencekeys.h index 791e48a9d9113..2a7bf30ee8464 100644 --- a/global/settings/types/preferencekeys.h +++ b/global/settings/types/preferencekeys.h @@ -53,6 +53,7 @@ #define PREF_APP_TELEMETRY_ALLOWED "application/telemetry/allowed" #define PREF_EXPORT_AUDIO_NORMALIZE "export/audio/normalize" #define PREF_EXPORT_AUDIO_SAMPLERATE "export/audio/sampleRate" +#define PREF_EXPORT_AUDIO_PCMRATE "export/audio/PCMRate" #define PREF_EXPORT_MP3_BITRATE "export/mp3/bitRate" #define PREF_EXPORT_MUSICXML_EXPORTLAYOUT "export/musicXML/exportLayout" #define PREF_EXPORT_MUSICXML_EXPORTBREAKS "export/musicXML/exportBreaks" diff --git a/mscore/exportaudio.cpp b/mscore/exportaudio.cpp index 90896d8c6bf08..60587d978fd26 100644 --- a/mscore/exportaudio.cpp +++ b/mscore/exportaudio.cpp @@ -272,12 +272,21 @@ bool MuseScore::saveAudio(Score* score, const QString& name) } }; int format; + int PCMRate; + switch (preferences.getInt(PREF_EXPORT_AUDIO_PCMRATE)) { + case 32: PCMRate = SF_FORMAT_PCM_32; break; + case 24: PCMRate = SF_FORMAT_PCM_24; break; + case 16: PCMRate = SF_FORMAT_PCM_16; break; + case 8: PCMRate = SF_FORMAT_PCM_S8; break; + default: PCMRate = SF_FORMAT_PCM_16; break; + } + if (name.endsWith(".wav")) - format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; + format = SF_FORMAT_WAV | PCMRate; else if (name.endsWith(".ogg")) format = SF_FORMAT_OGG | SF_FORMAT_VORBIS; - else if (name.endsWith("flac")) - format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16; + else if (name.endsWith(".flac")) + format = SF_FORMAT_FLAC | PCMRate; else { qDebug("unknown audio file type <%s>", qPrintable(name)); return false; diff --git a/mscore/preferences.cpp b/mscore/preferences.cpp index 438df56bf92a2..c03915668625d 100644 --- a/mscore/preferences.cpp +++ b/mscore/preferences.cpp @@ -102,6 +102,7 @@ void Preferences::init(bool storeInMemoryOnly) {PREF_APP_STARTUP_TELEMETRY_ACCESS_REQUESTED, new StringPreference("", false)}, {PREF_EXPORT_AUDIO_NORMALIZE, new BoolPreference(true)}, {PREF_EXPORT_AUDIO_SAMPLERATE, new IntPreference(44100, false)}, + {PREF_EXPORT_AUDIO_PCMRATE, new IntPreference(16)}, {PREF_EXPORT_MP3_BITRATE, new IntPreference(128, false)}, {PREF_EXPORT_MUSICXML_EXPORTBREAKS, new EnumPreference(QVariant::fromValue(MusicxmlExportBreaks::ALL), false)}, {PREF_EXPORT_MUSICXML_EXPORTLAYOUT, new BoolPreference(true, false)}, From 16aecb232b324b24319753f184013106829656a2 Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Sun, 8 Mar 2020 13:30:07 +0100 Subject: [PATCH 43/49] code formatting +collect_artifacts --- mscore/exportaudio.cpp | 466 ++++++++++++++++++++--------------------- 1 file changed, 233 insertions(+), 233 deletions(-) diff --git a/mscore/exportaudio.cpp b/mscore/exportaudio.cpp index 60587d978fd26..9c5b3ad440c4f 100644 --- a/mscore/exportaudio.cpp +++ b/mscore/exportaudio.cpp @@ -41,174 +41,174 @@ namespace Ms { /// If the callback function is non zero an returns false the export will be canceled. /// bool MuseScore::saveAudio(Score* score, QIODevice *device, std::function updateProgress) - { - if (!device) { - qDebug() << "Invalid device"; - return false; - } - - if (!device->open(QIODevice::WriteOnly)) { - qDebug() << "Could not write to device"; - return false; - } - - EventMap events; - // In non-GUI mode current synthesizer settings won't - // allow single note dynamics. See issue #289947. - const bool useCurrentSynthesizerState = !MScore::noGui; - - if (useCurrentSynthesizerState) { - score->renderMidi(&events, synthesizerState()); - if (events.empty()) - return false; - } - - MasterSynthesizer* synth = synthesizerFactory(); - synth->init(); - int sampleRate = preferences.getInt(PREF_EXPORT_AUDIO_SAMPLERATE); - synth->setSampleRate(sampleRate); - if (MScore::noGui) { // use score settings if possible - bool r = synth->setState(score->synthesizerState()); - if (!r) - synth->init(); - } - else { // use current synth settings - bool r = synth->setState(mscore->synthesizerState()); - if (!r) - synth->init(); - } - - if (!useCurrentSynthesizerState) { - score->masterScore()->rebuildAndUpdateExpressive(synth->synthesizer("Fluid")); - score->renderMidi(&events, score->synthesizerState()); - if (synti) - score->masterScore()->rebuildAndUpdateExpressive(synti->synthesizer("Fluid")); - - if (events.empty()) - return false; - } - - int oldSampleRate = MScore::sampleRate; - MScore::sampleRate = sampleRate; - - float peak = 0.0; - double gain = 1.0; - EventMap::const_iterator endPos = events.cend(); - --endPos; - const int et = (score->utick2utime(endPos->first) + 1) * MScore::sampleRate; - const int maxEndTime = (score->utick2utime(endPos->first) + 3) * MScore::sampleRate; - - bool cancelled = false; - int passes = preferences.getBool(PREF_EXPORT_AUDIO_NORMALIZE) ? 2 : 1; - for (int pass = 0; pass < passes; ++pass) { - EventMap::const_iterator playPos; - playPos = events.cbegin(); - synth->allSoundsOff(-1); - - // - // init instruments - // - for (Part* part : score->parts()) { - const InstrumentList* il = part->instruments(); - for (auto i = il->begin(); i!= il->end(); i++) { - for (const Channel* instrChan : i->second->channel()) { - const Channel* a = score->masterScore()->playbackChannel(instrChan); - for (MidiCoreEvent e : a->initList()) { - if (e.type() == ME_INVALID) - continue; - e.setChannel(a->channel()); - int syntiIdx = synth->index(score->masterScore()->midiMapping(a->channel())->articulation()->synti()); - synth->play(e, syntiIdx); - } - } - } - } - - static const unsigned FRAMES = 512; - float buffer[FRAMES * 2]; - int playTime = 0; - - for (;;) { - unsigned frames = FRAMES; - // - // collect events for one segment - // - float max = 0.0; - memset(buffer, 0, sizeof(float) * FRAMES * 2); - int endTime = playTime + frames; - float* p = buffer; - for (; playPos != events.cend(); ++playPos) { - int f = score->utick2utime(playPos->first) * MScore::sampleRate; - if (f >= endTime) - break; - int n = f - playTime; - if (n) { - synth->process(n, p); - p += 2 * n; - } - - playTime += n; - frames -= n; - const NPlayEvent& e = playPos->second; - if (e.isChannelEvent()) { - int channelIdx = e.channel(); - const Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation(); - if (!c->mute()) { - synth->play(e, synth->index(c->synti())); - } - } - } - if (frames) { - synth->process(frames, p); - playTime += frames; - } - if (pass == 1) { - for (unsigned i = 0; i < FRAMES * 2; ++i) { - max = qMax(max, qAbs(buffer[i])); - buffer[i] *= gain; - } - } - else { - for (unsigned i = 0; i < FRAMES * 2; ++i) { - max = qMax(max, qAbs(buffer[i])); - peak = qMax(peak, qAbs(buffer[i])); - } - } - if (pass == (passes - 1)) - device->write(reinterpret_cast(buffer), 2 * FRAMES * sizeof(float)); - playTime = endTime; - if (updateProgress) { - // normalize to [0, 1] range - if (!updateProgress(float(pass * et + playTime) / passes / et)) { - cancelled = true; + { + if (!device) { + qDebug() << "Invalid device"; + return false; + } + + if (!device->open(QIODevice::WriteOnly)) { + qDebug() << "Could not write to device"; + return false; + } + + EventMap events; + // In non-GUI mode current synthesizer settings won't + // allow single note dynamics. See issue #289947. + const bool useCurrentSynthesizerState = !MScore::noGui; + + if (useCurrentSynthesizerState) { + score->renderMidi(&events, synthesizerState()); + if (events.empty()) + return false; + } + + MasterSynthesizer* synth = synthesizerFactory(); + synth->init(); + int sampleRate = preferences.getInt(PREF_EXPORT_AUDIO_SAMPLERATE); + synth->setSampleRate(sampleRate); + if (MScore::noGui) { // use score settings if possible + bool r = synth->setState(score->synthesizerState()); + if (!r) + synth->init(); + } + else { // use current synth settings + bool r = synth->setState(mscore->synthesizerState()); + if (!r) + synth->init(); + } + + if (!useCurrentSynthesizerState) { + score->masterScore()->rebuildAndUpdateExpressive(synth->synthesizer("Fluid")); + score->renderMidi(&events, score->synthesizerState()); + if (synti) + score->masterScore()->rebuildAndUpdateExpressive(synti->synthesizer("Fluid")); + + if (events.empty()) + return false; + } + + int oldSampleRate = MScore::sampleRate; + MScore::sampleRate = sampleRate; + + float peak = 0.0; + double gain = 1.0; + EventMap::const_iterator endPos = events.cend(); + --endPos; + const int et = (score->utick2utime(endPos->first) + 1) * MScore::sampleRate; + const int maxEndTime = (score->utick2utime(endPos->first) + 3) * MScore::sampleRate; + + bool cancelled = false; + int passes = preferences.getBool(PREF_EXPORT_AUDIO_NORMALIZE) ? 2 : 1; + for (int pass = 0; pass < passes; ++pass) { + EventMap::const_iterator playPos; + playPos = events.cbegin(); + synth->allSoundsOff(-1); + + // + // init instruments + // + for (Part* part : score->parts()) { + const InstrumentList* il = part->instruments(); + for (auto i = il->begin(); i!= il->end(); i++) { + for (const Channel* instrChan : i->second->channel()) { + const Channel* a = score->masterScore()->playbackChannel(instrChan); + for (MidiCoreEvent e : a->initList()) { + if (e.type() == ME_INVALID) + continue; + e.setChannel(a->channel()); + int syntiIdx = synth->index(score->masterScore()->midiMapping(a->channel())->articulation()->synti()); + synth->play(e, syntiIdx); + } + } + } + } + + static const unsigned FRAMES = 512; + float buffer[FRAMES * 2]; + int playTime = 0; + + for (;;) { + unsigned frames = FRAMES; + // + // collect events for one segment + // + float max = 0.0; + memset(buffer, 0, sizeof(float) * FRAMES * 2); + int endTime = playTime + frames; + float* p = buffer; + for (; playPos != events.cend(); ++playPos) { + int f = score->utick2utime(playPos->first) * MScore::sampleRate; + if (f >= endTime) + break; + int n = f - playTime; + if (n) { + synth->process(n, p); + p += 2 * n; + } + + playTime += n; + frames -= n; + const NPlayEvent& e = playPos->second; + if (e.isChannelEvent()) { + int channelIdx = e.channel(); + const Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation(); + if (!c->mute()) { + synth->play(e, synth->index(c->synti())); + } + } + } + if (frames) { + synth->process(frames, p); + playTime += frames; + } + if (pass == 1) { + for (unsigned i = 0; i < FRAMES * 2; ++i) { + max = qMax(max, qAbs(buffer[i])); + buffer[i] *= gain; + } + } + else { + for (unsigned i = 0; i < FRAMES * 2; ++i) { + max = qMax(max, qAbs(buffer[i])); + peak = qMax(peak, qAbs(buffer[i])); + } + } + if (pass == (passes - 1)) + device->write(reinterpret_cast(buffer), 2 * FRAMES * sizeof(float)); + playTime = endTime; + if (updateProgress) { + // normalize to [0, 1] range + if (!updateProgress(float(pass * et + playTime) / passes / et)) { + cancelled = true; + break; + } + } + if (playTime >= et) + synth->allNotesOff(-1); + // create sound until the sound decays + if (playTime >= et && max*peak < 0.000001) break; - } - } - if (playTime >= et) - synth->allNotesOff(-1); - // create sound until the sound decays - if (playTime >= et && max*peak < 0.000001) - break; - // hard limit - if (playTime > maxEndTime) - break; - } - if (cancelled) - break; - if (pass == 0 && peak == 0.0) { - qDebug("song is empty"); - break; - } - gain = 0.99 / peak; - } - - MScore::sampleRate = oldSampleRate; - delete synth; - - device->close(); - - return !cancelled; -} + // hard limit + if (playTime > maxEndTime) + break; + } + if (cancelled) + break; + if (pass == 0 && peak == 0.0) { + qDebug("song is empty"); + break; + } + gain = 0.99 / peak; + } + + MScore::sampleRate = oldSampleRate; + delete synth; + + device->close(); + + return !cancelled; + } #ifdef HAS_AUDIOFILE @@ -219,58 +219,58 @@ bool MuseScore::saveAudio(Score* score, QIODevice *device, std::function(dta), trueFrames); - return trueFrames * 2 * sizeof(float); - } - - bool open(QIODevice::OpenMode mode) { - if ((mode & QIODevice::WriteOnly) == 0) { - return false; - } - sf = sf_open(qPrintable(filename), SFM_WRITE, &info); - if (sf == nullptr) { - qDebug("open soundfile failed: %s", sf_strerror(sf)); - return false; - } - return QIODevice::open(mode); - } - void close() { - if (sf && sf_close(sf)) { - qDebug("close soundfile failed"); - } - sf = nullptr; - QIODevice::close(); - } - }; + // QIODevice - SoundFile wrapper class + class SoundFileDevice : public QIODevice { + private: + SF_INFO info; + SNDFILE *sf = nullptr; + const QString filename; + public: + SoundFileDevice(int sampleRate, int format, const QString& name) + : filename(name) { + memset(&info, 0, sizeof(info)); + info.channels = 2; + info.samplerate = sampleRate; + info.format = format; + } + ~SoundFileDevice() { + if (sf) { + sf_close(sf); + sf = nullptr; + } + } + + virtual qint64 readData(char *dta, qint64 maxlen) override final { + Q_UNUSED(dta); + qDebug() << "Error: No write supported!"; + return maxlen; + } + + virtual qint64 writeData(const char *dta, qint64 len) override final { + size_t trueFrames = len / sizeof(float) / 2; + sf_writef_float(sf, reinterpret_cast(dta), trueFrames); + return trueFrames * 2 * sizeof(float); + } + + bool open(QIODevice::OpenMode mode) { + if ((mode & QIODevice::WriteOnly) == 0) { + return false; + } + sf = sf_open(qPrintable(filename), SFM_WRITE, &info); + if (sf == nullptr) { + qDebug("open soundfile failed: %s", sf_strerror(sf)); + return false; + } + return QIODevice::open(mode); + } + void close() { + if (sf && sf_close(sf)) { + qDebug("close soundfile failed"); + } + sf = nullptr; + QIODevice::close(); + } + }; int format; int PCMRate; switch (preferences.getInt(PREF_EXPORT_AUDIO_PCMRATE)) { @@ -298,12 +298,12 @@ bool MuseScore::saveAudio(Score* score, const QString& name) return false; MasterSynthesizer* synth = synthesizerFactory(); - synth->init(); + synth->init(); int sampleRate = preferences.getInt(PREF_EXPORT_AUDIO_SAMPLERATE); - synth->setSampleRate(sampleRate); + synth->setSampleRate(sampleRate); bool r = synth->setState(score->synthesizerState()); if (!r) - synth->init(); + synth->init(); int oldSampleRate = MScore::sampleRate; MScore::sampleRate = sampleRate; @@ -321,19 +321,19 @@ bool MuseScore::saveAudio(Score* score, const QString& name) progress.setCancelButtonText(tr("Cancel")); progress.setLabelText(tr("Exporting…")); if (!MScore::noGui) { - // callback function that will update the progress bar - // it will return false and thus cancel the export if the user - // cancels the progress dialog. - progressCallback = [&progress](float v) -> bool { - if (progress.wasCanceled()) - return false; - progress.setValue(v * 1000); - qApp->processEvents(); - return true; - }; + // callback function that will update the progress bar + // it will return false and thus cancel the export if the user + // cancels the progress dialog. + progressCallback = [&progress](float v) -> bool { + if (progress.wasCanceled()) + return false; + progress.setValue(v * 1000); + qApp->processEvents(); + return true; + }; progress.show(); - } + } // The range is set arbitrarily to 1000 as steps. // The callback will return float numbers between 0 and 1 From ba9ebc83aa3c5a0c53af7b737c60597eba3bab55 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Mon, 9 Mar 2020 15:51:03 +0200 Subject: [PATCH 44/49] Score comparison tool: avoid crash on inability to merge text diffs Calling merge() on non-adjacent text diffs should probably not happen and reveals a potential bug in score diff code, but it is not a fatal error and should not lead to MuseScore crash. This commit avoids terminating MuseScore in this case. Score comparison still produces sensible results in case of such error. --- libmscore/scorediff.cpp | 23 ++++++++++++++++------- libmscore/scorediff.h | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/libmscore/scorediff.cpp b/libmscore/scorediff.cpp index 374ad9e3f2d3d..5f7b0b6c285a7 100644 --- a/libmscore/scorediff.cpp +++ b/libmscore/scorediff.cpp @@ -403,14 +403,17 @@ int MscxModeDiff::performShiftDiff(std::vector& diffs, int index, int std::copy(chunkEnd, chunkEnd + 2, eqDiff.end); const int prevDiffIdx = index + (down ? -1 : 1); + bool merged = false; if (diffs[prevDiffIdx].type == DiffType::EQUAL) - diffs[prevDiffIdx].merge(eqDiff); - else { + merged = diffs[prevDiffIdx].merge(eqDiff); + + if (!merged) { const int insertIdx = down ? index : (index + 1); diffs.insert(diffs.begin() + insertIdx, eqDiff); if (down) ++index; } + return index; } @@ -1170,7 +1173,7 @@ QString ScoreDiff::userDiff() const // TextDiff::merge //--------------------------------------------------------- -void TextDiff::merge(const TextDiff& other) +bool TextDiff::merge(const TextDiff& other) { if (type == other.type) { if (other.end[0] == (start[0] - 1) && other.end[1] == (start[1] - 1)) { @@ -1185,8 +1188,10 @@ void TextDiff::merge(const TextDiff& other) text[0].append(other.text[0]); text[1].append(other.text[1]); } - else - qFatal("TextDiff:merge: invalid argument: wrong line numbers"); + else { + qWarning("TextDiff:merge: invalid argument: wrong line numbers"); + return false; + } } else if ((type == DiffType::INSERT && other.type == DiffType::DELETE) || (type == DiffType::DELETE && other.type == DiffType::INSERT) @@ -1197,8 +1202,12 @@ void TextDiff::merge(const TextDiff& other) end[iOther] = other.end[iOther]; text[iOther] = other.text[iOther]; } - else - qFatal("TextDiff:merge: invalid argument: wrong types"); + else { + qWarning("TextDiff:merge: invalid argument: wrong types"); + return false; + } + + return true; } //--------------------------------------------------------- diff --git a/libmscore/scorediff.h b/libmscore/scorediff.h index 18c3623a4b044..c9e5150979c77 100644 --- a/libmscore/scorediff.h +++ b/libmscore/scorediff.h @@ -56,7 +56,7 @@ struct TextDiff { int start[2]; // starting line numbers in both texts int end[2]; // ending line numbers in both texts - void merge(const TextDiff& other); // merge other diff into this one + bool merge(const TextDiff& other); // merge other diff into this one QString toString(DiffType type, bool prefixLines = false) const; QString toString(bool prefixLines = false) const { return toString(type, prefixLines); } }; From 22db2720be074a4d571bc03b5c0ec1e89e7e6de1 Mon Sep 17 00:00:00 2001 From: "J. Edward Sanchez" Date: Mon, 9 Mar 2020 13:15:42 -0700 Subject: [PATCH 45/49] Fix #302171: Preferences | Shortcuts should also search by keyboard shortcut Enhanced the Search box on the Shortcuts tab of the Preferences dialog to support searching for currently defined keyboard shortcuts in addition to action descriptions. --- mscore/prefsdialog.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mscore/prefsdialog.cpp b/mscore/prefsdialog.cpp index 6416f80c5ee70..b4e4227647dff 100644 --- a/mscore/prefsdialog.cpp +++ b/mscore/prefsdialog.cpp @@ -711,11 +711,7 @@ void PreferenceDialog::filterShortcutsTextChanged(const QString &query ) QTreeWidgetItem *item; for(int i = 0; i < shortcutList->topLevelItemCount(); i++) { item = shortcutList->topLevelItem(i); - - if(item->text(0).toLower().contains(query.toLower())) - item->setHidden(false); - else - item->setHidden(true); + item->setHidden(!(item->text(0).contains(query, Qt::CaseInsensitive) || item->text(1).contains(query, Qt::CaseInsensitive))); } } From f97cfd1f1a3c5fb72fea09f5c5f5cdae4b3e9487 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Wed, 5 Feb 2020 11:49:51 +0200 Subject: [PATCH 46/49] fix #289643: fix crashes if volta anchor is set incorrectly in MSCZ file --- libmscore/volta.cpp | 24 +++++++++++++++++++++--- libmscore/volta.h | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/libmscore/volta.cpp b/libmscore/volta.cpp index 827bd08e9371a..a5ea732b280e3 100644 --- a/libmscore/volta.cpp +++ b/libmscore/volta.cpp @@ -98,7 +98,7 @@ Volta::Volta(Score* s) resetProperty(Pid::BEGIN_HOOK_TYPE); resetProperty(Pid::END_HOOK_TYPE); - setAnchor(Anchor::MEASURE); + setAnchor(VOLTA_ANCHOR); } //--------------------------------------------------------- @@ -138,11 +138,29 @@ void Volta::read(XmlReader& e) _endings.append(i); } } - else if (!TextLineBase::readProperties(e)) + else if (!readProperties(e)) e.unknown(); } } +//--------------------------------------------------------- +// readProperties +//--------------------------------------------------------- + +bool Volta::readProperties(XmlReader& e) + { + if (!TextLineBase::readProperties(e)) + return false; + + if (anchor() != VOLTA_ANCHOR) { + // Volta strictly assumes that its anchor is measure, so don't let old scores override this. + qWarning("Correcting volta anchor type from %d to %d", int(anchor()), int(VOLTA_ANCHOR)); + setAnchor(VOLTA_ANCHOR); + } + + return true; + } + //--------------------------------------------------------- // write //--------------------------------------------------------- @@ -246,7 +264,7 @@ QVariant Volta::propertyDefault(Pid propertyId) const case Pid::VOLTA_ENDING: return QVariant::fromValue(QList()); case Pid::ANCHOR: - return int(Anchor::MEASURE); + return int(VOLTA_ANCHOR); case Pid::BEGIN_HOOK_TYPE: return int(HookType::HOOK_90); case Pid::END_HOOK_TYPE: diff --git a/libmscore/volta.h b/libmscore/volta.h index 909c7cc5ca910..a943cc52f4a2d 100644 --- a/libmscore/volta.h +++ b/libmscore/volta.h @@ -47,6 +47,7 @@ class VoltaSegment final : public TextLineBaseSegment { class Volta final : public TextLineBase { QList _endings; + static constexpr Anchor VOLTA_ANCHOR = Anchor::MEASURE; public: enum class Type : char { @@ -60,6 +61,7 @@ class Volta final : public TextLineBase { virtual void write(XmlWriter&) const override; virtual void read(XmlReader& e) override; + bool readProperties(XmlReader&) override; virtual SpannerSegment* layoutSystem(System* system) override; void setVelocity() const; From 0f9c5e2d890c8f2831fbace4585246d4401c748c Mon Sep 17 00:00:00 2001 From: Howard-C Date: Sat, 15 Feb 2020 13:46:46 +0800 Subject: [PATCH 47/49] fix #301103: "Straight" text does not work + rename "SwingOff" to "swingOff" for consistency --- libmscore/staff.cpp | 3 +-- libmscore/stafftextbase.h | 2 +- mscore/editstyle.cpp | 6 +++--- mscore/editstyle.ui | 4 ++-- mscore/menus.cpp | 5 ++++- mscore/stafftext.ui | 4 ++-- mscore/stafftextproperties.cpp | 8 ++++---- 7 files changed, 17 insertions(+), 15 deletions(-) diff --git a/libmscore/staff.cpp b/libmscore/staff.cpp index 618511f182e8b..53dd2b6bfb834 100644 --- a/libmscore/staff.cpp +++ b/libmscore/staff.cpp @@ -863,9 +863,8 @@ SwingParameters Staff::swing(const Fraction& tick) const int swingUnit = 0; QString unit = score()->styleSt(Sid::swingUnit); int swingRatio = score()->styleI(Sid::swingRatio); - if (unit == TDuration(TDuration::DurationType::V_EIGHTH).name()) { + if (unit == TDuration(TDuration::DurationType::V_EIGHTH).name()) swingUnit = MScore::division / 2; - } else if (unit == TDuration(TDuration::DurationType::V_16TH).name()) swingUnit = MScore::division / 4; else if (unit == TDuration(TDuration::DurationType::V_ZERO).name()) diff --git a/libmscore/stafftextbase.h b/libmscore/stafftextbase.h index 51376c1d5b53e..1c2e47879072b 100644 --- a/libmscore/stafftextbase.h +++ b/libmscore/stafftextbase.h @@ -51,7 +51,7 @@ class StaffTextBase : public TextBase { Segment* segment() const; QString channelName(int voice) const { return _channelNames[voice]; } void setChannelName(int v, const QString& s) { _channelNames[v] = s; } - void setSwingParameters(int unit, int ratio) { _swingParameters.swingUnit = unit; _swingParameters.swingRatio = ratio; } + void setSwingParameters(int unit, int ratio) { _swingParameters.swingUnit = unit; _swingParameters.swingRatio = ratio; } const QList* channelActions() const { return &_channelActions; } QList* channelActions() { return &_channelActions; } const SwingParameters* swingParameters() const { return &_swingParameters; } diff --git a/mscore/editstyle.cpp b/mscore/editstyle.cpp index c3d7cc2609b23..7e23248300b23 100644 --- a/mscore/editstyle.cpp +++ b/mscore/editstyle.cpp @@ -493,7 +493,7 @@ EditStyle::EditStyle(Score* s, QWidget* parent) chordDescriptionFileButton->setIcon(*icons[int(Icons::fileOpen_ICON)]); - connect(SwingOff, SIGNAL(toggled(bool)), SLOT(setSwingParams(bool))); + connect(swingOff, SIGNAL(toggled(bool)), SLOT(setSwingParams(bool))); connect(swingEighth, SIGNAL(toggled(bool)), SLOT(setSwingParams(bool))); connect(swingSixteenth, SIGNAL(toggled(bool)), SLOT(setSwingParams(bool))); @@ -1063,7 +1063,7 @@ void EditStyle::setValues() swingBox->setEnabled(true); } else if (unit == TDuration(TDuration::DurationType::V_ZERO).name()) { - SwingOff->setChecked(true); + swingOff->setChecked(true); swingBox->setEnabled(false); } QString s(lstyle.value(Sid::chordDescriptionFile).toString()); @@ -1143,7 +1143,7 @@ void EditStyle::setSwingParams(bool checked) if (!checked) return; QVariant val; - if (SwingOff->isChecked()) { + if (swingOff->isChecked()) { val = TDuration(TDuration::DurationType::V_ZERO).name(); swingBox->setEnabled(false); } diff --git a/mscore/editstyle.ui b/mscore/editstyle.ui index 171d38e147dd2..26ee10f72b3a9 100644 --- a/mscore/editstyle.ui +++ b/mscore/editstyle.ui @@ -540,7 +540,7 @@
- + Off @@ -10547,7 +10547,7 @@ dontHideStavesInFirstSystem crossMeasureValues hideInstrumentNameIfOneInstrument - SwingOff + swingOff swingEighth swingSixteenth swingBox diff --git a/mscore/menus.cpp b/mscore/menus.cpp index e5aa5ca2f4ee5..16b901fe3bdf7 100644 --- a/mscore/menus.cpp +++ b/mscore/menus.cpp @@ -1595,7 +1595,10 @@ PalettePanel* MuseScore::newTextPalettePanel(bool defaultPalettePanel) stxt = new SystemText(gscore, Tid::TEMPO); /*: System text to switch from swing rhythm back to straight rhythm */ stxt->setXmlText(QT_TRANSLATE_NOOP("Palette", "Straight")); - stxt->setSwing(false); // redundant, being the default anyhow, but for documentation + // need to be true to enable the "Off" option + stxt->setSwing(true); + // 0 (swingUnit) turns of swing; swingRatio is set to default + stxt->setSwingParameters(0, stxt->score()->styleI(Sid::swingRatio)); /*: System text to switch from swing rhythm back to straight rhythm */ sp->append(stxt, QT_TRANSLATE_NOOP("Palette", "Straight"))->setElementTranslated(true); diff --git a/mscore/stafftext.ui b/mscore/stafftext.ui index 50a0d743ee5e0..9de7739389820 100644 --- a/mscore/stafftext.ui +++ b/mscore/stafftext.ui @@ -4077,7 +4077,7 @@ VI - + true @@ -4342,7 +4342,7 @@ VI stop_1_14 stop_1_15 setSwingBox - SwingOff + swingOff swingEighth swingSixteenth swingBox diff --git a/mscore/stafftextproperties.cpp b/mscore/stafftextproperties.cpp index 678046dc25023..fe0a3e3d7fc60 100644 --- a/mscore/stafftextproperties.cpp +++ b/mscore/stafftextproperties.cpp @@ -152,13 +152,13 @@ StaffTextProperties::StaffTextProperties(const StaffTextBase* st, QWidget* paren } else if (_staffText->swingParameters()->swingUnit == 0) { swingBox->setEnabled(false); - SwingOff->setChecked(true); + swingOff->setChecked(true); swingBox->setValue(_staffText->swingParameters()->swingRatio); } } connect(mapper, SIGNAL(mapped(int)), SLOT(voiceButtonClicked(int))); - connect(SwingOff, SIGNAL(toggled(bool)), SLOT(setSwingControls(bool))); + connect(swingOff, SIGNAL(toggled(bool)), SLOT(setSwingControls(bool))); connect(swingEighth, SIGNAL(toggled(bool)), SLOT(setSwingControls(bool))); connect(swingSixteenth, SIGNAL(toggled(bool)), SLOT(setSwingControls(bool))); @@ -291,7 +291,7 @@ void StaffTextProperties::setSwingControls(bool checked) { if (!checked) return; - if (SwingOff->isChecked()) + if (swingOff->isChecked()) swingBox->setEnabled(false); else if (swingEighth->isChecked()) swingBox->setEnabled(true); @@ -465,7 +465,7 @@ void StaffTextProperties::saveValues() } if (setSwingBox->isChecked()) { _staffText->setSwing(true); - if (SwingOff->isChecked()) { + if (swingOff->isChecked()) { _staffText->setSwingParameters(0, swingBox->value()); swingBox->setEnabled(false); } From 10bf8b56ee37651822d581d2c34448c0f18e9a1c Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Wed, 11 Mar 2020 15:26:49 +0200 Subject: [PATCH 48/49] Fix build after dd735c95c919041c318dd345a2b6b5a062d45792 --- libmscore/layout.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 8064ae6644938..fe631b8936b12 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -4371,8 +4371,7 @@ void Score::doLayoutRange(const Fraction& st, const Fraction& et) _systems.clear(); qDeleteAll(pages()); pages().clear(); - LayoutContext lc; - lc.score = this; + LayoutContext lc(this); lc.getNextPage(); return; } From dafff7c7c0949c6e1dfbaf131358cc7cddd18a38 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Wed, 11 Mar 2020 15:37:14 +0200 Subject: [PATCH 49/49] Correct a typo in Makefile from 0b37675892606ba3fc8960a9312f96893d929072 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 49a5f6426c1b0..b249ff7e1af26 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ release: -DTELEMETRY_TRACK_ID="${TELEMETRY_TRACK_ID}" \ -DBUILD_LAME="${BUILD_LAME}" \ -DBUILD_PULSEAUDIO="${BUILD_PULSEAUDIO}" \ - -DBUILD_PULSEMIDI="${DBUILD_PULSEMIDI}" \ + -DBUILD_PORTMIDI="${BUILD_PORTMIDI}" \ -DBUILD_JACK="${BUILD_JACK}" \ -BUILD_ALSA="${BUILD_ALSA}" \ -DBUILD_PORTAUDIO="${BUILD_PORTAUDIO}" \ @@ -93,7 +93,7 @@ debug: -DCMAKE_BUILD_NUMBER="${BUILD_NUMBER}" \ -DBUILD_LAME="${BUILD_LAME}" \ -DBUILD_PULSEAUDIO="${BUILD_PULSEAUDIO}" \ - -DBUILD_PULSEMIDI="${DBUILD_PULSEMIDI}" \ + -DBUILD_PORTMIDI="${BUILD_PORTMIDI}" \ -DBUILD_JACK="${BUILD_JACK}" \ -BUILD_ALSA="${BUILD_ALSA}" \ -DBUILD_PORTAUDIO="${BUILD_PORTAUDIO}" \