From d956517c16a5b1dfbd0ad9167ce0b39df920ad70 Mon Sep 17 00:00:00 2001 From: heavy-matill Date: Sun, 9 Feb 2025 21:55:54 +0100 Subject: [PATCH 1/8] Added RehearsalMark to MIDI export as Markers Implemented in the same RepeatSegment loop as lyrics. --- .../midi/internal/midiexport/exportmidi.cpp | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/importexport/midi/internal/midiexport/exportmidi.cpp b/src/importexport/midi/internal/midiexport/exportmidi.cpp index 37f794b18e3d0..4cbb09b931cc1 100644 --- a/src/importexport/midi/internal/midiexport/exportmidi.cpp +++ b/src/importexport/midi/internal/midiexport/exportmidi.cpp @@ -27,6 +27,7 @@ #include "engraving/dom/masterscore.h" #include "engraving/dom/note.h" #include "engraving/dom/part.h" +#include "engraving/dom/rehearsalmark.h" #include "engraving/dom/repeatlist.h" #include "engraving/dom/sig.h" #include "engraving/dom/staff.h" @@ -372,12 +373,13 @@ bool ExportMidi::write(QIODevice* device, bool midiExpandRepeats, bool exportRPN } } - // Export lyrics + // Export lyrics and RehearsalMarks as Meta events for (const RepeatSegment* rs : m_score->repeatList()) { int startTick = rs->tick; int endTick = startTick + rs->len(); int tickOffset = rs->utick - rs->tick; + // export Lyrics SegmentType st = SegmentType::ChordRest; for (Segment* seg = rs->firstMeasure()->first(st); seg && seg->tick().ticks() < endTick; seg = seg->next1(st)) { for (track_idx_t i = part->startTrack(); i < part->endTrack(); ++i) { @@ -402,6 +404,33 @@ bool ExportMidi::write(QIODevice* device, bool midiExpandRepeats, bool exportRPN } } } + + // export RehearsalMarks only for first track + if (staffIdx == 0) { + for (Segment* seg = rs->firstMeasure()->first(Segment::CHORD_REST_OR_TIME_TICK_TYPE); + seg && seg->tick().ticks() < endTick; + seg = seg->next1(Segment::CHORD_REST_OR_TIME_TICK_TYPE)) { + for (EngravingItem* e : seg->annotations()) { + if (e->isRehearsalMark()) { + RehearsalMark* r = toRehearsalMark(e); + muse::ByteArray rText = r->plainText().toUtf8(); + size_t len = rText.size() + 1; + unsigned char* data = new unsigned char[len]; + + memcpy(data, rText.constData(), len); + + MidiEvent ev; + ev.setType(ME_META); + ev.setMetaType(META_MARKER); + ev.setEData(data); + ev.setLen(static_cast(len)); + + int tick = r->segment()->tick().ticks() + tickOffset; + track.insert(CompatMidiRender::tick(context, tick), ev); + } + } + } + } } ++staffIdx; } From 39b70e68944464cced51c295bc489bdaf2127be7 Mon Sep 17 00:00:00 2001 From: Alexander Pavlov Date: Thu, 27 Feb 2025 00:26:24 +0200 Subject: [PATCH 2/8] skipping passed property while on reading mscz version 2 --- src/engraving/rw/read206/read206.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engraving/rw/read206/read206.cpp b/src/engraving/rw/read206/read206.cpp index 44448e69dc881..8f09bd03fce72 100644 --- a/src/engraving/rw/read206/read206.cpp +++ b/src/engraving/rw/read206/read206.cpp @@ -347,6 +347,10 @@ void Read206::readTextStyle206(MStyle* style, XmlReader& e, ReadContext& ctx, st ts = textStyle(ss); } for (const auto& i : *ts) { + if (ctx.shouldSkipProperty(i.pid)) { + continue; + } + PropertyValue value; if (i.sid == Sid::NOSTYLE) { break; From 2159e135c14fc6a537f5950a695333f272f1a1bd Mon Sep 17 00:00:00 2001 From: Dylan Nicholson Date: Sat, 14 Sep 2024 08:51:12 +1000 Subject: [PATCH 3/8] fix #24704: ensure xml parse can cope with comments after empy notes --- .../global/serialization/xmlstreamreader.cpp | 10 +++--- .../musicxml/import/importmusicxmlpass1.cpp | 3 ++ .../musicxml/import/importmusicxmlpass2.cpp | 36 +++++++++---------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/framework/global/serialization/xmlstreamreader.cpp b/src/framework/global/serialization/xmlstreamreader.cpp index 61cbbd5941cb0..bb7fb55a51509 100644 --- a/src/framework/global/serialization/xmlstreamreader.cpp +++ b/src/framework/global/serialization/xmlstreamreader.cpp @@ -157,7 +157,7 @@ static std::pair resolveNode(XMLNode* curr } XMLNode* sibling = currentNode->NextSibling(); - if (!sibling || sibling->ToElement() || sibling->ToText()) { + if (!sibling || sibling->ToElement() || sibling->ToText() || sibling->ToComment()) { return { currentNode, XmlStreamReader::TokenType::EndElement }; } } @@ -474,11 +474,11 @@ double XmlStreamReader::readDouble(bool* ok) int64_t XmlStreamReader::lineNumber() const { - if (!m_xml->doc.Error() && m_xml->node) { - return m_xml->node->GetLineNum(); + int64_t lineNum = m_xml->doc.ErrorLineNum(); + if (lineNum == 0 && m_xml->node) { + lineNum = m_xml->node->GetLineNum(); } - - return m_xml->doc.ErrorLineNum(); + return lineNum; } int64_t XmlStreamReader::columnNumber() const diff --git a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass1.cpp b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass1.cpp index f4c7968850f9c..2f5f4693d73c2 100644 --- a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass1.cpp +++ b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass1.cpp @@ -1286,6 +1286,9 @@ Err MusicXmlParserPass1::parse() if (!found) { m_logger->logError(u"this is not a MusicXML score-partwise file, node not found", &m_e); + if (!m_e.errorString().isEmpty()) { + m_errors += errorStringWithLocation(m_e.lineNumber(), m_e.columnNumber(), m_e.errorString()) + '\n'; + } return Err::FileBadFormat; } diff --git a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp index ca2d5e326bfc4..bfc8330da2776 100644 --- a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp @@ -3062,7 +3062,7 @@ void MusicXmlParserPass2::staffDetails(const String& partId, Measure* measure) staff_idx_t staffIdx = m_score->staffIdx(part) + n; - StringData* t = new StringData; + StringData stringData; String visible = m_e.attribute("print-object"); String spacing = m_e.attribute("print-spacing"); if (visible == "no") { @@ -3096,15 +3096,13 @@ void MusicXmlParserPass2::staffDetails(const String& partId, Measure* measure) // save staff lines for later staffLines = m_e.readInt(); // for a TAB staff also resize the string table and init with zeroes - if (t) { - if (0 < staffLines) { - t->stringList() = std::vector(staffLines); - } else { - m_logger->logError(String(u"illegal staff-lines %1").arg(staffLines), &m_e); - } + if (0 < staffLines) { + stringData.stringList() = std::vector(staffLines); + } else { + m_logger->logError(String(u"illegal staff-lines %1").arg(staffLines), &m_e); } } else if (m_e.name() == "staff-tuning") { - staffTuning(t); + staffTuning(&stringData); } else if (m_e.name() == "staff-size") { const double val = m_e.readDouble() / 100; m_score->staff(staffIdx)->setProperty(Pid::MAG, val); @@ -3117,20 +3115,18 @@ void MusicXmlParserPass2::staffDetails(const String& partId, Measure* measure) setStaffLines(m_score, staffIdx, staffLines); } - if (t) { - Instrument* i = part->instrument(); - if (m_score->staff(staffIdx)->isTabStaff(Fraction(0, 1))) { - if (i->stringData()->frets() == 0) { - t->setFrets(25); - } else { - t->setFrets(i->stringData()->frets()); - } - } - if (t->strings() > 0) { - i->setStringData(*t); + Instrument* i = part->instrument(); + if (m_score->staff(staffIdx)->isTabStaff(Fraction(0, 1))) { + if (i->stringData()->frets() == 0) { + stringData.setFrets(25); } else { - m_logger->logError(u"trying to change string data (not supported)", &m_e); + stringData.setFrets(i->stringData()->frets()); + } + if (stringData.strings() > 0) { + i->setStringData(stringData); } + } else if (stringData.strings() > 0) { + m_logger->logError(u"trying to change string data for non-TAB staff (not supported)", &m_e); } } From c26cebb4b4fb1805c69a4c38e2f9300fe46d341d Mon Sep 17 00:00:00 2001 From: Leon Vinken Date: Sun, 24 Nov 2024 20:51:08 +0100 Subject: [PATCH 4/8] fix issue 25617: prevent crash importing MusicXML file containing grace rest followed by tuple starting with rest --- .../internal/musicxml/import/importmusicxmlpass2.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp index bfc8330da2776..1d578ea46ea9e 100644 --- a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp @@ -6875,9 +6875,13 @@ Note* MusicXmlParserPass2::note(const String& partId, isSingleDrumset = instrument->drumset() && instruments.size() == 1; // begin allocation if (rest) { - const int track = msTrack + msVoice; - cr = addRest(m_score, measure, noteStartTime, track, msMove, - duration, dura); + if (!grace) { + const int track = msTrack + msVoice; + cr = addRest(m_score, measure, noteStartTime, track, msMove, + duration, dura); + } else { + LOGD("ignoring grace rest"); + } } else { if (!grace) { // regular note From 47195bd38b41c38b54e373d17bedd931a19a36c4 Mon Sep 17 00:00:00 2001 From: Ash-86 <108089527+Ash-86@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:18:55 -0300 Subject: [PATCH 5/8] fix plugin categories submenues Allow submenues of plugin categories that are not built in. --- src/appshell/view/appmenumodel.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/appshell/view/appmenumodel.cpp b/src/appshell/view/appmenumodel.cpp index b8ab70ebd2383..dec79092ea7f6 100644 --- a/src/appshell/view/appmenumodel.cpp +++ b/src/appshell/view/appmenumodel.cpp @@ -772,7 +772,10 @@ MenuItemList AppMenuModel::makePluginsItems() MenuItemList pluginsWithoutCategories; for (const Manifest& m : enabledExtensions) { std::string categoryStr = m.category.toStdString(); - if (muse::contains(categories, categoryStr)) { + if (!categoryStr.empty()) { + if (!muse::contains(categories, categoryStr)) { + categories[categoryStr] = TranslatableString("extensions", m.category); + } MenuItemList& items = categoriesMap[categoryStr]; addMenuItems(items, m); } else { From f89d407b4ef7714ddf22eeb92e5b2842005237a2 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Fri, 27 Dec 2024 02:56:29 +0100 Subject: [PATCH 6/8] add positioning attributes to breath marks and fingering --- .../musicxml/internal/musicxml/export/exportmusicxml.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp b/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp index 406036abe863b..791929e6985fd 100644 --- a/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp +++ b/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp @@ -3488,6 +3488,7 @@ static void writeBreathMark(const Breath* const breath, XmlWriter& xml, Notation } } tagName += color2xml(breath); + tagName += ExportMusicXml::positioningAttributes(breath); if (breath->placement() == PlacementV::BELOW) { tagName += u" placement=\"below\""; } else if (ExportMusicXml::configuration()->exportMu3Compat()) { @@ -4086,6 +4087,7 @@ static void writeFingering(XmlWriter& xml, Notations& notations, Technical& tech attr += fontStyleToXML(static_cast(f->getProperty(Pid::FONT_STYLE).toInt()), false); } attr += color2xml(f); + attr += ExportMusicXml::positioningAttributes(f); if (f->textStyleType() == TextStyleType::RH_GUITAR_FINGERING) { xml.tagRaw(u"pluck" + attr, t); From c3d1b6b3a0574bd9e8197154e2b94aae701bc46d Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Mon, 24 Feb 2025 21:44:47 +0100 Subject: [PATCH 7/8] add positioning attributes to articulations --- .../musicxml/internal/musicxml/export/exportmusicxml.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp b/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp index 791929e6985fd..a9b5af2cc0002 100644 --- a/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp +++ b/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp @@ -3549,6 +3549,7 @@ void ExportMusicXml::chordAttributes(Chord* chord, Notations& notations, Technic } } mxmlArtic += color2xml(a); + mxmlArtic += ExportMusicXml::positioningAttributes(a); notations.tag(m_xml, a); articulations.tag(m_xml); From d3405324a3d5c5620a332b064bcc72c583d3c961 Mon Sep 17 00:00:00 2001 From: Klaus Rettinghaus Date: Mon, 4 Nov 2024 19:33:59 +0100 Subject: [PATCH 8/8] revert exchange of staccatissimo and spiccato --- .../musicxml/internal/musicxml/export/exportmusicxml.cpp | 4 ++-- .../musicxml/internal/musicxml/import/importmusicxmlpass2.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp b/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp index a9b5af2cc0002..645d3b121749a 100644 --- a/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp +++ b/src/importexport/musicxml/internal/musicxml/export/exportmusicxml.cpp @@ -3112,6 +3112,8 @@ static std::vector symIdToArtic(const SymId sid) return { u"staccato" }; break; + case SymId::articStaccatissimoAbove: + case SymId::articStaccatissimoBelow: case SymId::articStaccatissimoWedgeAbove: case SymId::articStaccatissimoWedgeBelow: return { u"staccatissimo" }; @@ -3182,8 +3184,6 @@ static std::vector symIdToArtic(const SymId sid) return { u"tenuto", u"accent" }; break; - case SymId::articStaccatissimoAbove: - case SymId::articStaccatissimoBelow: case SymId::articStaccatissimoStrokeAbove: case SymId::articStaccatissimoStrokeBelow: return { u"spiccato" }; diff --git a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp index 1d578ea46ea9e..7986df697ffcf 100644 --- a/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/musicxml/import/importmusicxmlpass2.cpp @@ -1394,8 +1394,8 @@ static bool convertArticulationToSymId(const String& mxmlName, SymId& id) { u"staccato", SymId::articStaccatoAbove }, { u"tenuto", SymId::articTenutoAbove }, { u"detached-legato", SymId::articTenutoStaccatoAbove }, - { u"staccatissimo", SymId::articStaccatissimoWedgeAbove }, - { u"spiccato", SymId::articStaccatissimoAbove }, + { u"staccatissimo", SymId::articStaccatissimoAbove }, + { u"spiccato", SymId::articStaccatissimoStrokeAbove }, { u"stress", SymId::articStressAbove }, { u"unstress", SymId::articUnstressAbove }, { u"soft-accent", SymId::articSoftAccentAbove },