This commit is contained in:
Leon Vinken 2012-08-12 21:10:08 +02:00
parent 963f62c81a
commit 8cf98010d0
3 changed files with 114 additions and 199 deletions

View file

@ -266,8 +266,12 @@ static Fraction noteTypeToFraction(QString type)
// calculateFraction
//---------------------------------------------------------
/**
Convert note type, number of dots and actual and normal notes into a duration
*/
static Fraction calculateFraction(QString type, int dots, int normalNotes, int actualNotes)
{
{
// type
Fraction f = noteTypeToFraction(type);
if (f.isValid()) {
@ -283,7 +287,7 @@ static Fraction calculateFraction(QString type, int dots, int normalNotes, int a
f.reduce();
}
return f;
}
}
//---------------------------------------------------------
@ -292,87 +296,90 @@ static Fraction calculateFraction(QString type, int dots, int normalNotes, int a
/**
Determine note duration as fraction. Prefer note type over duration.
Input e is the note element.
If chord or grace, duration is 0.
*/
static Fraction noteDurationAsFraction(const int divisions, const QDomElement e)
{
int actualNotes = 0;
bool chord = false;
int dots = 0;
int duration = 0;
bool grace = false;
int normalNotes = 0;
bool rest = false;
QString type;
for (QDomElement ee = e.firstChildElement(); !ee.isNull(); ee = ee.nextSiblingElement()) {
if (ee.tagName() == "chord")
chord = true;
else if (ee.tagName() == "dot")
dots++;
else if (ee.tagName() == "duration") {
bool ok;
duration = stringToInt(ee.text(), &ok);
if (!ok)
qDebug("MusicXml-Import: bad duration value: <%s>",
qPrintable(ee.text()));
}
else if (ee.tagName() == "grace")
grace = true;
else if (ee.tagName() == "rest")
rest = true;
else if (ee.tagName() == "time-modification") {
for (QDomElement eee = ee.firstChildElement(); !eee.isNull(); eee = eee.nextSiblingElement()) {
if (eee.tagName() == "actual-notes") {
bool ok;
actualNotes = stringToInt(eee.text(), &ok);
if (!ok || divisions <= 0)
qDebug("MusicXml-Import: bad actual-notes value: <%s>",
qPrintable(eee.text()));
}
if (eee.tagName() == "normal-notes") {
bool ok;
normalNotes = stringToInt(eee.text(), &ok);
if (!ok || divisions <= 0)
qDebug("MusicXml-Import: bad normal-notes value: <%s>",
qPrintable(eee.text()));
}
}
}
else if (ee.tagName() == "type")
type = ee.text();
}
int actualNotes = 0;
bool chord = false;
int dots = 0;
int duration = 0;
bool grace = false;
int normalNotes = 0;
bool rest = false;
QString type;
for (QDomElement ee = e.firstChildElement(); !ee.isNull(); ee = ee.nextSiblingElement()) {
if (ee.tagName() == "chord")
chord = true;
else if (ee.tagName() == "dot")
dots++;
else if (ee.tagName() == "duration") {
bool ok;
duration = stringToInt(ee.text(), &ok);
if (!ok)
qDebug("MusicXml-Import: bad duration value: <%s>",
qPrintable(ee.text()));
}
else if (ee.tagName() == "grace")
grace = true;
else if (ee.tagName() == "rest")
rest = true;
else if (ee.tagName() == "time-modification") {
for (QDomElement eee = ee.firstChildElement(); !eee.isNull(); eee = eee.nextSiblingElement()) {
if (eee.tagName() == "actual-notes") {
bool ok;
actualNotes = stringToInt(eee.text(), &ok);
if (!ok || divisions <= 0)
qDebug("MusicXml-Import: bad actual-notes value: <%s>",
qPrintable(eee.text()));
}
if (eee.tagName() == "normal-notes") {
bool ok;
normalNotes = stringToInt(eee.text(), &ok);
if (!ok || divisions <= 0)
qDebug("MusicXml-Import: bad normal-notes value: <%s>",
qPrintable(eee.text()));
}
}
}
else if (ee.tagName() == "type")
type = ee.text();
}
// if chord or grace, duration is 0
if (chord || grace)
return Fraction(0, 1);
// if chord or grace, duration is 0
if (chord || grace)
return Fraction(0, 1);
// calculate note duration as fraction based on type, dots, normal and actual notes
Fraction f = calculateFraction(type, dots, normalNotes, actualNotes);
if (!f.isValid()) {
qDebug("time-in-fraction: f invalid, using duration");
f = Fraction(duration, 4 * divisions); // note divisions = ticks / quarter note
}
// calculate note duration as fraction based on type, dots, normal and actual notes
// if that does not succeed, fallback to using the <duration> element
// note divisions = ticks / quarter note
Fraction f = calculateFraction(type, dots, normalNotes, actualNotes);
if (!f.isValid()) {
qDebug("time-in-fraction: f invalid, using duration");
f = Fraction(duration, 4 * divisions);
}
// bug fix for rests in triplet
if (f.isValid() && rest && normalNotes == 0 && actualNotes == 0) {
qDebug("time-in-fraction: check for rest in triplet bug: %s",
qPrintable((Fraction(duration, 4 * divisions) / f).print()));
if ((Fraction(duration, 4 * divisions) / f) == Fraction(2, 3)) {
// duration is exactly 2/3 of what is expected based on type
qDebug("time-in-fraction: rest in triplet bug found, fixing ...");
f = Fraction(duration, 4 * divisions);
}
}
// bug fix for rests in triplet
if (f.isValid() && rest && normalNotes == 0 && actualNotes == 0) {
qDebug("time-in-fraction: check for rest in triplet bug: %s",
qPrintable((Fraction(duration, 4 * divisions) / f).print()));
if ((Fraction(duration, 4 * divisions) / f) == Fraction(2, 3)) {
// duration is exactly 2/3 of what is expected based on type
qDebug("time-in-fraction: rest in triplet bug found, fixing ...");
f = Fraction(duration, 4 * divisions);
}
}
#ifdef DEBUG_TICK
qDebug("time-in-fraction: note type %s dots %d norm %d act %d"
" dur %d chord %d grace %d-> dt frac %s (ticks %d)",
qPrintable(type), dots, normalNotes, actualNotes, duration,
chord, grace, qPrintable(f.print()), f.ticks());
qDebug("time-in-fraction: note type %s dots %d norm %d act %d"
" dur %d chord %d grace %d-> dt frac %s (ticks %d)",
qPrintable(type), dots, normalNotes, actualNotes, duration,
chord, grace, qPrintable(f.print()), f.ticks());
#endif
return f;
return f;
}
@ -381,7 +388,7 @@ static Fraction noteDurationAsFraction(const int divisions, const QDomElement e)
//---------------------------------------------------------
/**
Move tick/typFr by amount specified in the element e, which must be
Move tick and typFr by amount specified in the element e, which must be
a forward, backup or note.
*/
@ -397,8 +404,8 @@ static void moveTick(const int mtick, int& tick, int& maxtick, Fraction& typFr,
bool ok;
val = stringToInt(ee.text(), &ok);
if (!ok || divisions <= 0)
qDebug("MusicXml-Import: bad divisions value: <%s>",
qPrintable(ee.text()));
qDebug("MusicXml-Import: bad divisions value: <%s>",
qPrintable(ee.text()));
Fraction f(val, 4 * divisions); // note divisions = ticks / quarter note
typFr += f;
typFr.reduce();
@ -424,8 +431,8 @@ static void moveTick(const int mtick, int& tick, int& maxtick, Fraction& typFr,
bool ok;
val = stringToInt(ee.text(), &ok);
if (!ok || divisions <= 0)
qDebug("MusicXml-Import: bad divisions value: <%s>",
qPrintable(ee.text()));
qDebug("MusicXml-Import: bad divisions value: <%s>",
qPrintable(ee.text()));
Fraction f(val, 4 * divisions); // note divisions = ticks / quarter note
if (f < typFr) {
typFr -= f;
@ -1017,12 +1024,6 @@ static bool determineTimeSig(const QString beats, const QString beatType, const
*/
/*
* TODO for debugging issue 17654, dump both
* - the timing in fraction based on note type (and backup/restore)
* - the timing in duration (as fraction) only
*/
static bool determineMeasureLength(QDomElement e, QVector<int>& ml)
{
#ifdef DEBUG_TICK
@ -1042,12 +1043,8 @@ static bool determineMeasureLength(QDomElement e, QVector<int>& ml)
// current "tick" within this measure as fraction
// calculated using note type, backup and forward
Fraction noteTypeTickFr;
// current "tick" within this measure as fraction
// calculated using note duration, backup and forward
Fraction noteDurationTickFr;
// maximum "tick" within this measure as fraction
Fraction maxNoteTypeTickFr;
Fraction maxNoteDurationTickFr;
// dummy
int dummy_tick = 0;
int dummy_maxtick = 0;
@ -1100,39 +1097,25 @@ static bool determineMeasureLength(QDomElement e, QVector<int>& ml)
// (divisions must be valid)
if (divisions > 0) {
if (ee.tagName() == "note") {
moveTick(0, dummy_tick, dummy_maxtick, noteTypeTickFr, divisions, ee);
if (noteTypeTickFr > maxNoteTypeTickFr)
maxNoteTypeTickFr = noteTypeTickFr;
qDebug("time-in-fraction: after note type based fraction %s tick %d max fraction %s tick %d",
qPrintable(noteTypeTickFr.print()), noteTypeTickFr.ticks(),
qPrintable(maxNoteTypeTickFr.print()), maxNoteTypeTickFr.ticks());
// noteDurationTickFr += Fraction(duration, 4 * divisions); // note divisions = ticks / quarter note
noteDurationTickFr.reduce();
if (noteDurationTickFr > maxNoteDurationTickFr)
maxNoteDurationTickFr = noteDurationTickFr;
qDebug("time-in-fraction: after note duration based fraction %s tick %d max fraction %s tick %d",
qPrintable(noteDurationTickFr.print()), noteDurationTickFr.ticks(),
qPrintable(maxNoteDurationTickFr.print()), maxNoteDurationTickFr.ticks());
moveTick(0, dummy_tick, dummy_maxtick, noteTypeTickFr, divisions, ee);
if (noteTypeTickFr > maxNoteTypeTickFr)
maxNoteTypeTickFr = noteTypeTickFr;
qDebug("time-in-fraction: after note type based fraction %s tick %d max fraction %s tick %d",
qPrintable(noteTypeTickFr.print()), noteTypeTickFr.ticks(),
qPrintable(maxNoteTypeTickFr.print()), maxNoteTypeTickFr.ticks());
}
else if (ee.tagName() == "backup") {
moveTick(0, dummy_tick, dummy_maxtick, noteTypeTickFr, divisions, ee);
qDebug("time-in-fraction: after backup type based fraction %s tick %d",
qPrintable(noteTypeTickFr.print()), noteTypeTickFr.ticks());
qDebug("time-in-fraction: after backup duration based fraction %s tick %d",
qPrintable(noteDurationTickFr.print()), noteDurationTickFr.ticks());
}
else if (ee.tagName() == "forward") {
moveTick(0, dummy_tick, dummy_maxtick, noteTypeTickFr, divisions, ee);
if (noteTypeTickFr > maxNoteTypeTickFr)
maxNoteTypeTickFr = noteTypeTickFr;
if (noteDurationTickFr > maxNoteDurationTickFr)
maxNoteDurationTickFr = noteDurationTickFr;
qDebug("time-in-fraction: after forward type based fraction %s tick %d max fraction %s tick %d",
qPrintable(noteTypeTickFr.print()), noteTypeTickFr.ticks(),
qPrintable(maxNoteTypeTickFr.print()), maxNoteTypeTickFr.ticks());
qDebug("time-in-fraction: after forward duration based fraction %s tick %d max fraction %s tick %d",
qPrintable(noteDurationTickFr.print()), noteDurationTickFr.ticks(),
qPrintable(maxNoteDurationTickFr.print()), maxNoteDurationTickFr.ticks());
}
}
else
@ -1140,9 +1123,8 @@ static bool determineMeasureLength(QDomElement e, QVector<int>& ml)
} // for (QDomElement ee ....
// measure has been read, determine length
qDebug("time-in-fraction: max type based fraction %s tick %d max duration based fraction %s tick %d",
qPrintable(maxNoteTypeTickFr.print()), maxNoteTypeTickFr.ticks(),
qPrintable(maxNoteDurationTickFr.print()), maxNoteDurationTickFr.ticks());
qDebug("time-in-fraction: max type based fraction %s tick %d",
qPrintable(maxNoteTypeTickFr.print()), maxNoteTypeTickFr.ticks());
int length = maxNoteTypeTickFr.ticks();
int correctedLength = length;
#if 1 // change in 0.9.6 trunk revision 5241 for issue 14451, TODO verify if useful in trunk
@ -4981,7 +4963,7 @@ void MusicXml::xmlNote(Measure* measure, int staff, const QString& partId, QDomE
Segment* s = measure->getSegment(cr, loc_tick);
//sibelius might import 2 rests at the same place, ignore the 2one
//<?DoletSibelius Two NoteRests in same voice at same position may be an error?>
if(!s->element(cr->track()))
if (!s->element(cr->track()))
s->add(cr);
cr->setVisible(printObject == "yes");
if (step != "" && 0 <= octave && octave <= 9) {
@ -5145,79 +5127,13 @@ void MusicXml::xmlNote(Measure* measure, int staff, const QString& partId, QDomE
addLyrics(cr, numberedLyrics, defaultyLyrics, unNumberedLyrics);
if (!chord)
prevtick = tick; // remember tick where last chordrest was inserted
prevtick = tick; // remember tick where last chordrest was inserted
#ifdef DEBUG_TICK
qDebug(" after inserting note tick=%d prevtick=%d", tick, prevtick);
#endif
}
//---------------------------------------------------------
// addWedge
//---------------------------------------------------------
/**
Add a MusicXML wedge to the wedge list.
Called when the wedge start is read. Stores all wedge parameters known at this time.
*/
/*
void MusicXml::addWedge(int no, int startTick, qreal rx, qreal ry, bool above, bool hasYoffset, qreal yoffset, int subType)
{
qDebug("addWedge(no %d, startTick %d, subType %d)", no, startTick, subType);
MusicXmlWedge wedge;
wedge.number = no;
wedge.startTick = startTick;
wedge.rx = rx;
wedge.ry = ry;
wedge.above = above;
wedge.hasYoffset = hasYoffset;
wedge.yoffset = yoffset;
wedge.subType = subType;
if (int(wedgeList.size()) > no)
wedgeList[no] = wedge;
else
wedgeList.push_back(wedge);
}
*/
//---------------------------------------------------------
// genWedge
//---------------------------------------------------------
/**
Add a MusicXML wedge to the score.
Called when the wedge stop is read. Wedge stop tick was unknown until this time.
*/
/*
void MusicXml::genWedge(int no, int endTick, Measure* measure, int staff)
{
qDebug("genWedge(no %d, endTick %d", no, endTick);
Hairpin* hp = new Hairpin(score);
hp->setSubtype(wedgeList[no].subType);
if (wedgeList[no].hasYoffset)
hp->setYoff(wedgeList[no].yoffset);
else
hp->setYoff(wedgeList[no].above ? -3 : 8);
hp->setUserOff(QPointF(wedgeList[no].rx, wedgeList[no].ry));
hp->setTrack(staff * VOICES);
// TODO LVI following fails for wedges starting in a different measure !
Segment* seg = measure->getSegment(Segment::SegChordRest, wedgeList[no].startTick);
qDebug("start seg %p", seg);
hp->setStartElement(seg);
seg->add(hp);
seg = measure->getSegment(Segment::SegChordRest, endTick);
qDebug(", stop seg %p", seg);
hp->setEndElement(seg);
seg->addSpannerBack(hp);
score->updateHairpin(hp);
// qDebug("gen wedge %p staff %d, tick %d-%d", hp, staff, hp->tick(), hp->tick2());
}
*/
//---------------------------------------------------------
// xmlHarmony

View file

@ -93,7 +93,8 @@ struct CreditWords {
QString hAlign;
QString vAlign;
QString words;
CreditWords(double a, double b, QString c, QString d, QString e, QString f) {
CreditWords(double a, double b, QString c, QString d, QString e, QString f)
{
defaultX = a;
defaultY = b;
justify = c;
@ -119,10 +120,10 @@ class MusicXmlCreator {
QString _type;
QString _text;
public:
public:
MusicXmlCreator(QString& tp, QString& txt) { _type = tp; _text = txt; }
QString crType() const { return _type; }
QString crText() const { return _text; }
QString crType() const { return _type; }
QString crText() const { return _text; }
};
//---------------------------------------------------------
@ -134,24 +135,24 @@ class MusicXmlCreator {
*/
class VoiceDesc {
public:
public:
VoiceDesc();
void incrChordRests(int s);
int numberChordRests() const;
int numberChordRests(int s) const { return (s >= 0 && s < MAX_STAVES) ? _chordRests[s] : 0; }
int preferredStaff() const; ///< Determine preferred staff for this voice
void setStaff(int s) { if (s >= 0) _staff = s; }
int staff() const { return _staff; }
void setVoice(int v) { if (v >= 0) _voice = v; }
int voice() const { return _voice; }
void setVoice(int s, int v) { if (s >= 0 && s < MAX_STAVES) _voices[s] = v; }
int voice(int s) const { return (s >= 0 && s < MAX_STAVES) ? _voices[s] : -1; }
void setOverlap(bool b) { _overlaps = b; }
bool overlaps() const { return _overlaps; }
void setStaffAlloc(int s, int i) { if (s >= 0 && s < MAX_STAVES) _staffAlloc[s] = i; }
int staffAlloc(int s) const { return (s >= 0 && s < MAX_STAVES) ? _staffAlloc[s] : -1; }
void setStaff(int s) { if (s >= 0) _staff = s; }
int staff() const { return _staff; }
void setVoice(int v) { if (v >= 0) _voice = v; }
int voice() const { return _voice; }
void setVoice(int s, int v) { if (s >= 0 && s < MAX_STAVES) _voices[s] = v; }
int voice(int s) const { return (s >= 0 && s < MAX_STAVES) ? _voices[s] : -1; }
void setOverlap(bool b) { _overlaps = b; }
bool overlaps() const { return _overlaps; }
void setStaffAlloc(int s, int i) { if (s >= 0 && s < MAX_STAVES) _staffAlloc[s] = i; }
int staffAlloc(int s) const { return (s >= 0 && s < MAX_STAVES) ? _staffAlloc[s] : -1; }
QString toString() const;
private:
private:
int _chordRests[MAX_STAVES]; ///< The number of chordrests on each MusicXML staff
int _staff; ///< The MuseScore staff allocated
int _voice; ///< The MuseScore voice allocated
@ -172,9 +173,9 @@ class JumpMarkerDesc {
Element* _el;
const Measure* _meas;
public:
public:
JumpMarkerDesc(Element* el, const Measure* meas) : _el(el), _meas(meas) {}
Element* el() const { return _el; }
Element* el() const { return _el; }
const Measure* meas() const { return _meas; }
};
@ -223,7 +224,6 @@ class MusicXml {
CreditWordsList credits;
JumpMarkerDescList jumpsMarkers;
// std::vector<MusicXmlWedge> wedgeList;
std::vector<MusicXmlPartGroup*> partGroupList;
QMap<Spanner*, QPair<int, int> > spanners;
@ -242,8 +242,6 @@ class MusicXml {
//-----------------------------
// void addWedge(int no, int startPos, qreal rx, qreal ry, bool above, bool hasYoffset, qreal yoffset, int subType);
// void genWedge(int no, int endPos, Measure*, int staff);
void doCredits();
void direction(Measure* measure, int staff, QDomElement node);
void scorePartwise(QDomElement);
@ -262,7 +260,7 @@ class MusicXml {
int xmlClef(QDomElement, int staffIdx, Measure*);
void initVoiceMapperAndMapVoices(QDomElement e);
public:
public:
MusicXml(QDomDocument* d);
void import(Score*);
};

View file

@ -1,3 +1,4 @@
testDurationRoundingError.xml
testDynamics3.xml
testEmptyMeasure.xml
testEmptyVoice1.xml