Skip to content

Commit

Permalink
musescore#15899: support figured bass extend elements
Browse files Browse the repository at this point in the history
  • Loading branch information
lvinken committed Jan 1, 2013
1 parent 8218c97 commit 1fa8c41
Show file tree
Hide file tree
Showing 7 changed files with 640 additions and 45 deletions.
61 changes: 39 additions & 22 deletions libmscore/figuredbass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,15 +770,15 @@ QString FiguredBassItem::Modifier2MusicXML(FiguredBassItem::Modifier prefix) con
// node instead of for each individual <figure> node.
//---------------------------------------------------------

void FiguredBassItem::readMusicXML(const QDomElement& de, bool paren)
void FiguredBassItem::readMusicXML(const QDomElement& de, bool paren, bool& extend)
{
// read the <figure> node de
for (QDomElement e = de.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
const QString& tag(e.tagName());
const QString& val(e.text());
int iVal = val.toInt();
if (tag == "extend")
; // TODO
extend = true;
else if (tag == "figure-number") {
// MusicXML spec states figure-number is a number
// MuseScore can only handle single digit
Expand Down Expand Up @@ -815,17 +815,22 @@ void FiguredBassItem::readMusicXML(const QDomElement& de, bool paren)
// Write MusicXML
//---------------------------------------------------------

void FiguredBassItem::writeMusicXML(Xml& xml) const
void FiguredBassItem::writeMusicXML(Xml& xml, bool doFigure, bool doExtend) const
{
xml.stag("figure");
QString strPrefix = Modifier2MusicXML(_prefix);
if (strPrefix != "")
xml.tag("prefix", strPrefix);
if (_digit != FBIDigitNone)
xml.tag("figure-number", _digit);
QString strSuffix = Modifier2MusicXML(_suffix);
if (strSuffix != "")
xml.tag("suffix", strSuffix);
if (doFigure) {
QString strPrefix = Modifier2MusicXML(_prefix);
if (strPrefix != "")
xml.tag("prefix", strPrefix);
if (_digit != FBIDigitNone)
xml.tag("figure-number", _digit);
QString strSuffix = Modifier2MusicXML(_suffix);
if (strSuffix != "")
xml.tag("suffix", strSuffix);
}
if (doExtend) {
xml.tagE("extend");
}
xml.etag();
}

Expand Down Expand Up @@ -1490,10 +1495,13 @@ bool FiguredBass::fontData(int nIdx, QString * pFamily, QString * pDisplayName,
// Note that onNote and ticks must be set by the MusicXML importer,
// as the required context is not present in the items DOM tree.
// Exception: if a <duration> element is present, tick can be set.
// Return true if valid, non-empty figure(s) are found
// Set extend to true if extend elements were found
//---------------------------------------------------------

void FiguredBass::readMusicXML(const QDomElement& de, int divisions)
bool FiguredBass::readMusicXML(const QDomElement& de, int divisions, bool& extend)
{
extend = false;
bool parentheses = (de.attribute("parentheses") == "yes");
QString normalizedText;
int idx = 0;
Expand All @@ -1513,20 +1521,27 @@ void FiguredBass::readMusicXML(const QDomElement& de, int divisions)
qPrintable(val));
}
else if (tag == "figure") {
bool figureExtend = false;
FiguredBassItem * pItem = new FiguredBassItem(score(), idx++);
pItem->setTrack(track());
pItem->setParent(this);
pItem->readMusicXML(e, parentheses);
pItem->readMusicXML(e, parentheses, figureExtend);
if (figureExtend)
extend = true;
items.append(*pItem);
// add item normalized text
if(!normalizedText.isEmpty())
normalizedText.append('\n');
normalizedText.append(pItem->normalizedText());
}
else
else {
domError(e);
return false;
}
}
setText(normalizedText); // this is the text to show while editing
bool res = !normalizedText.isEmpty();
return res;
}

//---------------------------------------------------------
Expand All @@ -1547,15 +1562,17 @@ bool FiguredBass::hasParentheses() const
// Write MusicXML
//---------------------------------------------------------

void FiguredBass::writeMusicXML(Xml& xml) const
void FiguredBass::writeMusicXML(Xml& xml, bool doFigure, bool doExtend) const
{
QString stag = "figured-bass";
if (hasParentheses())
stag += " parentheses=\"yes\"";
xml.stag(stag);
foreach(FiguredBassItem item, items)
item.writeMusicXML(xml);
xml.etag();
if (doFigure || doExtend) {
QString stag = "figured-bass";
if (hasParentheses())
stag += " parentheses=\"yes\"";
xml.stag(stag);
foreach(FiguredBassItem item, items)
item.writeMusicXML(xml, doFigure, doExtend);
xml.etag();
}
}

//---------------------------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions libmscore/figuredbass.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ class FiguredBassItem : public Element {
virtual void write(Xml& xml) const;

// read / write MusicXML
void readMusicXML(const QDomElement& de, bool paren);
void writeMusicXML(Xml& xml) const;
void readMusicXML(const QDomElement& de, bool paren, bool& extend);
void writeMusicXML(Xml& xml, bool doFigure, bool doExtend) const;
bool startsWithParenthesis() const;

// specific API
Expand Down Expand Up @@ -255,8 +255,8 @@ class FiguredBass : public Text {
virtual void write(Xml& xml) const;

// read / write MusicXML
void readMusicXML(const QDomElement& de, int divisions);
void writeMusicXML(Xml& xml) const;
bool readMusicXML(const QDomElement& de, int divisions, bool& extend);
void writeMusicXML(Xml& xml, bool doFigure, bool doExtend) const;

//DEBUG
Q_INVOKABLE FiguredBassItem* addItem();
Expand Down
80 changes: 63 additions & 17 deletions mscore/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@
// #define DEBUG_REPEATS true
// #define DEBUG_TICK true

//---------------------------------------------------------
// typedefs
//---------------------------------------------------------

typedef QMap<int, const FiguredBass*> FigBassMap;

//---------------------------------------------------------
// attributes -- prints <attributes> tag when necessary
//---------------------------------------------------------
Expand Down Expand Up @@ -292,7 +298,6 @@ class ExportMusicXml {
void symbol(Symbol const* const sym, int staff);
void tempoText(TempoText const* const text, int staff);
void harmony(Harmony const* const);
void figuredBass(FiguredBass const* const);
};

//---------------------------------------------------------
Expand Down Expand Up @@ -3376,14 +3381,11 @@ static void annotations(ExportMusicXml* exp, int strack, int etrack, int track,
case Element::HARMONY:
exp->harmony(static_cast<const Harmony*>(e) /*, sstaff */);
break;
case Element::FIGURED_BASS:
exp->figuredBass(static_cast<const FiguredBass*>(e) /*, sstaff */);
break;
case Element::REHEARSAL_MARK:
exp->rehearsal(static_cast<const RehearsalMark*>(e), sstaff);
break;
case Element::JUMP:
// ignore
case Element::FIGURED_BASS: // handled separately by figuredBass()
case Element::JUMP: // ignore
break;
default:
qDebug("annotations: direction type %s at tick %d not implemented\n",
Expand All @@ -3395,6 +3397,58 @@ static void annotations(ExportMusicXml* exp, int strack, int etrack, int track,
}
}

//---------------------------------------------------------
// figuredBass
//---------------------------------------------------------

static void figuredBass(Xml& xml, int strack, int etrack, int track, const ChordRest* cr, FigBassMap& fbMap)
{
Segment* seg = cr->segment();
if (seg->subtype() == Segment::SegChordRest) {
foreach(const Element* e, seg->annotations()) {

int wtrack = -1; // track to write annotation

if (strack <= e->track() && e->track() < etrack)
wtrack = findTrackForAnnotations(e->track(), seg);

if (track == wtrack) {
if (e->type() == Element::FIGURED_BASS) {
const FiguredBass* fb = static_cast<const FiguredBass*>(e);
//qDebug("figuredbass() track %d seg %p fb %p seg %p tick %d ticks %d cr %p tick %d ticks %d",
// track, seg, fb, fb->segment(), fb->segment()->tick(), fb->ticks(), cr, cr->tick(), cr->actualTicks());
bool extend = fb->ticks() > cr->actualTicks();
if (extend) {
//qDebug("figuredbass() extend to %d + %d = %d",
// cr->tick(), fb->ticks(), cr->tick() + fb->ticks());
fbMap.insert(strack, fb);
}
else
fbMap.remove(strack);
fb->writeMusicXML(xml, true, extend);
// there can only be one FB, if one was found
// no extend can be pending
return;
}
}
}
// check for extend pending
if (fbMap.contains(strack)) {
const FiguredBass* fb = fbMap.value(strack);
int endTick = fb->segment()->tick() + fb->ticks();
if (cr->tick() < endTick) {
//qDebug("figuredbass() at tick %d extend only", cr->tick());
// write figured bass element with extend only
fb->writeMusicXML(xml, false, true);
}
if (endTick <= cr->tick() + cr->actualTicks()) {
//qDebug("figuredbass() at tick %d extend done", cr->tick() + cr->actualTicks());
fbMap.remove(strack);
}
}
}
}

//---------------------------------------------------------
// spannerStart
//---------------------------------------------------------
Expand Down Expand Up @@ -3733,6 +3787,8 @@ void ExportMusicXml::write(QIODevice* dev)
int irregularMeasureNo = 1; // number of next irregular measure
int pickupMeasureNo = 1; // number of next pickup measure

FigBassMap fbMap; // pending figure base extends

for (MeasureBase* mb = score->measures()->first(); mb; mb = mb->next()) {
if (mb->type() != Element::MEASURE)
continue;
Expand Down Expand Up @@ -4020,6 +4076,7 @@ void ExportMusicXml::write(QIODevice* dev)
if (el->isChordRest()) {
attr.doAttr(xml, false);
annotations(this, strack, etrack, st, sstaff, seg);
figuredBass(xml, strack, etrack, st, static_cast<const ChordRest*>(el), fbMap);
spannerStop(this, strack, etrack, st, sstaff, seg);
spannerStart(this, strack, etrack, st, sstaff, seg);
}
Expand Down Expand Up @@ -4203,17 +4260,6 @@ double ExportMusicXml::getTenthsFromDots(double dots)
return dots / MScore::DPMM / millimeters * tenths;
}


//---------------------------------------------------------
// figuredBass
//---------------------------------------------------------

void ExportMusicXml::figuredBass(FiguredBass const* const fb)
{
fb->writeMusicXML(xml);
}


//---------------------------------------------------------
// harmony
//---------------------------------------------------------
Expand Down
45 changes: 43 additions & 2 deletions mscore/importxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ void MusicXml::import(Score* s)
tremStart = 0;
hairpin = 0;
figBass = 0;
figBassExtend = false;

// TODO only if multi-measure rests used ???
// score->style()->set(ST_createMultiMeasureRests, true);
Expand Down Expand Up @@ -2367,8 +2368,15 @@ Measure* MusicXml::xmlMeasure(Part* part, QDomElement e, int number, int measure
}
else {
// read figured bass element to attach to next note
figBassExtend = false;
bool mustkeep = false;
figBass = new FiguredBass(score);
figBass->readMusicXML(e, divisions);
mustkeep = figBass->readMusicXML(e, divisions, figBassExtend);
// qDebug("xmlMeaure: fb mustkeep %d extend %d", mustkeep, figBassExtend);
if (!mustkeep) {
delete figBass;
figBass = 0;
}
}
}
else
Expand Down Expand Up @@ -4551,6 +4559,31 @@ static void handleBeamAndStemDir(ChordRest* cr, const BeamMode bm, const MScore:
}


//---------------------------------------------------------
// findLastFiguredBass
//---------------------------------------------------------

/**
* Find last figured bass on \a track before \a seg
*/

static FiguredBass* findLastFiguredBass(int track, Segment* seg)
{
// qDebug("findLastFiguredBass(track %d seg %p)", track, seg);
while ((seg = seg->prev1(Segment::SegChordRest))) {
// qDebug("findLastFiguredBass seg %p", seg);
foreach(Element* e, seg->annotations()) {
if (e->track() == track && e->type() == Element::FIGURED_BASS) {
FiguredBass* fb = static_cast<FiguredBass*>(e);
// qDebug("findLastFiguredBass found fb %p at seg %p", fb, seg);
return fb;
}
}
}
return 0;
}


//---------------------------------------------------------
// xmlNote
//---------------------------------------------------------
Expand Down Expand Up @@ -5039,7 +5072,7 @@ void MusicXml::xmlNote(Measure* measure, int staff, const QString& partId, QDomE

// add figured bass element
if (figBass) {
qDebug("add figured bass %p at tick %d ticks %d trk %d", figBass, tick, ticks, trk);
// qDebug("add figured bass %p at tick %d ticks %d trk %d", figBass, tick, ticks, trk);
figBass->setTrack(trk);
figBass->setTicks(ticks);
// TODO: set correct onNote value
Expand All @@ -5048,6 +5081,14 @@ void MusicXml::xmlNote(Measure* measure, int staff, const QString& partId, QDomE
s->add(figBass);
figBass = 0;
}
else if (figBassExtend) {
// extend last figured bass to end of this chord
// qDebug("extend figured bass at tick %d ticks %d trk %d end %d", tick, ticks, trk, tick + ticks);
FiguredBass* fb = findLastFiguredBass((trk / VOICES) * VOICES, cr->segment());
if (fb)
fb->setTicks(tick + ticks - fb->segment()->tick());
}
figBassExtend = false;

if (!chord)
prevtick = tick; // remember tick where last chordrest was inserted
Expand Down
1 change: 1 addition & 0 deletions mscore/musicxml.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ class MusicXml {
Hairpin* hairpin; ///< Current hairpin (obsoletes wedgelist)
Chord* tremStart; ///< Starting chord for current tremolo
FiguredBass* figBass; ///< Current figured bass element (to attach to next note)
bool figBassExtend; ///< Current figured bass extend
BeamMode beamMode; ///< Current beam mode
Beam* beam; ///< Current beam mode

Expand Down
Loading

0 comments on commit 1fa8c41

Please sign in to comment.