Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "measurerw.h"
23 :
24 : #include "translation.h"
25 :
26 : #include "../dom/ambitus.h"
27 : #include "../dom/barline.h"
28 : #include "../dom/beam.h"
29 : #include "../dom/breath.h"
30 : #include "../dom/chord.h"
31 : #include "../dom/dynamic.h"
32 : #include "../dom/expression.h"
33 : #include "../dom/factory.h"
34 : #include "../dom/instrchange.h"
35 : #include "../dom/fermata.h"
36 : #include "../dom/fret.h"
37 : #include "../dom/keysig.h"
38 : #include "../dom/location.h"
39 : #include "../dom/measure.h"
40 : #include "../dom/measurenumber.h"
41 : #include "../dom/measurerepeat.h"
42 : #include "../dom/mmrest.h"
43 : #include "../dom/mmrestrange.h"
44 : #include "../dom/part.h"
45 : #include "../dom/score.h"
46 : #include "../dom/segment.h"
47 : #include "../dom/spacer.h"
48 : #include "../dom/staff.h"
49 : #include "../dom/stafflines.h"
50 : #include "../dom/stafftext.h"
51 : #include "../dom/system.h"
52 : #include "../dom/systemdivider.h"
53 : #include "../dom/timesig.h"
54 : #include "../dom/tuplet.h"
55 : #include "../dom/harmony.h"
56 : #include "../dom/fret.h"
57 : #include "../dom/tremolobar.h"
58 : #include "../dom/tempotext.h"
59 : #include "../dom/image.h"
60 : #include "../editing/transpose.h"
61 :
62 : #include "tread.h"
63 :
64 : #include "log.h"
65 :
66 : using namespace mu::engraving;
67 : using namespace mu::engraving::read400;
68 : using namespace mu::engraving::write;
69 :
70 5112 : void MeasureRead::readMeasure(Measure* measure, XmlReader& e, ReadContext& ctx, int staffIdx)
71 : {
72 5112 : IF_ASSERT_FAILED(ctx.isSameScore(measure)) {
73 0 : return;
74 : }
75 :
76 5112 : ctx.setCurrentMeasure(measure);
77 5112 : int nextTrack = staffIdx * VOICES;
78 5112 : ctx.setTrack(nextTrack);
79 :
80 5112 : for (int n = int(measure->mstaves().size()); n <= staffIdx; ++n) {
81 0 : Staff* staff = ctx.staff(n);
82 0 : MStaff* s = new MStaff;
83 0 : s->setLines(Factory::createStaffLines(measure));
84 0 : s->lines()->setTrack(n * VOICES);
85 0 : s->lines()->setVisible(!staff->isLinesInvisible(measure->tick()));
86 0 : measure->mstaves().push_back(s);
87 : }
88 :
89 5112 : bool irregular = false;
90 5112 : if (e.hasAttribute("len")) {
91 43 : bool ok = true;
92 43 : measure->setTicks(Fraction::fromString(e.attribute("len"), &ok));
93 43 : if (!ok || measure->ticks() < Fraction(1, 128)) {
94 0 : e.raiseError(muse::mtrc("engraving", "MSCX error at byte offset %1: invalid measure length: %2")
95 0 : .arg(e.byteOffset()).arg(e.attribute("len")));
96 0 : return;
97 : }
98 43 : irregular = true;
99 43 : ctx.compatTimeSigMap()->add(measure->tick().ticks(), SigEvent(measure->ticks(), measure->timesig()));
100 43 : ctx.compatTimeSigMap()->add(measure->endTick().ticks(), SigEvent(measure->timesig()));
101 : }
102 :
103 11321 : while (e.readNextStartElement()) {
104 6209 : const AsciiStringView tag(e.name());
105 :
106 6209 : if (tag == "voice") {
107 5310 : ctx.setTrack(nextTrack++);
108 5310 : ctx.setTick(measure->tick());
109 5310 : readVoice(measure, e, ctx, staffIdx, irregular);
110 899 : } else if (tag == "Marker" || tag == "Jump") {
111 158 : EngravingItem* el = Factory::createItemByName(tag, measure);
112 158 : el->setTrack(ctx.track());
113 158 : TRead::readItem(el, e, ctx);
114 158 : if (el->systemFlag() && el->isTopSystemObject()) {
115 158 : el->setTrack(0); // original system object always goes on top
116 : }
117 158 : measure->add(el);
118 741 : } else if (tag == "stretch") {
119 0 : if (measure->score()->mscVersion() < 400) {
120 : // Ignore measure stretch pre 4.0
121 0 : e.skipCurrentElement();
122 : } else {
123 0 : double val = e.readDouble();
124 0 : if (val < 0.0) {
125 0 : val = 0;
126 : }
127 0 : measure->setUserStretch(val);
128 : }
129 741 : } else if (tag == "noOffset") {
130 0 : measure->setMeasureNumberOffset(e.readInt());
131 741 : } else if (tag == "measureNumberMode") {
132 0 : measure->setMeasureNumberMode(MeasureNumberMode(e.readInt()));
133 741 : } else if (tag == "irregular") {
134 1 : measure->setExcludeFromNumbering(e.readBool());
135 740 : } else if (tag == "breakMultiMeasureRest") {
136 25 : measure->setBreakMultiMeasureRest(e.readBool());
137 715 : } else if (tag == "startRepeat") {
138 68 : measure->setRepeatStart(true);
139 68 : e.readNext();
140 647 : } else if (tag == "endRepeat") {
141 106 : measure->setRepeatCount(e.readInt());
142 106 : measure->setRepeatEnd(true);
143 541 : } else if (tag == "vspacer" || tag == "vspacerDown") {
144 0 : if (!measure->mstaves()[staffIdx]->vspacerDown()) {
145 0 : Spacer* spacer = Factory::createSpacer(measure);
146 0 : spacer->setSpacerType(SpacerType::DOWN);
147 0 : spacer->setTrack(staffIdx * VOICES);
148 0 : measure->add(spacer);
149 : }
150 0 : measure->mstaves()[staffIdx]->vspacerDown()->setGap(Spatium(e.readDouble()));
151 541 : } else if (tag == "vspacerFixed") {
152 0 : if (!measure->mstaves()[staffIdx]->vspacerDown()) {
153 0 : Spacer* spacer = Factory::createSpacer(measure);
154 0 : spacer->setSpacerType(SpacerType::FIXED);
155 0 : spacer->setTrack(staffIdx * VOICES);
156 0 : measure->add(spacer);
157 : }
158 0 : measure->mstaves()[staffIdx]->vspacerDown()->setGap(Spatium(e.readDouble()));
159 541 : } else if (tag == "vspacerUp") {
160 0 : if (!measure->mstaves()[staffIdx]->vspacerUp()) {
161 0 : Spacer* spacer = Factory::createSpacer(measure);
162 0 : spacer->setSpacerType(SpacerType::UP);
163 0 : spacer->setTrack(staffIdx * VOICES);
164 0 : measure->add(spacer);
165 : }
166 0 : measure->mstaves()[staffIdx]->vspacerUp()->setGap(Spatium(e.readDouble()));
167 541 : } else if (tag == "visible") {
168 0 : measure->mstaves()[staffIdx]->setVisible(e.readInt());
169 541 : } else if ((tag == "slashStyle") || (tag == "stemless")) {
170 0 : measure->mstaves()[staffIdx]->setStemless(e.readInt());
171 541 : } else if (tag == "measureRepeatCount") {
172 23 : measure->setMeasureRepeatCount(e.readInt(), staffIdx);
173 518 : } else if (tag == "SystemDivider") {
174 0 : SystemDivider* sd = new SystemDivider(ctx.dummy());
175 0 : TRead::read(sd, e, ctx);
176 : //! TODO Looks like a bug.
177 : //! The SystemDivider parent must be System
178 : //! there is a method: `System* system() const { return (System*)parent(); }`,
179 : //! but when we add it to Measure, the parent will be rewritten.
180 0 : measure->add(sd);
181 518 : } else if (tag == "multiMeasureRest") {
182 30 : measure->setMMRestCount(e.readInt());
183 : // set tick to previous measure
184 30 : measure->setTick(ctx.lastMeasure()->tick());
185 30 : ctx.setTick(ctx.lastMeasure()->tick());
186 488 : } else if (tag == "MeasureNumber") {
187 1 : MeasureNumber* noText = new MeasureNumber(measure);
188 1 : TRead::read(noText, e, ctx);
189 1 : noText->setTrack(ctx.track());
190 1 : measure->add(noText);
191 487 : } else if (tag == "MMRestRange") {
192 0 : MMRestRange* range = new MMRestRange(measure);
193 0 : TRead::read(range, e, ctx);
194 0 : range->setTrack(ctx.track());
195 0 : measure->add(range);
196 487 : } else if (TRead::readProperties(static_cast<MeasureBase*>(measure), e, ctx)) {
197 : } else {
198 0 : e.unknown();
199 : }
200 : }
201 5112 : ctx.checkConnectors();
202 5112 : if (measure->isMMRest()) {
203 30 : Measure* lm = ctx.lastMeasure();
204 30 : ctx.setTick(lm->endTick());
205 : }
206 5112 : ctx.setCurrentMeasure(nullptr);
207 :
208 5112 : measure->connectTremolo();
209 : }
210 :
211 5310 : void MeasureRead::readVoice(Measure* measure, XmlReader& e, ReadContext& ctx, int staffIdx, bool irregular)
212 : {
213 5310 : Segment* segment = nullptr;
214 5310 : std::vector<Chord*> graceNotes;
215 5310 : Beam* startingBeam = nullptr;
216 5310 : Tuplet* tuplet = nullptr;
217 5310 : Fermata* fermata = nullptr;
218 :
219 5310 : Staff* staff = ctx.staff(staffIdx);
220 5310 : Fraction timeStretch(staff->timeStretch(measure->tick()));
221 :
222 22383 : while (e.readNextStartElement()) {
223 17073 : const AsciiStringView tag(e.name());
224 :
225 17073 : if (tag == "location") {
226 81 : Location loc = Location::relative();
227 81 : TRead::read(&loc, e, ctx);
228 81 : ctx.setLocation(loc);
229 16992 : } else if (tag == "tick") { // obsolete?
230 0 : LOGD() << "read midi tick";
231 0 : ctx.setTick(Fraction::fromTicks(ctx.fileDivision(e.readInt())));
232 16992 : } else if (tag == "BarLine") {
233 752 : BarLine* barLine = Factory::createBarLine(ctx.dummy());
234 752 : barLine->setTrack(ctx.track());
235 752 : TRead::read(barLine, e, ctx);
236 : //
237 : // StartRepeatBarLine: at rtick == 0, always BarLineType::START_REPEAT
238 : // BarLine: in the middle of a measure, has no semantic
239 : // EndBarLine: at the end of a measure
240 : // BeginBarLine: first segment of a measure, systemic barline
241 :
242 752 : SegmentType st = SegmentType::Invalid;
243 752 : Fraction t = ctx.tick() - measure->tick();
244 752 : if (t.isNotZero() && (t != measure->ticks())) {
245 3 : st = SegmentType::BarLine;
246 749 : } else if (barLine->barLineType() == BarLineType::START_REPEAT && t.isZero()) {
247 10 : st = SegmentType::StartRepeatBarLine;
248 739 : } else if (barLine->barLineType() == BarLineType::START_REPEAT && t == measure->ticks()) {
249 : // old version, ignore
250 0 : delete barLine;
251 0 : barLine = 0;
252 739 : } else if (t.isZero() && segment == 0) {
253 0 : st = SegmentType::BeginBarLine;
254 : } else {
255 739 : st = SegmentType::EndBarLine;
256 : }
257 752 : if (barLine) {
258 752 : segment = measure->getSegmentR(st, t);
259 752 : segment->add(barLine);
260 : }
261 752 : if (fermata) {
262 0 : segment->add(fermata);
263 0 : fermata = nullptr;
264 : }
265 16240 : } else if (tag == "Chord") {
266 7316 : Chord* chord = Factory::createChord(ctx.dummy());
267 7316 : chord->setTrack(ctx.track());
268 7316 : TRead::read(chord, e, ctx);
269 7316 : if (startingBeam) {
270 768 : startingBeam->add(chord); // also calls chord->setBeam(startingBeam)
271 768 : startingBeam = nullptr;
272 : }
273 : // if (tuplet && !chord->isGrace())
274 : // chord->readAddTuplet(tuplet);
275 7316 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
276 7316 : if (chord->noteType() != NoteType::NORMAL) {
277 101 : graceNotes.push_back(chord);
278 : } else {
279 7215 : segment->add(chord);
280 7316 : for (size_t i = 0; i < graceNotes.size(); ++i) {
281 101 : Chord* gc = graceNotes[i];
282 101 : gc->setGraceIndex(static_cast<int>(i));
283 101 : chord->add(gc);
284 : }
285 7215 : graceNotes.clear();
286 7215 : if (tuplet) {
287 1008 : tuplet->add(chord);
288 : }
289 7215 : ctx.incTick(chord->actualTicks());
290 : }
291 7316 : if (fermata) {
292 38 : segment->add(fermata);
293 38 : fermata = nullptr;
294 : }
295 8924 : } else if (tag == "Rest") {
296 4307 : if (measure->isMMRest()) {
297 30 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
298 30 : MMRest* mmr = Factory::createMMRest(segment);
299 30 : mmr->setTrack(ctx.track());
300 30 : TRead::read(mmr, e, ctx);
301 30 : segment->add(mmr);
302 30 : ctx.incTick(mmr->actualTicks());
303 : } else {
304 4277 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
305 4277 : Rest* rest = Factory::createRest(segment);
306 4277 : rest->setDurationType(DurationType::V_MEASURE);
307 4277 : rest->setTicks(measure->timesig() / timeStretch);
308 4277 : rest->setTrack(ctx.track());
309 4277 : TRead::read(rest, e, ctx);
310 4277 : if (startingBeam) {
311 0 : startingBeam->add(rest); // also calls rest->setBeam(startingBeam)
312 0 : startingBeam = nullptr;
313 : }
314 :
315 4277 : segment->add(rest);
316 4277 : if (fermata) {
317 0 : segment->add(fermata);
318 0 : fermata = nullptr;
319 : }
320 :
321 4277 : if (!rest->ticks().isValid()) { // hack
322 0 : rest->setTicks(measure->timesig() / timeStretch);
323 : }
324 :
325 4277 : if (tuplet) {
326 23 : tuplet->add(rest);
327 : }
328 4277 : ctx.incTick(rest->actualTicks());
329 : }
330 4617 : } else if (tag == "Breath") {
331 31 : segment = measure->getSegment(SegmentType::Breath, ctx.tick());
332 31 : Breath* breath = Factory::createBreath(segment);
333 31 : breath->setTrack(ctx.track());
334 31 : breath->setPlacement(breath->track() & 1 ? PlacementV::BELOW : PlacementV::ABOVE);
335 31 : TRead::read(breath, e, ctx);
336 31 : segment->add(breath);
337 4586 : } else if (tag == "Spanner") {
338 662 : TRead::readSpanner(e, ctx, measure, ctx.track());
339 3924 : } else if (tag == "MeasureRepeat" || tag == "RepeatMeasure") {
340 : // 4.x 3.x
341 41 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
342 41 : MeasureRepeat* mr = Factory::createMeasureRepeat(segment);
343 41 : mr->setTrack(ctx.track());
344 41 : TRead::read(mr, e, ctx);
345 41 : if (!mr->numMeasures()) {
346 27 : mr->setNumMeasures(1); // 3.x doesn't have any other possibilities
347 : }
348 41 : if (!measure->measureRepeatCount(staffIdx)) {
349 27 : measure->setMeasureRepeatCount(1, staffIdx);
350 : }
351 41 : segment->add(mr);
352 41 : ctx.incTick(measure->ticks());
353 3883 : } else if (tag == "Clef") {
354 274 : Clef* clef = Factory::createClef(ctx.dummy());
355 274 : clef->setTrack(ctx.track());
356 274 : bool isHeader = false;
357 274 : TRead::read(clef, e, ctx, &isHeader);
358 274 : clef->setGenerated(false);
359 :
360 274 : bool header = false;
361 274 : if (ctx.score()->mscVersion() < 410) {
362 : /***********************************************************************
363 : * LEGACY: we used to try to guess if the clef is a header based
364 : * on context, which is very unreliable. After 4.1, we just TAG it.
365 : * *********************************************************************/
366 : // there may be more than one clef segment for same tick position
367 : // the first clef may be missing and is added later in layout
368 274 : if (ctx.tick() != measure->tick()) {
369 58 : header = false;
370 216 : } else if (!segment) {
371 214 : header = true;
372 : } else {
373 2 : header = true;
374 4 : for (Segment* s = measure->first(); s && s->rtick().isZero(); s = s->next()) {
375 4 : if (s->isKeySigType() || s->isTimeSigType()) {
376 : // hack: there may be other segment types which should
377 : // generate a clef at current position
378 2 : header = false;
379 2 : break;
380 : }
381 : }
382 : }
383 : } else {
384 0 : header = isHeader;
385 : }
386 :
387 : // Clef segments are sorted on layout now. Previously, clef barline position could be out of sync with segment placement.
388 332 : if (ctx.tick() != Fraction(0, 1) && ctx.tick() == measure->tick()
389 332 : && !(measure->prevMeasure() && measure->prevMeasure()->repeatEnd()) && !header) {
390 0 : clef->setClefToBarlinePosition(ClefToBarlinePosition::AFTER);
391 : }
392 :
393 274 : segment = measure->getSegment(header ? SegmentType::HeaderClef : SegmentType::Clef, ctx.tick());
394 274 : segment->add(clef);
395 3609 : } else if (tag == "TimeSig") {
396 797 : TimeSig* ts = Factory::createTimeSig(ctx.dummy());
397 797 : ts->setTrack(ctx.track());
398 797 : TRead::read(ts, e, ctx);
399 : // if time sig not at beginning of measure => courtesy time sig
400 797 : Fraction currTick = ctx.tick();
401 797 : bool courtesySig = (currTick > measure->tick());
402 797 : if (courtesySig) {
403 : // if courtesy sig., just add it without map processing
404 0 : segment = measure->getSegment(SegmentType::TimeSigAnnounce, currTick);
405 0 : segment->add(ts);
406 : } else {
407 : // if 'real' time sig., do full process
408 797 : segment = measure->getSegment(SegmentType::TimeSig, currTick);
409 797 : segment->add(ts);
410 :
411 797 : timeStretch = ts->stretch().reduced();
412 797 : measure->setTimesig(ts->sig() / timeStretch);
413 :
414 797 : if (!irregular) {
415 783 : measure->setTicks(measure->timesig());
416 : }
417 : }
418 2812 : } else if (tag == "KeySig") {
419 148 : KeySig* ks = Factory::createKeySig(ctx.dummy());
420 148 : ks->setTrack(ctx.track());
421 148 : TRead::read(ks, e, ctx);
422 148 : Fraction curTick = ctx.tick();
423 : // if key sig not at beginning of measure => courtesy key sig
424 148 : bool courtesySig = (curTick == measure->endTick());
425 148 : segment = measure->getSegment(courtesySig ? SegmentType::KeySigAnnounce : SegmentType::KeySig, curTick);
426 148 : segment->add(ks);
427 148 : if (!courtesySig) {
428 148 : staff->setKey(curTick, ks->keySigEvent());
429 : }
430 2664 : } else if (tag == "Text") {
431 0 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
432 0 : StaffText* t = Factory::createStaffText(segment);
433 0 : t->setTrack(ctx.track());
434 0 : TRead::read(t, e, ctx);
435 0 : if (t->empty()) {
436 0 : LOGD("==reading empty text: deleted");
437 0 : delete t;
438 : } else {
439 0 : segment->add(t);
440 : }
441 : }
442 : //----------------------------------------------------
443 : // Annotation
444 2664 : else if (tag == "Dynamic") {
445 65 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
446 65 : Dynamic* dyn = Factory::createDynamic(segment);
447 65 : dyn->setTrack(ctx.track());
448 65 : TRead::read(dyn, e, ctx);
449 65 : segment->add(dyn);
450 2599 : } else if (tag == "Expression") {
451 0 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
452 0 : Expression* expr = Factory::createExpression(segment);
453 0 : expr->setTrack(ctx.track());
454 0 : TRead::read(expr, e, ctx);
455 0 : segment->add(expr);
456 2599 : } else if (tag == "Harmony") {
457 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
458 : // for symbols attached to anything but a measure
459 578 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
460 578 : Harmony* el = Factory::createHarmony(segment);
461 :
462 578 : el->setTrack(ctx.track());
463 578 : TRead::read(el, e, ctx);
464 578 : if (el->systemFlag() && el->isTopSystemObject()) {
465 0 : el->setTrack(0); // original system object always goes on top
466 : }
467 578 : if (el->chords().empty()) {
468 : // Invalid harmony
469 0 : delete el;
470 : } else {
471 578 : segment->add(el);
472 : }
473 2021 : } else if (tag == "FretDiagram") {
474 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
475 : // for symbols attached to anything but a measure
476 41 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
477 41 : FretDiagram* el = Factory::createFretDiagram(segment);
478 :
479 41 : el->setTrack(ctx.track());
480 41 : TRead::read(el, e, ctx);
481 41 : if (el->systemFlag() && el->isTopSystemObject()) {
482 0 : el->setTrack(0); // original system object always goes on top
483 : }
484 41 : segment->add(el);
485 1980 : } else if (tag == "TremoloBar") {
486 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
487 : // for symbols attached to anything but a measure
488 19 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
489 19 : TremoloBar* el = Factory::createTremoloBar(segment);
490 19 : el->setTrack(ctx.track());
491 19 : TRead::read(el, e, ctx);
492 19 : if (el->systemFlag() && el->isTopSystemObject()) {
493 0 : el->setTrack(0); // original system object always goes on top
494 : }
495 19 : segment->add(el);
496 1961 : } else if (tag == "Symbol") {
497 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
498 : // for symbols attached to anything but a measure
499 18 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
500 18 : Symbol* el = Factory::createSymbol(segment);
501 :
502 18 : el->setTrack(ctx.track());
503 18 : TRead::read(el, e, ctx);
504 18 : if (el->systemFlag() && el->isTopSystemObject()) {
505 0 : el->setTrack(0); // original system object always goes on top
506 : }
507 18 : segment->add(el);
508 1943 : } else if (tag == "Tempo") {
509 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
510 : // for symbols attached to anything but a measure
511 134 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
512 134 : TempoText* el = Factory::createTempoText(segment);
513 :
514 134 : el->setTrack(ctx.track());
515 134 : TRead::read(el, e, ctx);
516 134 : if (el->systemFlag() && el->isTopSystemObject()) {
517 134 : el->setTrack(0); // original system object always goes on top
518 : }
519 134 : segment->add(el);
520 1809 : } else if (tag == "StaffText") {
521 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
522 : // for symbols attached to anything but a measure
523 162 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
524 162 : StaffText* el = Factory::createStaffText(segment);
525 162 : el->setTrack(ctx.track());
526 162 : TRead::read(el, e, ctx);
527 162 : if (el->systemFlag() && el->isTopSystemObject()) {
528 0 : el->setTrack(0); // original system object always goes on top
529 : }
530 162 : segment->add(el);
531 1647 : } else if (tag == "Sticking"
532 1647 : || tag == "SystemText"
533 1613 : || tag == "PlayTechAnnotation"
534 1611 : || tag == "RehearsalMark"
535 1558 : || tag == "InstrumentChange"
536 1533 : || tag == "StaffState"
537 1533 : || tag == "FiguredBass"
538 3294 : || tag == "HarpPedalDiagram"
539 : ) {
540 : // hack - getSegment needed because tick tags are unreliable in 1.3 scores
541 : // for symbols attached to anything but a measure
542 156 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
543 156 : EngravingItem* el = Factory::createItemByName(tag, segment);
544 :
545 156 : el->setTrack(ctx.track());
546 156 : TRead::readItem(el, e, ctx);
547 156 : if (el->systemFlag() && el->isTopSystemObject()) {
548 87 : el->setTrack(0); // original system object always goes on top
549 : }
550 156 : segment->add(el);
551 156 : if (el->isInstrumentChange()) {
552 25 : Fraction tick = ctx.tick();
553 25 : Key key = staff->key(tick);
554 25 : Key cKey = staff->concertKey(tick);
555 25 : Interval vi = staff->part()->instrument(tick)->transpose();
556 25 : Interval vk = calculateInterval(cKey, key);
557 25 : bool concertPitch = ctx.style().styleB(Sid::concertPitch);
558 25 : if (!concertPitch && vk.chromatic != std::abs(vi.chromatic)) {
559 4 : InstrumentChange* ic = toInstrumentChange(el);
560 5 : for (KeySig* ks : ic->keySigs(true)) {
561 1 : KeySigEvent ke = ks->keySigEvent();
562 1 : ke.setConcertKey(Transpose::transposeKey(key, vi));
563 1 : ke.setKey(key);
564 1 : ks->setKeySigEvent(ke);
565 : //segment->add(ks);
566 1 : staff->setKey(tick, ke);
567 5 : }
568 : }
569 : }
570 1491 : } else if (tag == "Fermata") {
571 39 : fermata = Factory::createFermata(ctx.dummy());
572 39 : fermata->setTrack(ctx.track());
573 39 : fermata->setPlacement(fermata->track() & 1 ? PlacementV::BELOW : PlacementV::ABOVE);
574 39 : TRead::read(fermata, e, ctx);
575 1452 : } else if (tag == "Image") {
576 0 : if (MScore::noImages) {
577 0 : e.skipCurrentElement();
578 : } else {
579 0 : segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
580 0 : Image* el = Factory::createImage(segment);
581 0 : el->setTrack(ctx.track());
582 0 : TRead::read(el, e, ctx);
583 0 : segment->add(el);
584 : }
585 : }
586 : //----------------------------------------------------
587 1452 : else if (tag == "Tuplet") {
588 342 : Tuplet* oldTuplet = tuplet;
589 342 : tuplet = Factory::createTuplet(measure);
590 342 : tuplet->setTrack(ctx.track());
591 342 : tuplet->setTick(ctx.tick());
592 342 : TRead::read(tuplet, e, ctx);
593 342 : if (oldTuplet) {
594 14 : oldTuplet->add(tuplet);
595 : }
596 1110 : } else if (tag == "endTuplet") {
597 342 : if (!tuplet) {
598 0 : LOGD("Measure::read: encountered <endTuplet/> when no tuplet was started");
599 0 : e.skipCurrentElement();
600 0 : continue;
601 : }
602 342 : Tuplet* oldTuplet = tuplet;
603 342 : tuplet = tuplet->tuplet();
604 342 : if (oldTuplet->elements().empty()) {
605 : // this should not happen and is a sign of input file corruption
606 0 : LOGD("Measure:read: empty tuplet in measure index=%d, input file corrupted?", ctx.currentMeasureIndex());
607 0 : if (tuplet) {
608 0 : tuplet->remove(oldTuplet);
609 : }
610 0 : delete oldTuplet;
611 : }
612 342 : e.readNext();
613 768 : } else if (tag == "Beam") {
614 768 : Beam* beam = Factory::createBeam(ctx.score());
615 768 : beam->setTrack(ctx.track());
616 768 : TRead::read(beam, e, ctx);
617 768 : if (startingBeam) {
618 0 : LOGD("The read beam was not used");
619 0 : delete startingBeam;
620 : }
621 768 : startingBeam = beam;
622 0 : } else if (tag == "Segment" && segment) {
623 0 : read400::TRead::read(segment, e, ctx);
624 0 : } else if (tag == "Ambitus") {
625 0 : segment = measure->getSegment(SegmentType::Ambitus, ctx.tick());
626 0 : Ambitus* range = Factory::createAmbitus(segment);
627 0 : TRead::read(range, e, ctx);
628 0 : range->setTrack(trackZeroVoice(ctx.track()));
629 0 : segment->add(range);
630 : } else {
631 0 : e.unknown();
632 : }
633 : }
634 5310 : if (startingBeam) {
635 0 : LOGD("The read beam was not used");
636 0 : delete startingBeam;
637 : }
638 5310 : if (tuplet) {
639 0 : LOGD("Measure:readVoice: measure index=%d, <endTuplet/> not found", ctx.currentMeasureIndex());
640 0 : if (tuplet->elements().empty()) {
641 0 : if (tuplet->tuplet()) {
642 0 : tuplet->tuplet()->remove(tuplet);
643 : }
644 0 : delete tuplet;
645 : }
646 : }
647 5310 : if (fermata) {
648 1 : SegmentType st = (ctx.tick() == measure->endTick() ? SegmentType::EndBarLine : SegmentType::ChordRest);
649 1 : segment = measure->getSegment(st, ctx.tick());
650 1 : segment->add(fermata);
651 1 : fermata = nullptr;
652 : }
653 5310 : }
|