diff --git a/src/include/mx/api/ChordData.h b/src/include/mx/api/ChordData.h index cef16d76c..15c923acf 100644 --- a/src/include/mx/api/ChordData.h +++ b/src/include/mx/api/ChordData.h @@ -177,6 +177,8 @@ class FrameData int stringCount; int fretCount; + // What to display above a string without a frame note, such as "x" for a muted string. + std::optional unplayed; int firstFret; bool isFirstFretSpecified; std::vector notes; @@ -185,6 +187,7 @@ class FrameData MXAPI_EQUALS_BEGIN(FrameData) MXAPI_EQUALS_MEMBER(stringCount) MXAPI_EQUALS_MEMBER(fretCount) +MXAPI_EQUALS_MEMBER(unplayed) MXAPI_EQUALS_MEMBER(firstFret) MXAPI_EQUALS_MEMBER(isFirstFretSpecified) MXAPI_EQUALS_MEMBER(notes) diff --git a/src/private/mx/api/ChordData.cpp b/src/private/mx/api/ChordData.cpp index 442ef181f..e7bb91bea 100644 --- a/src/private/mx/api/ChordData.cpp +++ b/src/private/mx/api/ChordData.cpp @@ -24,7 +24,7 @@ FrameNoteData::FrameNoteData() { } -FrameData::FrameData() : stringCount{6}, fretCount{4}, firstFret{1}, isFirstFretSpecified{false}, notes{} +FrameData::FrameData() : stringCount{6}, fretCount{4}, unplayed{}, firstFret{1}, isFirstFretSpecified{false}, notes{} { } diff --git a/src/private/mx/impl/DirectionReader.cpp b/src/private/mx/impl/DirectionReader.cpp index 8399af94c..f12b1b40a 100644 --- a/src/private/mx/impl/DirectionReader.cpp +++ b/src/private/mx/impl/DirectionReader.cpp @@ -1428,6 +1428,10 @@ void DirectionReader::parseHarmony(const core::Harmony &inHarmony, const core::H const auto &frame = *inHarmony.frame(); chord.frameData.stringCount = frame.frameStrings(); chord.frameData.fretCount = frame.frameFrets(); + if (frame.unplayed().has_value()) + { + chord.frameData.unplayed = *frame.unplayed(); + } if (frame.firstFret().has_value()) { diff --git a/src/private/mx/impl/DirectionWriter.cpp b/src/private/mx/impl/DirectionWriter.cpp index a861a3bec..a0d148113 100644 --- a/src/private/mx/impl/DirectionWriter.cpp +++ b/src/private/mx/impl/DirectionWriter.cpp @@ -1699,6 +1699,10 @@ std::vector DirectionWriter::createHarmonyElements(int in core::Frame frame{}; frame.setFrameStrings(chordIter->frameData.stringCount); frame.setFrameFrets(chordIter->frameData.fretCount); + if (chordIter->frameData.unplayed.has_value()) + { + frame.setUnplayed(chordIter->frameData.unplayed); + } if (chordIter->frameData.isFirstFretSpecified) { diff --git a/src/private/mxtest/api/HarmonyExtrasApiTest.cpp b/src/private/mxtest/api/HarmonyExtrasApiTest.cpp index 0f8211768..cf36c0592 100644 --- a/src/private/mxtest/api/HarmonyExtrasApiTest.cpp +++ b/src/private/mxtest/api/HarmonyExtrasApiTest.cpp @@ -206,6 +206,25 @@ TEST(harmonyInversionRoundTrip, HarmonyExtrasApi) T_END; +TEST(harmonyFrameUnplayedRoundTrip, HarmonyExtrasApi) +{ + auto score = makeScoreWithChord(); + auto &chord = chordOf(score); + chord.root = Step::c; + chord.chordKind = ChordKind::major; + chord.hasFrameData = true; + chord.frameData.unplayed = "x"; + + const auto xml = mxtest::toXml(score); + CHECK(xml.find("unplayed=\"x\"") != std::string::npos); + + const auto out = mxtest::roundTrip(score); + CHECK(out.parts.front().measures.front().staves.front().directions.front().chords.front().frameData.unplayed == + std::optional{"x"}); +} + +T_END; + TEST(harmonyFunctionRoundTrip, HarmonyExtrasApi) { auto score = makeScoreWithChord();