Skip to content

[From MU3 Backend] ENG-17: Fix beams in multi-voice MusicXML import #9502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
27 changes: 18 additions & 9 deletions src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1789,7 +1789,7 @@ static void removeBeam(Beam*& beam)
beam->elements().at(i)->setBeamMode(Beam::Mode::NONE);
}
delete beam;
beam = 0;
beam = nullptr;
}

//---------------------------------------------------------
Expand All @@ -1815,9 +1815,10 @@ static void handleBeamAndStemDir(ChordRest* cr, const Beam::Mode bm, const Direc
}
// add ChordRest to beam
if (beam) {
// verify still in the same track (switching voices in the middle of a beam is not supported)
// verify still in the same track (if still in the same voice)
// and in a beam ...
// (note no check is done on correct order of beam begin/continue/end)
// TODO: Some BEGINs are being skipped
if (cr->track() != beam->track()) {
qDebug("handleBeamAndStemDir() from track %d to track %d -> abort beam",
beam->track(), cr->track());
Expand Down Expand Up @@ -1851,7 +1852,7 @@ static void handleBeamAndStemDir(ChordRest* cr, const Beam::Mode bm, const Direc
}
// terminate the current beam and add to the score
if (beam && bm == Beam::Mode::END) {
beam = 0;
beam = nullptr;
}
}

Expand Down Expand Up @@ -2014,7 +2015,7 @@ void MusicXMLParserPass2::measure(const QString& partId, const Fraction time)
Fraction mDura; // current total measure duration
GraceChordList gcl; // grace chords collected sofar
int gac = 0; // grace after count in the grace chord list
Beam* beam = 0; // current beam
Beams beams; // Current beam for each voice in the current part
QString cv = "1"; // current voice for chords, default is 1
FiguredBassList fbl; // List of figured bass elements under a single note
MxmlTupletStates tupletStates; // Tuplet state for each voice in the current part
Expand Down Expand Up @@ -2044,7 +2045,7 @@ void MusicXMLParserPass2::measure(const QString& partId, const Fraction time)
// note: chord and grace note handling done in note()
// dura > 0 iff valid rest or first note of chord found
Note* n = note(partId, measure, time + mTime, time + prevTime, missingPrev, dura, missingCurr, cv, gcl, gac,
beam, fbl, alt, tupletStates, tuplets);
beams, fbl, alt, tupletStates, tuplets);
if (n && !n->chord()->isGrace()) {
prevChord = n->chord(); // remember last non-grace chord
}
Expand Down Expand Up @@ -2146,9 +2147,11 @@ void MusicXMLParserPass2::measure(const QString& partId, const Fraction time)
Part* part = _pass1.getPart(partId); // should not fail, we only get here if the part exists
fillGapsInFirstVoices(measure, part);

// can't have beams extending into the next measure
if (beam) {
removeBeam(beam);
// Prevent any beams from extending into the next measure
for (Beam* beam : beams.values()) {
if (beam) {
removeBeam(beam);
}
}

// TODO:
Expand Down Expand Up @@ -4410,7 +4413,7 @@ Note* MusicXMLParserPass2::note(const QString& partId,
QString& currentVoice,
GraceChordList& gcl,
int& gac,
Beam*& currBeam,
Beams& currBeams,
FiguredBassList& fbl,
int& alt,
MxmlTupletStates& tupletStates,
Expand Down Expand Up @@ -4524,6 +4527,12 @@ Note* MusicXMLParserPass2::note(const QString& partId,
voice = "1";
}

// Define currBeam based on currentVoice to handle multi-voice beaming (and instantiate if not already)
if (!currBeams.contains(currentVoice)) {
currBeams.insert(currentVoice, (Beam*)nullptr);
}
Beam*& currBeam = currBeams[currentVoice];

// check for timing error(s) and set dura
// keep in this order as checkTiming() might change dura
auto errorStr = mnd.checkTiming(type, rest, grace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ using FiguredBassList = QVector<FiguredBass*>;
// typedef QList<Chord*> GraceChordList;
// typedef QVector<FiguredBass*> FiguredBassList;
using Tuplets = std::map<QString, Tuplet*>;
using Beams = QMap<QString, Beam*>;

//---------------------------------------------------------
// MxmlStartStop
Expand Down Expand Up @@ -281,7 +282,7 @@ class MusicXMLParserPass2
void divisions();
void transpose(const QString& partId, const Fraction& tick);
Note* note(const QString& partId, Measure* measure, const Fraction sTime, const Fraction prevTime, Fraction& missingPrev,
Fraction& dura, Fraction& missingCurr, QString& currentVoice, GraceChordList& gcl, int& gac, Beam*& beam,
Fraction& dura, Fraction& missingCurr, QString& currentVoice, GraceChordList& gcl, int& gac, Beams& beams,
FiguredBassList& fbl, int& alt, MxmlTupletStates& tupletStates, Tuplets& tuplets);
void notePrintSpacingNo(Fraction& dura);
FiguredBassItem* figure(const int idx, const bool paren, FiguredBass* parent);
Expand Down