1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2016 Werner Schweer and others
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2
9 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENSE.GPL
11 //=============================================================================
12 
13 #include "xml.h"
14 #include "score.h"
15 #include "staff.h"
16 #include "revisions.h"
17 #include "part.h"
18 #include "page.h"
19 #include "style.h"
20 #include "sym.h"
21 #include "audio.h"
22 #include "sig.h"
23 #include "barline.h"
24 #include "excerpt.h"
25 #include "spanner.h"
26 #include "scoreOrder.h"
27 #include "measurebase.h"
28 
29 #ifdef OMR
30 #include "omr/omr.h"
31 #include "omr/omrpage.h"
32 #endif
33 
34 namespace Ms {
35 
36 //---------------------------------------------------------
37 //   read
38 //    return false on error
39 //---------------------------------------------------------
40 
read(XmlReader & e)41 bool Score::read(XmlReader& e)
42       {
43       // HACK
44       // style setting compatibility settings for minor versions
45       // this allows new style settings to be added
46       // with different default values for older vs newer scores
47       // note: older templates get the default values for older scores
48       // these can be forced back in MuseScore::getNewFile() if necessary
49       QString programVersion = masterScore()->mscoreVersion();
50       bool disableHarmonyPlay = MScore::harmonyPlayDisableCompatibility && !MScore::testMode;
51       if (!programVersion.isEmpty() && programVersion < "3.5" && disableHarmonyPlay) {
52             style().set(Sid::harmonyPlay, false);
53             }
54 
55       ScoreOrder* order { nullptr };
56       while (e.readNextStartElement()) {
57             e.setTrack(-1);
58             const QStringRef& tag(e.name());
59             if (tag == "Staff")
60                   readStaff(e);
61             else if (tag == "Omr") {
62 #ifdef OMR
63                   masterScore()->setOmr(new Omr(this));
64                   masterScore()->omr()->read(e);
65 #else
66                   e.skipCurrentElement();
67 #endif
68                   }
69             else if (tag == "Audio") {
70                   _audio = new Audio;
71                   _audio->read(e);
72                   }
73             else if (tag == "showOmr")
74                   masterScore()->setShowOmr(e.readInt());
75             else if (tag == "playMode")
76                   _playMode = PlayMode(e.readInt());
77             else if (tag == "LayerTag") {
78                   int id = e.intAttribute("id");
79                   const QString& t = e.attribute("tag");
80                   QString val(e.readElementText());
81                   if (id >= 0 && id < 32) {
82                         _layerTags[id] = t;
83                         _layerTagComments[id] = val;
84                         }
85                   }
86             else if (tag == "Layer") {
87                   Layer layer;
88                   layer.name = e.attribute("name");
89                   layer.tags = e.attribute("mask").toUInt();
90                   _layer.append(layer);
91                   e.readNext();
92                   }
93             else if (tag == "currentLayer")
94                   _currentLayer = e.readInt();
95             else if (tag == "Synthesizer")
96                   _synthesizerState.read(e);
97             else if (tag == "page-offset")
98                   _pageNumberOffset = e.readInt();
99             else if (tag == "Division")
100                   _fileDivision = e.readInt();
101             else if (tag == "showInvisible")
102                   _showInvisible = e.readInt();
103             else if (tag == "showUnprintable")
104                   _showUnprintable = e.readInt();
105             else if (tag == "showFrames")
106                   _showFrames = e.readInt();
107             else if (tag == "showMargins")
108                   _showPageborders = e.readInt();
109             else if (tag == "markIrregularMeasures")
110                   _markIrregularMeasures = e.readInt();
111             else if (tag == "Style") {
112                   qreal sp = style().value(Sid::spatium).toDouble();
113                   style().load(e);
114                   // if (_layoutMode == LayoutMode::FLOAT || _layoutMode == LayoutMode::SYSTEM) {
115                   if (_layoutMode == LayoutMode::FLOAT) {
116                         // style should not change spatium in
117                         // float mode
118                         style().set(Sid::spatium, sp);
119                         }
120                   _scoreFont = ScoreFont::fontFactory(style().value(Sid::MusicalSymbolFont).toString());
121                   }
122             else if (tag == "copyright" || tag == "rights") {
123                   Text* text = new Text(this);
124                   text->read(e);
125                   setMetaTag("copyright", text->xmlText());
126                   delete text;
127                   }
128             else if (tag == "movement-number")
129                   setMetaTag("movementNumber", e.readElementText());
130             else if (tag == "movement-title")
131                   setMetaTag("movementTitle", e.readElementText());
132             else if (tag == "work-number")
133                   setMetaTag("workNumber", e.readElementText());
134             else if (tag == "work-title")
135                   setMetaTag("workTitle", e.readElementText());
136             else if (tag == "source")
137                   setMetaTag("source", e.readElementText());
138             else if (tag == "metaTag") {
139                   QString name = e.attribute("name");
140                   setMetaTag(name, e.readElementText());
141                   }
142             else if (tag == "Order") {
143                   order = new ScoreOrder(e.attribute("id"));
144                   order->read(e);
145                   }
146             else if (tag == "Part") {
147                   Part* part = new Part(this);
148                   part->read(e);
149                   _parts.push_back(part);
150                   }
151             else if ((tag == "HairPin")
152                 || (tag == "Ottava")
153                 || (tag == "TextLine")
154                 || (tag == "Volta")
155                 || (tag == "Trill")
156                 || (tag == "Slur")
157                 || (tag == "Pedal")) {
158                   Spanner* s = toSpanner(Element::name2Element(tag, this));
159                   s->read(e);
160                   addSpanner(s);
161                   }
162             else if (tag == "Excerpt") {
163                   if (MScore::noExcerpts)
164                         e.skipCurrentElement();
165                   else {
166                         if (isMaster()) {
167                               Excerpt* ex = new Excerpt(static_cast<MasterScore*>(this));
168                               ex->read(e);
169                               excerpts().append(ex);
170                               }
171                         else {
172                               qDebug("Score::read(): part cannot have parts");
173                               e.skipCurrentElement();
174                               }
175                         }
176                   }
177             else if (e.name() == "Tracklist") {
178                   int strack = e.intAttribute("sTrack",   -1);
179                   int dtrack = e.intAttribute("dstTrack", -1);
180                   if (strack != -1 && dtrack != -1)
181                         e.tracks().insert(strack, dtrack);
182                   e.skipCurrentElement();
183                   }
184             else if (tag == "Score") {          // recursion
185                   if (MScore::noExcerpts)
186                         e.skipCurrentElement();
187                   else {
188                         e.tracks().clear();     // ???
189                         MasterScore* m = masterScore();
190                         Score* s       = new Score(m, m->style());
191                         Excerpt* ex    = new Excerpt(m);
192 
193                         ex->setPartScore(s);
194                         e.setLastMeasure(nullptr);
195                         s->read(e);
196                         s->linkMeasures(m);
197                         ex->setTracks(e.tracks());
198                         m->addExcerpt(ex);
199                         }
200                   }
201             else if (tag == "name") {
202                   QString n = e.readElementText();
203                   if (!isMaster()) //ignore the name if it's not a child score
204                         excerpt()->setTitle(n);
205                   }
206             else if (tag == "layoutMode") {
207                   QString s = e.readElementText();
208                   if (s == "line")
209                         _layoutMode = LayoutMode::LINE;
210                   else if (s == "system")
211                         _layoutMode = LayoutMode::SYSTEM;
212                   else
213                         qDebug("layoutMode: %s", qPrintable(s));
214                   }
215             else
216                   e.unknown();
217             }
218       e.reconnectBrokenConnectors();
219       if (e.error() != QXmlStreamReader::NoError) {
220             qDebug("%s: xml read error at line %lld col %lld: %s",
221                qPrintable(e.getDocName()), e.lineNumber(), e.columnNumber(),
222                e.name().toUtf8().data());
223             if (e.error() == QXmlStreamReader::CustomError)
224                   MScore::lastError = e.errorString();
225             else
226                   MScore::lastError = QObject::tr("XML read error at line %1, column %2: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg(e.name().toString());
227             return false;
228             }
229 
230       connectTies();
231 
232       _fileDivision = MScore::division;
233 
234 #if 0 // TODO:barline
235       //
236       //    sanity check for barLineSpan
237       //
238       for (Staff* st : staves()) {
239             int barLineSpan = st->barLineSpan();
240             int idx = st->idx();
241             int n   = nstaves();
242             if (idx + barLineSpan > n) {
243                   qDebug("bad span: idx %d  span %d staves %d", idx, barLineSpan, n);
244                   // span until last staff
245                   barLineSpan = n - idx;
246                   st->setBarLineSpan(barLineSpan);
247                   }
248             else if (idx == 0 && barLineSpan == 0) {
249                   qDebug("bad span: idx %d  span %d staves %d", idx, barLineSpan, n);
250                   // span from the first staff until the start of the next span
251                   barLineSpan = 1;
252                   for (int i = 1; i < n; ++i) {
253                         if (staff(i)->barLineSpan() == 0)
254                               ++barLineSpan;
255                         else
256                               break;
257                         }
258                   st->setBarLineSpan(barLineSpan);
259                   }
260             // check spanFrom
261             int minBarLineFrom = st->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : MIN_BARLINE_SPAN_FROMTO;
262             if (st->barLineFrom() < minBarLineFrom)
263                   st->setBarLineFrom(minBarLineFrom);
264             if (st->barLineFrom() > st->lines(0) * 2)
265                   st->setBarLineFrom(st->lines(0) * 2);
266             // check spanTo
267             Staff* stTo = st->barLineSpan() <= 1 ? st : staff(idx + st->barLineSpan() - 1);
268             // 1-line staves have special bar line spans
269             int maxBarLineTo        = stTo->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_TO : stTo->lines(0) * 2;
270             if (st->barLineTo() < MIN_BARLINE_SPAN_FROMTO)
271                   st->setBarLineTo(MIN_BARLINE_SPAN_FROMTO);
272             if (st->barLineTo() > maxBarLineTo)
273                   st->setBarLineTo(maxBarLineTo);
274             // on single staff span, check spanFrom and spanTo are distant enough
275             if (st->barLineSpan() == 1) {
276                   if (st->barLineTo() - st->barLineFrom() < MIN_BARLINE_FROMTO_DIST) {
277                         st->setBarLineFrom(0);
278                         st->setBarLineTo(0);
279                         }
280                   }
281             }
282 #endif
283       // Make sure every instrument has an instrumentId set.
284       for (Part* part : parts()) {
285             const InstrumentList* il = part->instruments();
286             for (auto it = il->begin(); it != il->end(); it++)
287                   static_cast<Instrument*>(it->second)->updateInstrumentId();
288             }
289       if (order) {
290             ScoreOrder* defined = scoreOrders.findByName(order->getName());
291             if (defined)
292                   {
293                   if (defined->isScoreOrder(this)) {
294                         // The order in the score file matches a score order
295                         // which is already defined so use that order.
296                         setScoreOrder(defined);
297                         delete order;
298                         }
299                   else {
300                         // The order in the score file is already defined in the score order
301                         // but the order is of the instruments is not the same so use the
302                         // order as a customized version of the already defined order.
303                         scoreOrders.addScoreOrder(order);
304                         setScoreOrder(order);
305                         }
306                   }
307             else {
308                   defined = scoreOrders.findById(order->getId());
309                   if (defined) {
310                         // The order in the score file is already available, resuse it.
311                         setScoreOrder(defined);
312                         delete order;
313                         }
314                   else {
315                         // The order in the score file is new, add it to the score orders.
316                         scoreOrders.addScoreOrder(order);
317                         setScoreOrder(order);
318                         }
319                   }
320             }
321 
322       if (!masterScore()->omr())
323             masterScore()->setShowOmr(false);
324 
325       fixTicks();
326 
327       for (Part* p : qAsConst(_parts)) {
328             p->updateHarmonyChannels(false);
329             }
330 
331       masterScore()->rebuildMidiMapping();
332       masterScore()->updateChannel();
333 
334 //      createPlayEvents();
335       return true;
336       }
337 
338 //---------------------------------------------------------
339 // linkMeasures
340 //---------------------------------------------------------
341 
linkMeasures(Score * score)342 void Score::linkMeasures(Score* score)
343       {
344       MeasureBase *mbMaster = score->first();
345       for (MeasureBase* mb = first(); mb; mb = mb->next()) {
346             if (!mb->isMeasure())
347                   continue;
348             while (mbMaster && !mbMaster->isMeasure())
349                   mbMaster = mbMaster->next();
350             if (!mbMaster) {
351                   qDebug("Measures in MasterScore and Score are not in sync.");
352                   break;
353                   }
354             mb->linkTo(mbMaster);
355             mbMaster = mbMaster->next();
356             }
357       }
358 
359 //---------------------------------------------------------
360 //   read
361 //---------------------------------------------------------
362 
read(XmlReader & e)363 bool MasterScore::read(XmlReader& e)
364       {
365       if (!Score::read(e))
366             return false;
367       for (Staff* s : staves())
368             s->updateOttava();
369       setCreated(false);
370       return true;
371       }
372 
373 //---------------------------------------------------------
374 //   addMovement
375 //---------------------------------------------------------
376 
addMovement(MasterScore * score)377 void MasterScore::addMovement(MasterScore* score)
378       {
379       score->_movements = _movements;
380       _movements->push_back(score);
381       MasterScore* ps = 0;
382       for (MasterScore* s : *_movements) {
383             s->setPrev(ps);
384             if (ps)
385                   ps->setNext(s);
386             s->setNext(0);
387             ps = s;
388             }
389       }
390 
391 //---------------------------------------------------------
392 //   read301
393 //---------------------------------------------------------
394 
read302(XmlReader & e)395 Score::FileError MasterScore::read302(XmlReader& e)
396       {
397       bool top = true;
398       while (e.readNextStartElement()) {
399             const QStringRef& tag(e.name());
400             if (tag == "programVersion") {
401                   setMscoreVersion(e.readElementText());
402                   parseVersion(mscoreVersion());
403                   }
404             else if (tag == "programRevision")
405                   setMscoreRevision(e.readIntHex());
406             else if (tag == "Score") {
407                   MasterScore* score;
408                   if (top) {
409                         score = this;
410                         top   = false;
411                         }
412                   else {
413                         score = new MasterScore();
414                         score->setMscVersion(mscVersion());
415                         addMovement(score);
416                         }
417                   if (!score->read(e)) {
418                         if (e.error() == QXmlStreamReader::CustomError)
419                               return FileError::FILE_CRITICALLY_CORRUPTED;
420                         return FileError::FILE_BAD_FORMAT;
421                         }
422                   }
423             else if (tag == "Revision") {
424                   Revision* revision = new Revision;
425                   revision->read(e);
426                   revisions()->add(revision);
427                   }
428             }
429       return FileError::FILE_NO_ERROR;
430       }
431 
styleDefaults301()432 MStyle* styleDefaults301()
433       {
434       static MStyle* result = nullptr;
435 
436       if (result)
437             return result;
438 
439       result = new MStyle();
440 
441       QFile baseDefaults(":/styles/legacy-style-defaults-v3.mss");
442 
443       if (!baseDefaults.open(QIODevice::ReadOnly))
444             return result;
445 
446       result->load(&baseDefaults);
447 
448       return result;
449       }
450 }
451 
452