Skip to content

Commit 3973427

Browse files
iveshenry18Jojo-Schmitz
authored andcommitted
ENG-23: Infer transpositions for Guitar staves
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
1 parent 82d262d commit 3973427

File tree

7 files changed

+4182
-8
lines changed

7 files changed

+4182
-8
lines changed

importexport/musicxml/importmxmlpass1.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,8 +1101,12 @@ void MusicXMLParserPass1::identification()
11011101
else if (_e.name() == "encoding") {
11021102
// TODO
11031103
while (_e.readNextStartElement()) {
1104-
if (_e.name() == "supports" && _e.attributes().value("element") == "beam" && _e.attributes().value("type") == "yes")
1105-
_hasBeamingInfo = true;
1104+
if (_e.name() == "supports" ) {
1105+
if (_e.attributes().value("element") == "beam" && _e.attributes().value("type") == "yes")
1106+
_hasBeamingInfo = true;
1107+
else if (_e.attributes().value("element") == "transpose")
1108+
_supportsTranspose = _e.attributes().value("type").toString();
1109+
}
11061110
_e.skipCurrentElement();
11071111
}
11081112
// _score->setMetaTag("encoding", _e.readElementText()); works with DOM but not with pull parser
@@ -1798,6 +1802,23 @@ static const InstrumentTemplate* findInstrument(const QString& instrSound)
17981802
}
17991803
#endif
18001804

1805+
//---------------------------------------------------------
1806+
// addInferredTranspose
1807+
//---------------------------------------------------------
1808+
/**
1809+
In the case that transposition information is missing,
1810+
instrument-level transpositions are inferred here.
1811+
This changes the *written* pitch, but retains the sounding pitch.
1812+
*/
1813+
void MusicXMLParserPass1::addInferredTranspose(const QString& partId)
1814+
{
1815+
if (_parts[partId].getName().contains("guitar", Qt::CaseInsensitive)
1816+
&& !_parts[partId].hasTab()) {
1817+
_parts[partId]._inferredTranspose = Interval(12);
1818+
_parts[partId]._intervals[Fraction(0, 1)] = Interval(-12);
1819+
}
1820+
}
1821+
18011822
//---------------------------------------------------------
18021823
// scorePart
18031824
//---------------------------------------------------------
@@ -2374,7 +2395,7 @@ void MusicXMLParserPass1::attributes(const QString& partId, const Fraction cTime
23742395
TODO: Store the clef type, to simplify staff type setting in pass 2.
23752396
*/
23762397

2377-
void MusicXMLParserPass1::clef(const QString& /* partId */)
2398+
void MusicXMLParserPass1::clef(const QString& partId)
23782399
{
23792400
Q_ASSERT(_e.isStartElement() && _e.name() == "clef");
23802401
_logger->logDebugTrace("MusicXMLParserPass1::clef", &_e);
@@ -2394,8 +2415,11 @@ void MusicXMLParserPass1::clef(const QString& /* partId */)
23942415
while (_e.readNextStartElement()) {
23952416
if (_e.name() == "line")
23962417
_e.skipCurrentElement(); // skip but don't log
2397-
else if (_e.name() == "sign")
2418+
else if (_e.name() == "sign") {
23982419
QString sign = _e.readElementText();
2420+
if (sign == "TAB")
2421+
_parts[partId].hasTab(true);
2422+
}
23992423
else
24002424
skipLogCurrElem();
24012425
}

importexport/musicxml/importmxmlpass1.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class MusicXMLParserPass1 {
167167
const CreditWordsList& credits() const { return _credits; }
168168
bool hasBeamingInfo() const { return _hasBeamingInfo; }
169169
static VBox* createAndAddVBoxForCreditWords(Score* const score, const int miny = 0, const int maxy = 75);
170+
QString supportsTranspose() const { return _supportsTranspose; }
171+
void addInferredTranspose(const QString& partId);
170172

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

190193
// part specific data (TODO: move to part-specific class)
191194
Fraction _timeSigDura; ///< Measure duration according to last timesig read

importexport/musicxml/importmxmlpass2.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ static int MusicXMLStepAltOct2Pitch(int step, int alter, int octave)
216216
Note that n's staff and track have not been set yet
217217
*/
218218

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

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

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

238239
int tpc2 = step2tpc(step, AccidentalVal(alter));
239-
int tpc1 = Ms::transposeTpc(tpc2, intval, true);
240+
tpc2 = Ms::transposeTpc(tpc2, inferredTranspose, true);
241+
int tpc1 = Ms::transposeTpc(tpc2, combinedIntval, true);
240242
n->setPitch(pitch, tpc1, tpc2);
241243
//qDebug(" pitch=%d tpc1=%d tpc2=%d", n->pitch(), n->tpc1(), n->tpc2());
242244
}
@@ -1666,6 +1668,9 @@ void MusicXMLParserPass2::part()
16661668
_hasDrumset = hasDrumset(instruments);
16671669

16681670
// set the parts first instrument
1671+
1672+
if (_pass1.supportsTranspose() == "no")
1673+
_pass1.addInferredTranspose(id);
16691674
setPartInstruments(_logger, &_e, _pass1.getPart(id), id, _score, _pass1.getInstrList(id), _pass1.getIntervals(id), instruments);
16701675

16711676
// set the part name
@@ -4540,7 +4545,7 @@ static void setPitch(Note* note, MusicXMLParserPass1& pass1, const QString& part
45404545
}
45414546
}
45424547
else {
4543-
xmlSetPitch(note, mnp.step(), mnp.alter(), mnp.octave(), octaveShift, instrument);
4548+
xmlSetPitch(note, mnp.step(), mnp.alter(), mnp.octave(), octaveShift, instrument, pass1.getMusicXmlPart(partId)._inferredTranspose);
45444549
}
45454550
}
45464551

importexport/musicxml/importxmlfirstpass.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class MusicXmlPart {
6565
int nMeasures() const { return measureDurations.size(); }
6666
MusicXmlInstrList _instrList; // TODO: make private
6767
MusicXmlIntervalList _intervals; ///< Transpositions
68+
Interval _inferredTranspose;
6869
Interval interval(const Fraction f) const;
6970
int octaveShift(const int staff, const Fraction f) const;
7071
void addOctaveShift(const int staff, const int shift, const Fraction f);
@@ -77,6 +78,8 @@ class MusicXmlPart {
7778
QString getAbbr() const { return abbr; }
7879
void setPrintAbbr(bool b) { printAbbr = b; }
7980
bool getPrintAbbr() const { return printAbbr; }
81+
bool hasTab() const { return _hasTab; }
82+
void hasTab(const bool b) { _hasTab = b; }
8083
LyricNumberHandler& lyricNumberHandler() { return _lyricNumberHandler; }
8184
const LyricNumberHandler& lyricNumberHandler() const { return _lyricNumberHandler; }
8285
void setMaxStaff(const int staff);
@@ -87,6 +90,7 @@ class MusicXmlPart {
8790
bool printName = true;
8891
QString abbr;
8992
bool printAbbr = true;
93+
bool _hasTab = false;
9094
QStringList measureNumbers; // MusicXML measure number attribute
9195
QList<Fraction> measureDurations; // duration in fraction for every measure
9296
QVector<MusicXmlOctaveShiftList> octaveShifts; // octave shift list for every staff

0 commit comments

Comments
 (0)