diff --git a/src/include/mx/api/ApiCommon.h b/src/include/mx/api/ApiCommon.h index 3ff4433aa..6efabd4b0 100644 --- a/src/include/mx/api/ApiCommon.h +++ b/src/include/mx/api/ApiCommon.h @@ -32,6 +32,17 @@ constexpr int NUMBER_LEVEL_UNSPECIFIED = -1; // MusicXML 'number' attributes, e. constexpr int VALUE_UNSPECIFIED = -1; // other absent-able ints, e.g. DirectionData::voice constexpr Double DOUBLE_UNSPECIFIED = -1.0; // absent-able doubles, e.g. StaffData::staffSize +// MusicXML lets most elements carry an optional id attribute, a name that identifies that one +// element within the document. Software uses it to point at a particular note, measure, or +// marking -- to line playback up with the score, to hang an annotation on a note, or to link one +// file to another. Every mx::api type that models such an element has an `id` member. Leave it +// empty and no id attribute is written. +// +// An id must be unique within the document and must follow the XML name rules: a letter or an +// underscore first, then letters, digits, dots, hyphens, or underscores. mx repairs an id that +// breaks the name rules when it writes the file, but it does not check uniqueness, so an id you +// invent must not collide with one already in the score. + // Intentional ternary: absent-able bools use Bool::unspecified, not std::optional. // See "mx::api conventions" in AGENTS.md. enum class Bool diff --git a/src/include/mx/api/BarlineData.h b/src/include/mx/api/BarlineData.h index 967a5112b..05857f979 100644 --- a/src/include/mx/api/BarlineData.h +++ b/src/include/mx/api/BarlineData.h @@ -116,10 +116,13 @@ class BarlineData RepeatWinged repeatWinged; HorizontalAlignment location; + // The element's id attribute (see ApiCommon.h). + std::optional id; + BarlineData() : tickTimePosition{0}, barlineType{BarlineType::normal}, ending{}, repeat{false}, repeatTimes{0}, repeatDirection{RepeatDirection::unspecified}, repeatAfterJump{Bool::unspecified}, - repeatWinged{RepeatWinged::unspecified}, location{HorizontalAlignment::unspecified} + repeatWinged{RepeatWinged::unspecified}, location{HorizontalAlignment::unspecified}, id{} { } }; @@ -134,6 +137,7 @@ MXAPI_EQUALS_MEMBER(repeatDirection) MXAPI_EQUALS_MEMBER(repeatAfterJump) MXAPI_EQUALS_MEMBER(repeatWinged) MXAPI_EQUALS_MEMBER(location) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(BarlineData); } // namespace api diff --git a/src/include/mx/api/ClefData.h b/src/include/mx/api/ClefData.h index c4feba6cd..81a788a87 100644 --- a/src/include/mx/api/ClefData.h +++ b/src/include/mx/api/ClefData.h @@ -6,6 +6,9 @@ #include "mx/api/ApiCommon.h" +#include +#include + namespace mx { namespace api @@ -67,6 +70,10 @@ class ClefData // Visibility of the clef via the MusicXML print-object attribute. // unspecified -> omit the attribute, yes/no -> write print-object verbatim. Bool printObject; + + // The element's id attribute (see ApiCommon.h). + std::optional id; + std::string toString() const; // convenience - set symbol, line and octave for common clefs @@ -99,6 +106,7 @@ MXAPI_EQUALS_MEMBER(tickTimePosition) MXAPI_EQUALS_MEMBER(location) MXAPI_EQUALS_MEMBER(additional) MXAPI_EQUALS_MEMBER(printObject) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(ClefData); } // namespace api diff --git a/src/include/mx/api/CurveData.h b/src/include/mx/api/CurveData.h index 8b9670a9d..178919df6 100644 --- a/src/include/mx/api/CurveData.h +++ b/src/include/mx/api/CurveData.h @@ -10,6 +10,9 @@ #include "mx/api/PositionData.h" #include "mx/api/SpannerNumber.h" +#include +#include + // MusicXML Documentation for Bezier Attributes Group // The bezier attribute group is used to indicate the curvature of slurs // and ties, representing the control points for a cubic bezier curve. @@ -100,9 +103,13 @@ struct CurveStart bool isColorSpecified; ColorData colorData; + // The id attribute of the element this curve end is written as -- for a slur, + // for a tie (see ApiCommon.h). + std::optional id; + CurveStart(CurveType inCurveType) : curveType{inCurveType}, number{}, curvePoints{}, curveOrientation{CurveOrientation::unspecified}, - placement{Placement::unspecified}, lineData{}, isColorSpecified{false}, colorData{} + placement{Placement::unspecified}, lineData{}, isColorSpecified{false}, colorData{}, id{} { } }; @@ -119,9 +126,13 @@ struct CurveContinue bool isBezierOffset2Specified; double bezierOffset2; + // The id attribute of the element this curve end is written as -- for a slur, + // for a tie (see ApiCommon.h). + std::optional id; + CurveContinue(CurveType inCurveType) : curveType{inCurveType}, number{}, curvePoints{}, isBezierX2Specified{false}, bezierX2{0.0}, - isBezierY2Specified{false}, bezierY2{0.0}, isBezierOffset2Specified{false}, bezierOffset2{0.0} + isBezierY2Specified{false}, bezierY2{0.0}, isBezierOffset2Specified{false}, bezierOffset2{0.0}, id{} { } }; @@ -132,7 +143,11 @@ struct CurveStop SpannerNumber number; CurvePoints curvePoints; - CurveStop(CurveType inCurveType) : curveType{inCurveType}, number{}, curvePoints{} + // The id attribute of the element this curve end is written as -- for a slur, + // for a tie (see ApiCommon.h). + std::optional id; + + CurveStop(CurveType inCurveType) : curveType{inCurveType}, number{}, curvePoints{}, id{} { } }; @@ -157,6 +172,7 @@ MXAPI_EQUALS_MEMBER(placement) MXAPI_EQUALS_MEMBER(lineData) MXAPI_EQUALS_MEMBER(isColorSpecified) MXAPI_EQUALS_MEMBER(colorData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(CurveStart); @@ -170,6 +186,7 @@ MXAPI_EQUALS_MEMBER(isBezierY2Specified) MXAPI_EQUALS_MEMBER(bezierY2) MXAPI_EQUALS_MEMBER(isBezierOffset2Specified) MXAPI_EQUALS_MEMBER(bezierOffset2) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(CurveContinue); @@ -177,6 +194,7 @@ MXAPI_EQUALS_BEGIN(CurveStop) MXAPI_EQUALS_MEMBER(curveType) MXAPI_EQUALS_MEMBER(number) MXAPI_EQUALS_MEMBER(curvePoints) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(CurveStop); } // namespace api diff --git a/src/include/mx/api/DirectionData.h b/src/include/mx/api/DirectionData.h index a4f61fae6..6981d2200 100644 --- a/src/include/mx/api/DirectionData.h +++ b/src/include/mx/api/DirectionData.h @@ -11,6 +11,7 @@ #include "mx/api/SoundData.h" #include +#include namespace mx { @@ -80,10 +81,13 @@ struct DirectionData // serialize as their own elements, not as direction-type content. std::vector figuredBasses; + // The element's id attribute (see ApiCommon.h). + std::optional id; + DirectionData() : tickTimePosition{0}, placement{Placement::unspecified}, systemRelation{SystemRelation::unspecified}, offset{}, voice{VALUE_UNSPECIFIED}, isStaffValueSpecified{true}, isSoundDataSpecified{false}, soundData{}, - directionTypes{}, chords{}, figuredBasses{} + directionTypes{}, chords{}, figuredBasses{}, id{} { } }; @@ -106,6 +110,7 @@ MXAPI_EQUALS_MEMBER(soundData) MXAPI_EQUALS_MEMBER(directionTypes) MXAPI_EQUALS_MEMBER(chords) MXAPI_EQUALS_MEMBER(figuredBasses) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(DirectionData); } // namespace api diff --git a/src/include/mx/api/FiguredBassData.h b/src/include/mx/api/FiguredBassData.h index 26263fbdd..a4ff4d9eb 100644 --- a/src/include/mx/api/FiguredBassData.h +++ b/src/include/mx/api/FiguredBassData.h @@ -6,6 +6,7 @@ #include "mx/api/ApiCommon.h" +#include #include #include @@ -48,7 +49,10 @@ class FiguredBassData // The optional , in ticks. A value less than 0 means 'unspecified' (no duration child). int durationTimeTicks; - FiguredBassData() : figures{}, parentheses{Bool::unspecified}, durationTimeTicks{VALUE_UNSPECIFIED} + // The element's id attribute (see ApiCommon.h). + std::optional id; + + FiguredBassData() : figures{}, parentheses{Bool::unspecified}, durationTimeTicks{VALUE_UNSPECIFIED}, id{} { } }; @@ -57,6 +61,7 @@ MXAPI_EQUALS_BEGIN(FiguredBassData) MXAPI_EQUALS_MEMBER(figures) MXAPI_EQUALS_MEMBER(parentheses) MXAPI_EQUALS_MEMBER(durationTimeTicks) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(FiguredBassData); diff --git a/src/include/mx/api/KeyData.h b/src/include/mx/api/KeyData.h index f4551b371..ff4666ae0 100644 --- a/src/include/mx/api/KeyData.h +++ b/src/include/mx/api/KeyData.h @@ -6,6 +6,9 @@ #include "mx/api/ApiCommon.h" #include "mx/api/KeyComponent.h" +#include +#include + namespace mx { namespace api @@ -121,9 +124,12 @@ struct KeyData // alterations. When custom is non-empty, then fifths and mode are ignored. std::vector nonTraditional; + // The element's id attribute (see ApiCommon.h). + std::optional id; + KeyData() : fifths{0}, cancel{0}, cancelLocation{CancelLocation::unspecified}, mode{KeyMode::unspecified}, - tickTimePosition{0}, staffIndex{INDEX_UNSPECIFIED}, nonTraditional{} + tickTimePosition{0}, staffIndex{INDEX_UNSPECIFIED}, nonTraditional{}, id{} { } }; @@ -136,6 +142,7 @@ MXAPI_EQUALS_MEMBER(mode) MXAPI_EQUALS_MEMBER(tickTimePosition) MXAPI_EQUALS_MEMBER(staffIndex) MXAPI_EQUALS_MEMBER(nonTraditional) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(KeyData); diff --git a/src/include/mx/api/LyricData.h b/src/include/mx/api/LyricData.h index f88c6f216..e08993b94 100644 --- a/src/include/mx/api/LyricData.h +++ b/src/include/mx/api/LyricData.h @@ -8,6 +8,9 @@ #include "mx/api/PositionData.h" #include "mx/api/PrintData.h" +#include +#include + namespace mx { namespace api @@ -38,7 +41,7 @@ class LyricData public: LyricData() : text{}, verseNumber{}, verseName{}, syllabic{LyricSyllabic::unspecified}, hasExtend{false}, - extendType{LyricExtendType::unspecified}, positionData{}, printData{} + extendType{LyricExtendType::unspecified}, positionData{}, printData{}, id{} { } @@ -50,6 +53,9 @@ class LyricData LyricExtendType extendType; PositionData positionData; PrintData printData; + + // The element's id attribute (see ApiCommon.h). + std::optional id; }; MXAPI_EQUALS_BEGIN(LyricData) @@ -61,6 +67,7 @@ MXAPI_EQUALS_MEMBER(hasExtend) MXAPI_EQUALS_MEMBER(extendType) MXAPI_EQUALS_MEMBER(positionData) MXAPI_EQUALS_MEMBER(printData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(LyricData); } // namespace api diff --git a/src/include/mx/api/MeasureData.h b/src/include/mx/api/MeasureData.h index 8a6cde682..6968b6daa 100644 --- a/src/include/mx/api/MeasureData.h +++ b/src/include/mx/api/MeasureData.h @@ -111,6 +111,9 @@ class MeasureData // before this field existed. std::vector transpositions; + // The element's id attribute (see ApiCommon.h). + std::optional id; + MeasureData() : staves{}, timeSignature{}, number{}, measureNumbering{MeasureNumbering::unspecified}, measureNumberingMultipleRestAlways{Bool::unspecified}, measureNumberingMultipleRestRange{Bool::unspecified}, @@ -141,6 +144,7 @@ MXAPI_EQUALS_MEMBER(keys) MXAPI_EQUALS_MEMBER(barlines) MXAPI_EQUALS_MEMBER(partSymbol) MXAPI_EQUALS_MEMBER(transpositions) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(MeasureData); } // namespace api diff --git a/src/include/mx/api/NoteData.h b/src/include/mx/api/NoteData.h index 79129b482..d746d18b7 100644 --- a/src/include/mx/api/NoteData.h +++ b/src/include/mx/api/NoteData.h @@ -82,7 +82,11 @@ struct TieLetRing bool isColorSpecified; ColorData colorData; - TieLetRing() : positionData{}, curveOrientation{CurveOrientation::unspecified}, isColorSpecified{false}, colorData{} + // The element's id attribute (see ApiCommon.h). + std::optional id; + + TieLetRing() + : positionData{}, curveOrientation{CurveOrientation::unspecified}, isColorSpecified{false}, colorData{}, id{} { } }; @@ -92,6 +96,7 @@ MXAPI_EQUALS_MEMBER(positionData) MXAPI_EQUALS_MEMBER(curveOrientation) MXAPI_EQUALS_MEMBER(isColorSpecified) MXAPI_EQUALS_MEMBER(colorData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(TieLetRing); @@ -202,6 +207,9 @@ class NoteData // similarly when parsing if we see ##misc-data## in this element, it // will be parsed into these strings. do not use commas in your misc // data strings as these are the delimiter + + // The element's id attribute (see ApiCommon.h). + std::optional id; std::vector miscData; }; @@ -234,6 +242,7 @@ MXAPI_EQUALS_MEMBER(printData) MXAPI_EQUALS_MEMBER(noteAttachmentData) MXAPI_EQUALS_MEMBER(lyrics) MXAPI_EQUALS_MEMBER(miscData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(NoteData); } // namespace api diff --git a/src/include/mx/api/PedalLineData.h b/src/include/mx/api/PedalLineData.h index 53c5c6c64..8606bcfc9 100644 --- a/src/include/mx/api/PedalLineData.h +++ b/src/include/mx/api/PedalLineData.h @@ -7,6 +7,9 @@ #include "mx/api/ApiCommon.h" #include "mx/api/PositionData.h" +#include +#include + namespace mx { namespace api @@ -50,11 +53,14 @@ struct PedalLineData int tickTimePosition; PositionData positionData; - PedalLineData() : kind{PedalLineKind::unspecified}, tickTimePosition{0}, positionData{} + // The element's id attribute (see ApiCommon.h). + std::optional id; + + PedalLineData() : kind{PedalLineKind::unspecified}, tickTimePosition{0}, positionData{}, id{} { } - PedalLineData(PedalLineKind inKind) : kind{inKind}, tickTimePosition{0}, positionData{} + PedalLineData(PedalLineKind inKind) : kind{inKind}, tickTimePosition{0}, positionData{}, id{} { } }; @@ -63,6 +69,7 @@ MXAPI_EQUALS_BEGIN(PedalLineData) MXAPI_EQUALS_MEMBER(kind) MXAPI_EQUALS_MEMBER(tickTimePosition) MXAPI_EQUALS_MEMBER(positionData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(PedalLineData); } // namespace api diff --git a/src/include/mx/api/RehearsalData.h b/src/include/mx/api/RehearsalData.h index 73685bcfd..a34430155 100644 --- a/src/include/mx/api/RehearsalData.h +++ b/src/include/mx/api/RehearsalData.h @@ -9,6 +9,9 @@ #include "mx/api/FontData.h" #include "mx/api/PositionData.h" +#include +#include + namespace mx { namespace api @@ -32,9 +35,12 @@ class RehearsalData // and says which edge of the text the position refers to; MusicXML defines both. HorizontalAlignment justify; + // The element's id attribute (see ApiCommon.h). + std::optional id; + RehearsalData() : text{}, positionData{}, isColorSpecified{false}, colorData{}, fontData{}, enclosure{Enclosure::unspecified}, - justify{HorizontalAlignment::unspecified} + justify{HorizontalAlignment::unspecified}, id{} { } }; @@ -47,6 +53,7 @@ MXAPI_EQUALS_MEMBER(colorData) MXAPI_EQUALS_MEMBER(fontData) MXAPI_EQUALS_MEMBER(enclosure) MXAPI_EQUALS_MEMBER(justify) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(RehearsalData); } // namespace api diff --git a/src/include/mx/api/SoundData.h b/src/include/mx/api/SoundData.h index 010080e37..121a12999 100644 --- a/src/include/mx/api/SoundData.h +++ b/src/include/mx/api/SoundData.h @@ -87,10 +87,13 @@ struct SoundData std::optional swing; + // The element's id attribute (see ApiCommon.h). + std::optional id; + SoundData() : tempo{DOUBLE_UNSPECIFIED}, dynamics{DOUBLE_UNSPECIFIED}, dacapo{Bool::unspecified}, forwardRepeat{Bool::unspecified}, pizzicato{Bool::unspecified}, segno{}, dalsegno{}, coda{}, tocoda{}, fine{}, - swing{} + swing{}, id{} { } @@ -98,7 +101,7 @@ struct SoundData { return tempo >= 0.0 || dynamics >= 0.0 || dacapo != Bool::unspecified || forwardRepeat != Bool::unspecified || pizzicato != Bool::unspecified || !segno.empty() || !dalsegno.empty() || !coda.empty() || - !tocoda.empty() || !fine.empty() || swing.has_value(); + !tocoda.empty() || !fine.empty() || swing.has_value() || id.has_value(); } }; @@ -123,6 +126,7 @@ MXAPI_EQUALS_MEMBER(coda) MXAPI_EQUALS_MEMBER(tocoda) MXAPI_EQUALS_MEMBER(fine) MXAPI_EQUALS_MEMBER(swing) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(SoundData); } // namespace api diff --git a/src/include/mx/api/SpannerData.h b/src/include/mx/api/SpannerData.h index 51645990f..dd7c55d8a 100644 --- a/src/include/mx/api/SpannerData.h +++ b/src/include/mx/api/SpannerData.h @@ -10,6 +10,7 @@ #include "mx/api/PrintData.h" #include "mx/api/SpannerNumber.h" +#include #include namespace mx @@ -25,7 +26,11 @@ struct SpannerStart PrintData printData; LineData lineData; - SpannerStart() : number{}, tickTimePosition{0}, positionData{}, printData{}, lineData{} + // The id attribute of the element this spanner end is written as -- , + // , or (see ApiCommon.h). + std::optional id; + + SpannerStart() : number{}, tickTimePosition{0}, positionData{}, printData{}, lineData{}, id{} { } }; @@ -37,7 +42,11 @@ struct SpannerStop PositionData positionData; LineData lineData; - SpannerStop() : number{}, tickTimePosition{0}, positionData{}, lineData{} + // The id attribute of the element this spanner end is written as -- , + // , or (see ApiCommon.h). + std::optional id; + + SpannerStop() : number{}, tickTimePosition{0}, positionData{}, lineData{}, id{} { } }; @@ -48,6 +57,7 @@ MXAPI_EQUALS_MEMBER(tickTimePosition) MXAPI_EQUALS_MEMBER(positionData) MXAPI_EQUALS_MEMBER(printData) MXAPI_EQUALS_MEMBER(lineData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(SpannerStart); @@ -56,6 +66,7 @@ MXAPI_EQUALS_MEMBER(number) MXAPI_EQUALS_MEMBER(tickTimePosition) MXAPI_EQUALS_MEMBER(positionData) MXAPI_EQUALS_MEMBER(lineData) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(SpannerStop); } // namespace api diff --git a/src/include/mx/api/SymbolData.h b/src/include/mx/api/SymbolData.h index 8b6d88742..3b215534b 100644 --- a/src/include/mx/api/SymbolData.h +++ b/src/include/mx/api/SymbolData.h @@ -41,9 +41,12 @@ class SymbolData // symbol-formatting attributes mirror the text-formatting ones on ``. HorizontalAlignment justify; + // The element's id attribute (see ApiCommon.h). + std::optional id; + SymbolData() : smufl{}, positionData{}, fontData{}, color{}, enclosure{Enclosure::unspecified}, - justify{HorizontalAlignment::unspecified} + justify{HorizontalAlignment::unspecified}, id{} { } }; @@ -55,6 +58,7 @@ MXAPI_EQUALS_MEMBER(fontData) MXAPI_EQUALS_MEMBER(color) MXAPI_EQUALS_MEMBER(enclosure) MXAPI_EQUALS_MEMBER(justify) +MXAPI_EQUALS_MEMBER(id) MXAPI_EQUALS_END; MXAPI_NOT_EQUALS_AND_VECTORS(SymbolData); } // namespace api diff --git a/src/include/mx/api/TimeChoice.h b/src/include/mx/api/TimeChoice.h index a16a3fcb1..d26ba44e2 100644 --- a/src/include/mx/api/TimeChoice.h +++ b/src/include/mx/api/TimeChoice.h @@ -8,6 +8,8 @@ #include "mx/api/ComplexTimeSignature.h" #include "mx/api/TimeSignatureData.h" +#include +#include #include namespace mx @@ -57,6 +59,10 @@ class TimeChoice // Print/hide the time signature (