From f1a39750a45cca36f78b6cede1a1c37e6b7f7d21 Mon Sep 17 00:00:00 2001 From: Matthew James Briggs Date: Mon, 6 Jul 2026 05:58:38 +0000 Subject: [PATCH] feat(api): time signature staff-scoping and composite meter support Splits the time-signature half out of the original combined time-signature and transposition PR so each can be reviewed and merged independently. Closes #268 --- src/include/mx/api/MeasureData.h | 10 +- src/include/mx/api/TimeSignatureData.h | 50 +++++-- src/private/mx/examples/Write.cpp | 5 +- src/private/mx/impl/Cursor.cpp | 2 +- src/private/mx/impl/Cursor.h | 2 +- src/private/mx/impl/MeasureReader.cpp | 78 ++++++++-- src/private/mx/impl/MeasureWriter.cpp | 7 +- src/private/mx/impl/PartReader.cpp | 2 +- src/private/mx/impl/PropertiesWriter.cpp | 24 ++- src/private/mx/impl/PropertiesWriter.h | 2 +- src/private/mx/impl/TimeReader.cpp | 87 +++++++---- src/private/mx/impl/TimeReader.h | 22 ++- src/private/mxtest/api/ApiK007aScoreData.h | 4 +- src/private/mxtest/api/ApiK007cScoreData.h | 4 +- .../mxtest/api/ApiK009bSlurScoreData.h | 6 +- .../mxtest/api/ApiK014aFermatasScoreData.h | 6 +- .../mxtest/api/ApiK015aLayoutScoreData.h | 6 +- src/private/mxtest/api/ApiLy43eScoreData.h | 20 +-- .../mxtest/api/ApiMuAccidentals1ScoreData.h | 12 +- src/private/mxtest/api/ChordApiTest.cpp | 4 +- .../mxtest/api/TimeSignatureApiTest.cpp | 141 +++++++++++++++++- src/private/mxtest/file/MxFileRepositoy.cpp | 1 + 22 files changed, 391 insertions(+), 104 deletions(-) diff --git a/src/include/mx/api/MeasureData.h b/src/include/mx/api/MeasureData.h index 659796157..a4f72d9b0 100644 --- a/src/include/mx/api/MeasureData.h +++ b/src/include/mx/api/MeasureData.h @@ -31,7 +31,11 @@ class MeasureData // this is the notes and other music data std::vector staves; - TimeSignatureData timeSignature; + // resolved, carried-forward time signature(s) in effect for this measure. Normally a single + // entry with staffIndex == INDEX_UNSPECIFIED (applies to all staves). When staff-scoped time + // signatures are used, there is one entry per staff. Mirrors the isImplicit carry-forward + // semantics of the old singular field. + std::vector timeSignatures; // an empty measureNumber indicates a normal // measure number (i.e. the measure's @@ -100,7 +104,7 @@ class MeasureData std::vector transpositions; MeasureData() - : staves{}, timeSignature{}, number{}, measureNumbering{MeasureNumbering::unspecified}, + : staves{}, timeSignatures{TimeSignatureData{}}, number{}, measureNumbering{MeasureNumbering::unspecified}, multiMeasureRest{VALUE_UNSPECIFIED}, implicit{Bool::unspecified}, nonControlling{Bool::unspecified}, width{DOUBLE_UNSPECIFIED} { @@ -109,7 +113,7 @@ class MeasureData MXAPI_EQUALS_BEGIN(MeasureData) MXAPI_EQUALS_MEMBER(staves) -MXAPI_EQUALS_MEMBER(timeSignature) +MXAPI_EQUALS_MEMBER(timeSignatures) MXAPI_EQUALS_MEMBER(number) MXAPI_EQUALS_MEMBER(measureNumbering) MXAPI_EQUALS_MEMBER(multiMeasureRest) diff --git a/src/include/mx/api/TimeSignatureData.h b/src/include/mx/api/TimeSignatureData.h index a6829808f..c4b915b08 100644 --- a/src/include/mx/api/TimeSignatureData.h +++ b/src/include/mx/api/TimeSignatureData.h @@ -7,6 +7,7 @@ #include "mx/api/ApiCommon.h" #include +#include namespace mx { @@ -20,17 +21,35 @@ enum class TimeSignatureSymbol singleNumber }; -class TimeSignatureData +// TimeSignatureComponent represents a single beats/beat-type pair. Most time signatures have +// exactly one component (e.g. "4/4"). Composite time signatures (e.g. "3+2/8" notated with +// multiple