Skip to content

Commit

Permalink
ENG-23: Infer transpositions for Guitar staves
Browse files Browse the repository at this point in the history
Dolet for Sibelius does not support transpositions, and thus exports the
sounding pitch for guitar staves, resulting in notation an octave below
where it ought to be. This adds a simple mechanism for inferring a
part's transposition. Since a normal MusicXML part expects the correct
written pitches, then applies the transposition to the sounding pitch,
this also adds a part-wise mechanism for transposing the *written*
pitch, called `_inferredTranspose`.

Duplicate of musescore#8358, plus fixing a compiler warning, duplicate of musescore#8481
  • Loading branch information
iveshenry18 authored and Jojo-Schmitz committed Jul 28, 2021
1 parent adcbc48 commit e6c7a1a
Show file tree
Hide file tree
Showing 7 changed files with 4,182 additions and 8 deletions.
32 changes: 28 additions & 4 deletions importexport/musicxml/importmxmlpass1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1101,8 +1101,12 @@ void MusicXMLParserPass1::identification()
else if (_e.name() == "encoding") {
// TODO
while (_e.readNextStartElement()) {
if (_e.name() == "supports" && _e.attributes().value("element") == "beam" && _e.attributes().value("type") == "yes")
_hasBeamingInfo = true;
if (_e.name() == "supports" ) {
if (_e.attributes().value("element") == "beam" && _e.attributes().value("type") == "yes")
_hasBeamingInfo = true;
else if (_e.attributes().value("element") == "transpose")
_supportsTranspose = _e.attributes().value("type").toString();
}
_e.skipCurrentElement();
}
// _score->setMetaTag("encoding", _e.readElementText()); works with DOM but not with pull parser
Expand Down Expand Up @@ -1798,6 +1802,23 @@ static const InstrumentTemplate* findInstrument(const QString& instrSound)
}
#endif

//---------------------------------------------------------
// addInferredTranspose
//---------------------------------------------------------
/**
In the case that transposition information is missing,
instrument-level transpositions are inferred here.
This changes the *written* pitch, but retains the sounding pitch.
*/
void MusicXMLParserPass1::addInferredTranspose(const QString& partId)
{
if (_parts[partId].getName().contains("guitar", Qt::CaseInsensitive)
&& !_parts[partId].hasTab()) {
_parts[partId]._inferredTranspose = Interval(12);
_parts[partId]._intervals[Fraction(0, 1)] = Interval(-12);
}
}

//---------------------------------------------------------
// scorePart
//---------------------------------------------------------
Expand Down Expand Up @@ -2374,7 +2395,7 @@ void MusicXMLParserPass1::attributes(const QString& partId, const Fraction cTime
TODO: Store the clef type, to simplify staff type setting in pass 2.
*/

void MusicXMLParserPass1::clef(const QString& /* partId */)
void MusicXMLParserPass1::clef(const QString& partId)
{
Q_ASSERT(_e.isStartElement() && _e.name() == "clef");
_logger->logDebugTrace("MusicXMLParserPass1::clef", &_e);
Expand All @@ -2394,8 +2415,11 @@ void MusicXMLParserPass1::clef(const QString& /* partId */)
while (_e.readNextStartElement()) {
if (_e.name() == "line")
_e.skipCurrentElement(); // skip but don't log
else if (_e.name() == "sign")
else if (_e.name() == "sign") {
QString sign = _e.readElementText();
if (sign == "TAB")
_parts[partId].hasTab(true);
}
else
skipLogCurrElem();
}
Expand Down
3 changes: 3 additions & 0 deletions importexport/musicxml/importmxmlpass1.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class MusicXMLParserPass1 {
const CreditWordsList& credits() const { return _credits; }
bool hasBeamingInfo() const { return _hasBeamingInfo; }
static VBox* createAndAddVBoxForCreditWords(Score* const score, const int miny = 0, const int maxy = 75);
QString supportsTranspose() const { return _supportsTranspose; }
void addInferredTranspose(const QString& partId);

private:
// functions
Expand All @@ -186,6 +188,7 @@ class MusicXMLParserPass1 {
Score* _score; ///< MuseScore score
MxmlLogger* _logger; ///< Error logger
bool _hasBeamingInfo; ///< Whether the score supports or contains beaming info
QString _supportsTranspose; ///< Whether the score supports transposition info

// part specific data (TODO: move to part-specific class)
Fraction _timeSigDura; ///< Measure duration according to last timesig read
Expand Down
13 changes: 9 additions & 4 deletions importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ static int MusicXMLStepAltOct2Pitch(int step, int alter, int octave)
Note that n's staff and track have not been set yet
*/

static void xmlSetPitch(Note* n, int step, int alter, int octave, const int octaveShift, const Instrument* const instr)
static void xmlSetPitch(Note* n, int step, int alter, int octave, const int octaveShift, const Instrument* const instr, Interval inferredTranspose = Interval(0))
{
//qDebug("xmlSetPitch(n=%p, step=%d, alter=%d, octave=%d, octaveShift=%d)",
// n, step, alter, octave, octaveShift);
Expand All @@ -225,18 +225,20 @@ static void xmlSetPitch(Note* n, int step, int alter, int octave, const int octa
//const Instrument* instr = staff->part()->instr();

const Interval intval = instr->transpose();

const Interval combinedIntval(intval.diatonic + inferredTranspose.diatonic, intval.chromatic + inferredTranspose.chromatic);
//qDebug(" staff=%p instr=%p dia=%d chro=%d",
// staff, instr, static_cast<int>(intval.diatonic), static_cast<int>(intval.chromatic));

int pitch = MusicXMLStepAltOct2Pitch(step, alter, octave);
pitch += intval.chromatic; // assume not in concert pitch
pitch += 12 * octaveShift; // correct for octave shift
pitch += inferredTranspose.chromatic;
// ensure sane values
pitch = limit(pitch, 0, 127);

int tpc2 = step2tpc(step, AccidentalVal(alter));
int tpc1 = Ms::transposeTpc(tpc2, intval, true);
tpc2 = Ms::transposeTpc(tpc2, inferredTranspose, true);
int tpc1 = Ms::transposeTpc(tpc2, combinedIntval, true);
n->setPitch(pitch, tpc1, tpc2);
//qDebug(" pitch=%d tpc1=%d tpc2=%d", n->pitch(), n->tpc1(), n->tpc2());
}
Expand Down Expand Up @@ -1666,6 +1668,9 @@ void MusicXMLParserPass2::part()
_hasDrumset = hasDrumset(instruments);

// set the parts first instrument

if (_pass1.supportsTranspose() == "no")
_pass1.addInferredTranspose(id);
setPartInstruments(_logger, &_e, _pass1.getPart(id), id, _score, _pass1.getInstrList(id), _pass1.getIntervals(id), instruments);

// set the part name
Expand Down Expand Up @@ -4540,7 +4545,7 @@ static void setPitch(Note* note, MusicXMLParserPass1& pass1, const QString& part
}
}
else {
xmlSetPitch(note, mnp.step(), mnp.alter(), mnp.octave(), octaveShift, instrument);
xmlSetPitch(note, mnp.step(), mnp.alter(), mnp.octave(), octaveShift, instrument, pass1.getMusicXmlPart(partId)._inferredTranspose);
}
}

Expand Down
4 changes: 4 additions & 0 deletions importexport/musicxml/importxmlfirstpass.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class MusicXmlPart {
int nMeasures() const { return measureDurations.size(); }
MusicXmlInstrList _instrList; // TODO: make private
MusicXmlIntervalList _intervals; ///< Transpositions
Interval _inferredTranspose;
Interval interval(const Fraction f) const;
int octaveShift(const int staff, const Fraction f) const;
void addOctaveShift(const int staff, const int shift, const Fraction f);
Expand All @@ -77,6 +78,8 @@ class MusicXmlPart {
QString getAbbr() const { return abbr; }
void setPrintAbbr(bool b) { printAbbr = b; }
bool getPrintAbbr() const { return printAbbr; }
bool hasTab() const { return _hasTab; }
void hasTab(const bool b) { _hasTab = b; }
LyricNumberHandler& lyricNumberHandler() { return _lyricNumberHandler; }
const LyricNumberHandler& lyricNumberHandler() const { return _lyricNumberHandler; }
void setMaxStaff(const int staff);
Expand All @@ -87,6 +90,7 @@ class MusicXmlPart {
bool printName = true;
QString abbr;
bool printAbbr = true;
bool _hasTab = false;
QStringList measureNumbers; // MusicXML measure number attribute
QList<Fraction> measureDurations; // duration in fraction for every measure
QVector<MusicXmlOctaveShiftList> octaveShifts; // octave shift list for every staff
Expand Down

0 comments on commit e6c7a1a

Please sign in to comment.