Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/include/mx/api/ClefData.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class ClefData
// int staffIndex;
ClefSymbol symbol;
int line;
// When true (the default), the writer emits <line>. Set to false when the source
// had no <line> element so the round-trip does not inject an implied default (#228).
bool isLineSpecified;
int octaveChange;
int tickTimePosition;
ClefLocation location;
Expand Down Expand Up @@ -69,6 +72,7 @@ MXAPI_EQUALS_BEGIN(ClefData)
// MXAPI_EQUALS_MEMBER( staffIndex )
MXAPI_EQUALS_MEMBER(symbol)
MXAPI_EQUALS_MEMBER(line)
MXAPI_EQUALS_MEMBER(isLineSpecified)
MXAPI_EQUALS_MEMBER(octaveChange)
MXAPI_EQUALS_MEMBER(tickTimePosition)
MXAPI_EQUALS_MEMBER(location)
Expand Down
10 changes: 8 additions & 2 deletions src/include/mx/api/DurationData.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,13 @@ struct DurationData
DurationData();

DurationName durationName; // i.e. quarter, eighth etc
int durationDots; // dots
int durationTimeTicks; // length of the note denominated in ticksPerQuarter
// When true (the default), the writer emits <type>. Set to false when the source
// had no <type> element so the round-trip does not inject an implied default (#228).
// When authoring, leave true and set durationName to control the display type;
// durationName and durationTimeTicks are independent (type is graphical, duration is sound).
bool isDurationNameSpecified;
int durationDots; // dots
int durationTimeTicks; // length of the note denominated in ticksPerQuarter
bool isTied; // affects sound only. is the note combined sound-wise with the following note of the same pitch
int timeModificationActualNotes; // i.e. for a triplet this would be 3
int timeModificationNormalNotes; // i.e. for a triplet this would be 2
Expand All @@ -78,6 +83,7 @@ struct DurationData

MXAPI_EQUALS_BEGIN(DurationData)
MXAPI_EQUALS_MEMBER(durationName)
MXAPI_EQUALS_MEMBER(isDurationNameSpecified)
MXAPI_EQUALS_MEMBER(durationDots)
MXAPI_EQUALS_MEMBER(durationTimeTicks)
MXAPI_EQUALS_MEMBER(isTied)
Expand Down
4 changes: 2 additions & 2 deletions src/private/mx/api/ClefData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ namespace mx
namespace api
{
ClefData::ClefData()
: symbol{DEFAULT_CLEF_SYMBOL}, line{DEFAULT_CLEF_LINE}, octaveChange{DEFAULT_CLEF_OCTAVE_CHANGE},
tickTimePosition{0}, location{ClefLocation::unspecified}
: symbol{DEFAULT_CLEF_SYMBOL}, line{DEFAULT_CLEF_LINE}, isLineSpecified{true},
octaveChange{DEFAULT_CLEF_OCTAVE_CHANGE}, tickTimePosition{0}, location{ClefLocation::unspecified}
{
}

Expand Down
4 changes: 2 additions & 2 deletions src/private/mx/api/DurationData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace mx
namespace api
{
DurationData::DurationData()
: durationName{DurationName::unspecified}, durationDots{0}, durationTimeTicks{1}, isTied{false},
timeModificationActualNotes{1}, timeModificationNormalNotes{1},
: durationName{DurationName::unspecified}, isDurationNameSpecified{true}, durationDots{0}, durationTimeTicks{1},
isTied{false}, timeModificationActualNotes{1}, timeModificationNormalNotes{1},
timeModificationNormalType{api::DurationName::unspecified}, timeModificationNormalTypeDots{0}
{
}
Expand Down
2 changes: 2 additions & 0 deletions src/private/mx/impl/MeasureReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,9 +759,11 @@ void MeasureReader::importClef(const core::Clef &inClef) const
if (inClef.clef().line().has_value())
{
clefData.line = inClef.clef().line()->value();
clefData.isLineSpecified = true;
}
else
{
clefData.isLineSpecified = false;
switch (clefData.symbol)
{
case api::ClefSymbol::g:
Expand Down
11 changes: 8 additions & 3 deletions src/private/mx/impl/MeasureWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ void MeasureWriter::writeStaves()

void MeasureWriter::writeVoices(const api::StaffData &inStaff)
{
const int numVoices = static_cast<int>(inStaff.voices.size());
auto clefIter = inStaff.clefs.cbegin();
const auto clefEnd = inStaff.clefs.cend();
while (clefIter != clefEnd && clefIter->tickTimePosition == 0)
Expand Down Expand Up @@ -451,9 +452,13 @@ void MeasureWriter::writeVoices(const api::StaffData &inStaff)
myPropertiesWriter->flushBuffer();
writeDirections(directionIter, directionEnd, noteIter, std::cbegin(voice.second.notes), noteEnd);

NoteWriter writer{
apiNote, myHistory.getCursor(), myScoreWriter, myPreviousCursor.isChordActive, voice.second.notes,
noteIndex};
NoteWriter writer{apiNote,
myHistory.getCursor(),
myScoreWriter,
myPreviousCursor.isChordActive,
voice.second.notes,
noteIndex,
numVoices};
myOutMeasure.addMusicData(core::MusicDataChoice::note(writer.getNote(isStartOfChord)));
myHistory.log("addNote cursorTime " + std::to_string(myHistory.getCursor().tickTimePosition) +
", noteTime " + std::to_string(apiNote.tickTimePosition));
Expand Down
2 changes: 2 additions & 0 deletions src/private/mx/impl/NoteFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ api::NoteData NoteFunctions::parseNote() const
if (reader.getIsDurationTypeSpecified())
{
myOutNoteData.durationData.durationName = converter.convert(reader.getDurationType());
myOutNoteData.durationData.isDurationNameSpecified = true;
}
else
{
myOutNoteData.durationData.durationName = deriveNoteTypeFromDurationValue(reader);
myOutNoteData.durationData.isDurationNameSpecified = false;
}

myOutNoteData.durationData.durationDots = reader.getNumDots();
Expand Down
14 changes: 9 additions & 5 deletions src/private/mx/impl/NoteWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ namespace impl
{
NoteWriter::NoteWriter(const api::NoteData &inNoteData, const MeasureCursor &inCursor, const ScoreWriter &inScoreWriter,
bool isPreviousNoteAChordMember, const std::vector<mx::api::NoteData> &inSiblingNotes,
int inNoteIndex)
int inNoteIndex, int inNumVoices)
: myNoteData{inNoteData}, myCursor{inCursor}, myScoreWriter{inScoreWriter}, myConverter{},
myIsPreviousNoteAChordMember{isPreviousNoteAChordMember}, mySiblingNotes{inSiblingNotes},
myNoteIndex{inNoteIndex}, myOutNote{}, myOutFullNoteGroup{}, myOutTies{}, myOutTieNotationsChoices{}
myNoteIndex{inNoteIndex}, myNumVoices{inNumVoices}, myOutNote{}, myOutFullNoteGroup{}, myOutTies{},
myOutTieNotationsChoices{}
{
}

Expand Down Expand Up @@ -375,18 +376,21 @@ void NoteWriter::setStaffAndVoice() const
myOutNote.setStaff(myCursor.staffIndex + 1);
}

if (myCursor.voiceIndex >= 0)
const bool sourceHadVoice = myNoteData.userRequestedVoiceNumber != -1;
const bool isNonDefaultVoice = myCursor.voiceIndex > 0;
const bool isMultiVoiceStaff = myNumVoices > 1;
if (myCursor.voiceIndex >= 0 && (sourceHadVoice || isNonDefaultVoice || isMultiVoiceStaff))
{
auto editorialVoice = myOutNote.editorialVoice();
editorialVoice.setVoice(std::to_string(myCursor.voiceIndex + 1));
myOutNote.setEditorialVoice(std::move(editorialVoice));
}
// TODO - only show voice number if it is needed i.e. only show if != 0 or voiceCount > 1
}

void NoteWriter::setDurationNameAndDots() const
{
if (!myNoteData.isRest || !myNoteData.isMeasureRest)
const bool isMeasureRest = myNoteData.isRest && myNoteData.isMeasureRest;
if (myNoteData.durationData.isDurationNameSpecified && !isMeasureRest)
{
core::NoteType noteType;
noteType.setValue(myConverter.convert(myNoteData.durationData.durationName));
Expand Down
4 changes: 3 additions & 1 deletion src/private/mx/impl/NoteWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class NoteWriter
{
public:
NoteWriter(const api::NoteData &inNoteData, const MeasureCursor &inCursor, const ScoreWriter &inScoreWriter,
bool isPreviousNoteAChordMember, const std::vector<mx::api::NoteData> &inSiblingNotes, int inNoteIndex);
bool isPreviousNoteAChordMember, const std::vector<mx::api::NoteData> &inSiblingNotes, int inNoteIndex,
int inNumVoices);

core::Note getNote(bool isStartOfChord) const;

Expand All @@ -36,6 +37,7 @@ class NoteWriter
const bool myIsPreviousNoteAChordMember;
const std::vector<mx::api::NoteData> &mySiblingNotes;
const int myNoteIndex;
const int myNumVoices;
mutable core::Note myOutNote;
mutable core::FullNoteGroup myOutFullNoteGroup;
mutable std::vector<core::Tie> myOutTies;
Expand Down
2 changes: 1 addition & 1 deletion src/private/mx/impl/PropertiesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ void PropertiesWriter::writeClef(int staffIndex, const api::ClefData &inClefData
core::ClefGroup cg{};
cg.setSign(converter.convert(inClefData.symbol));

if (inClefData.line >= 0)
if (inClefData.isLineSpecified)
{
cg.setLine(core::StaffLinePosition{inClefData.line});
}
Expand Down
20 changes: 20 additions & 0 deletions src/private/mxtest/api/roundtrip-baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,23 @@ synthetic/segno.3.0.xml
synthetic/segno.3.1.xml
synthetic/coda.3.0.xml
synthetic/coda.3.1.xml

# Unblocked by #228: the writer no longer injects a spurious <type> element for
# notes whose source omitted it. DurationData::isDurationNameSpecified tracks
# presence; the writer emits <type> only when the flag is set.
lysuite/ly41d_StaffGroups_Nested.xml
lysuite/ly41f_StaffGroups_Overlapping.xml
lysuite/ly45d_Repeats_Nested_Alternatives.xml
lysuite/ly45e_Repeats_Nested_Alternatives.xml

# Unblocked by #228 (add:line): the writer no longer injects a spurious <line>
# element in <clef> when the source omitted it. ClefData::isLineSpecified tracks
# presence; PropertiesWriter emits <line> only when the flag is set.
lysuite/ly12a_Clefs.xml

# Unblocked by #228 (add:voice): the writer no longer injects a spurious <voice>
# element for notes whose source omitted it. NoteData::userRequestedVoiceNumber
# (already -1 when absent) gates NoteWriter::setStaffAndVoice() voice emission.
mjbsuite/ChordDirectionPlacement.xml
mjbsuite/hello_timewise.xml
synthetic/key-accidental.3.0.xml
Loading