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