//============================================================================= // MuseScore // Music Composition & Notation // // Copyright (C) 2016 Werner Schweer and others // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 // as published by the Free Software Foundation and appearing in // the file LICENSE.GPL //============================================================================= #include "xml.h" #include "score.h" #include "staff.h" #include "revisions.h" #include "part.h" #include "page.h" #include "style.h" #include "sym.h" #include "audio.h" #include "sig.h" #include "barline.h" #include "excerpt.h" #include "spanner.h" #ifdef OMR #include "omr/omr.h" #include "omr/omrpage.h" #endif namespace Ms { //--------------------------------------------------------- // read // return false on error //--------------------------------------------------------- bool Score::read(XmlReader& e) { while (e.readNextStartElement()) { e.setTrack(-1); const QStringRef& tag(e.name()); if (tag == "Staff") readStaff(e); else if (tag == "Omr") { #ifdef OMR masterScore()->setOmr(new Omr(this)); masterScore()->omr()->read(e); #else e.skipCurrentElement(); #endif } else if (tag == "Audio") { _audio = new Audio; _audio->read(e); } else if (tag == "showOmr") masterScore()->setShowOmr(e.readInt()); else if (tag == "playMode") _playMode = PlayMode(e.readInt()); else if (tag == "LayerTag") { int id = e.intAttribute("id"); const QString& tag = e.attribute("tag"); QString val(e.readElementText()); if (id >= 0 && id < 32) { _layerTags[id] = tag; _layerTagComments[id] = val; } } else if (tag == "Layer") { Layer layer; layer.name = e.attribute("name"); layer.tags = e.attribute("mask").toUInt(); _layer.append(layer); e.readNext(); } else if (tag == "currentLayer") _currentLayer = e.readInt(); else if (tag == "Synthesizer") _synthesizerState.read(e); else if (tag == "Division") _fileDivision = e.readInt(); else if (tag == "showInvisible") _showInvisible = e.readInt(); else if (tag == "showUnprintable") _showUnprintable = e.readInt(); else if (tag == "showFrames") _showFrames = e.readInt(); else if (tag == "showMargins") _showPageborders = e.readInt(); else if (tag == "Style") { qreal sp = style().value(StyleIdx::spatium).toDouble(); style().load(e); // if (_layoutMode == LayoutMode::FLOAT || _layoutMode == LayoutMode::SYSTEM) { if (_layoutMode == LayoutMode::FLOAT) { // style should not change spatium in // float mode style().set(StyleIdx::spatium, sp); } _scoreFont = ScoreFont::fontFactory(style().value(StyleIdx::MusicalSymbolFont).toString()); } else if (tag == "copyright" || tag == "rights") { Text* text = new Text(this); text->read(e); setMetaTag("copyright", text->xmlText()); delete text; } else if (tag == "movement-number") setMetaTag("movementNumber", e.readElementText()); else if (tag == "movement-title") setMetaTag("movementTitle", e.readElementText()); else if (tag == "work-number") setMetaTag("workNumber", e.readElementText()); else if (tag == "work-title") setMetaTag("workTitle", e.readElementText()); else if (tag == "source") setMetaTag("source", e.readElementText()); else if (tag == "metaTag") { QString name = e.attribute("name"); setMetaTag(name, e.readElementText()); } else if (tag == "Part") { Part* part = new Part(this); part->read(e); _parts.push_back(part); } else if ((tag == "HairPin") || (tag == "Ottava") || (tag == "TextLine") || (tag == "Volta") || (tag == "Trill") || (tag == "Slur") || (tag == "Pedal")) { Spanner* s = static_cast(Element::name2Element(tag, this)); s->read(e); addSpanner(s); } else if (tag == "Excerpt") { if (MScore::noExcerpts) e.skipCurrentElement(); else { if (isMaster()) { Excerpt* ex = new Excerpt(static_cast(this)); ex->read(e); excerpts().append(ex); } else { qDebug("Score::read(): part cannot have parts"); e.skipCurrentElement(); } } } else if (e.name() == "Tracklist") { int strack = e.intAttribute("sTrack", -1); int dtrack = e.intAttribute("dstTrack", -1); if (strack != -1 && dtrack != -1) e.tracks().insert(strack, dtrack); e.skipCurrentElement(); } else if (tag == "Score") { // recursion if (MScore::noExcerpts) e.skipCurrentElement(); else { e.tracks().clear(); // ??? MasterScore* m = masterScore(); Score* s = new Score(m); Excerpt* ex = new Excerpt(m); ex->setPartScore(s); ex->setTracks(e.tracks()); e.setLastMeasure(nullptr); s->read(e); m->addExcerpt(ex); } } else if (tag == "name") { QString n = e.readElementText(); if (!isMaster()) //ignore the name if it's not a child score excerpt()->setTitle(n); } else if (tag == "layoutMode") { QString s = e.readElementText(); if (s == "line") _layoutMode = LayoutMode::LINE; else if (s == "system") _layoutMode = LayoutMode::SYSTEM; else qDebug("layoutMode: %s", qPrintable(s)); } else e.unknown(); } if (e.error() != QXmlStreamReader::NoError) { qDebug("%s: xml read error at line %lld col %lld: %s", qPrintable(e.getDocName()), e.lineNumber(), e.columnNumber(), e.name().toUtf8().data()); MScore::lastError = QObject::tr("XML read error at line %1 column %2: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg(e.name().toString()); return false; } connectTies(); _fileDivision = MScore::division; #if 0 // TODO:barline // // sanity check for barLineSpan // for (Staff* st : staves()) { int barLineSpan = st->barLineSpan(); int idx = st->idx(); int n = nstaves(); if (idx + barLineSpan > n) { qDebug("bad span: idx %d span %d staves %d", idx, barLineSpan, n); // span until last staff barLineSpan = n - idx; st->setBarLineSpan(barLineSpan); } else if (idx == 0 && barLineSpan == 0) { qDebug("bad span: idx %d span %d staves %d", idx, barLineSpan, n); // span from the first staff until the start of the next span barLineSpan = 1; for (int i = 1; i < n; ++i) { if (staff(i)->barLineSpan() == 0) ++barLineSpan; else break; } st->setBarLineSpan(barLineSpan); } // check spanFrom int minBarLineFrom = st->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : MIN_BARLINE_SPAN_FROMTO; if (st->barLineFrom() < minBarLineFrom) st->setBarLineFrom(minBarLineFrom); if (st->barLineFrom() > st->lines(0) * 2) st->setBarLineFrom(st->lines(0) * 2); // check spanTo Staff* stTo = st->barLineSpan() <= 1 ? st : staff(idx + st->barLineSpan() - 1); // 1-line staves have special bar line spans int maxBarLineTo = stTo->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_TO : stTo->lines(0) * 2; if (st->barLineTo() < MIN_BARLINE_SPAN_FROMTO) st->setBarLineTo(MIN_BARLINE_SPAN_FROMTO); if (st->barLineTo() > maxBarLineTo) st->setBarLineTo(maxBarLineTo); // on single staff span, check spanFrom and spanTo are distant enough if (st->barLineSpan() == 1) { if (st->barLineTo() - st->barLineFrom() < MIN_BARLINE_FROMTO_DIST) { st->setBarLineFrom(0); st->setBarLineTo(0); } } } #endif if (!masterScore()->omr()) masterScore()->setShowOmr(false); fixTicks(); masterScore()->rebuildMidiMapping(); masterScore()->updateChannel(); createPlayEvents(); return true; } //--------------------------------------------------------- // read //--------------------------------------------------------- bool MasterScore::read(XmlReader& e) { if (!Score::read(e)) return false; int id = 1; for (LinkedElements* le : e.linkIds()) le->setLid(this, id++); for (Staff* s : staves()) s->updateOttava(); setCreated(false); return true; } //--------------------------------------------------------- // addMovement //--------------------------------------------------------- void MasterScore::addMovement(MasterScore* score) { score->_movements = _movements; _movements->push_back(score); MasterScore* ps = 0; for (MasterScore* s : *_movements) { s->setPrev(ps); if (ps) ps->setNext(s); s->setNext(0); ps = s; } } //--------------------------------------------------------- // read300 //--------------------------------------------------------- Score::FileError MasterScore::read300(XmlReader& e) { bool top = true; while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "programVersion") { setMscoreVersion(e.readElementText()); parseVersion(mscoreVersion()); } else if (tag == "programRevision") setMscoreRevision(e.readIntHex()); else if (tag == "Score") { MasterScore* score; if (top) { score = this; top = false; } else { score = new MasterScore(); addMovement(score); } if (!score->read(e)) return FileError::FILE_BAD_FORMAT; } else if (tag == "Revision") { Revision* revision = new Revision; revision->read(e); revisions()->add(revision); } } return FileError::FILE_NO_ERROR; } }