1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2009-2011 Werner Schweer
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 LICENCE.GPL
11 //=============================================================================
12
13 #include "excerpt.h"
14 #include "score.h"
15 #include "part.h"
16 #include "xml.h"
17 #include "staff.h"
18 #include "box.h"
19 #include "textframe.h"
20 #include "style.h"
21 #include "page.h"
22 #include "text.h"
23 #include "slur.h"
24 #include "tie.h"
25 #include "sig.h"
26 #include "tempo.h"
27 #include "measure.h"
28 #include "rest.h"
29 #include "stafftype.h"
30 #include "tuplet.h"
31 #include "chord.h"
32 #include "note.h"
33 #include "lyrics.h"
34 #include "segment.h"
35 #include "textline.h"
36 #include "tupletmap.h"
37 #include "tiemap.h"
38 #include "layoutbreak.h"
39 #include "harmony.h"
40 #include "beam.h"
41 #include "utils.h"
42 #include "tremolo.h"
43 #include "barline.h"
44 #include "undo.h"
45 #include "bracketItem.h"
46
47 namespace Ms {
48
49 //---------------------------------------------------------
50 // Excerpt
51 //---------------------------------------------------------
52
Excerpt(const Excerpt & ex,bool copyPartScore)53 Excerpt::Excerpt(const Excerpt& ex, bool copyPartScore)
54 : QObject(), _oscore(ex._oscore), _title(ex._title), _parts(ex._parts), _tracks(ex._tracks)
55 {
56 _partScore = (copyPartScore && ex._partScore) ? ex._partScore->clone() : nullptr;
57 }
58
59 //---------------------------------------------------------
60 // ~Excerpt
61 //---------------------------------------------------------
62
~Excerpt()63 Excerpt::~Excerpt() {
64 delete _partScore;
65 }
66
67 //---------------------------------------------------------
68 // nstaves
69 //---------------------------------------------------------
70
nstaves() const71 int Excerpt::nstaves() const
72 {
73 int n { 0 };
74 for (Part* p : _parts)
75 n += p->nstaves();
76 return n;
77 }
78
79 //---------------------------------------------------------
80 // read
81 //---------------------------------------------------------
82
read(XmlReader & e)83 void Excerpt::read(XmlReader& e)
84 {
85 const QList<Part*>& pl = _oscore->parts();
86 QString name;
87 while (e.readNextStartElement()) {
88 const QStringRef& tag = e.name();
89 if (tag == "name")
90 name = e.readElementText();
91 else if (tag == "title")
92 _title = e.readElementText().trimmed();
93 else if (tag == "part") {
94 int partIdx = e.readInt();
95 if (partIdx < 0 || partIdx >= pl.size())
96 qDebug("Excerpt::read: bad part index");
97 else
98 _parts.append(pl.at(partIdx));
99 }
100 }
101 if (_title.isEmpty())
102 _title = name.trimmed();
103 }
104
105 //---------------------------------------------------------
106 // operator!=
107 //---------------------------------------------------------
108
operator !=(const Excerpt & e) const109 bool Excerpt::operator!=(const Excerpt& e) const
110 {
111 if (e._oscore != _oscore)
112 return true;
113 if (e._title != _title)
114 return true;
115 if (e._parts != _parts)
116 return true;
117 if (e._tracks != _tracks)
118 return true;
119 return false;
120 }
121
122 //---------------------------------------------------------
123 // operator==
124 //---------------------------------------------------------
125
operator ==(const Excerpt & e) const126 bool Excerpt::operator==(const Excerpt& e) const
127 {
128 if (e._oscore != _oscore)
129 return false;
130 if (e._title != _title)
131 return false;
132 if (e._parts != _parts)
133 return false;
134 if (e._tracks != _tracks)
135 return false;
136 return true;
137 }
138
139 //---------------------------------------------------------
140 // createExcerpt
141 //---------------------------------------------------------
142
createExcerpt(Excerpt * excerpt)143 void Excerpt::createExcerpt(Excerpt* excerpt)
144 {
145 MasterScore* oscore = excerpt->oscore();
146 Score* score = excerpt->partScore();
147
148 QList<Part*>& parts = excerpt->parts();
149 QList<int> srcStaves;
150
151 // clone layer:
152 for (int i = 0; i < 32; ++i) {
153 score->layerTags()[i] = oscore->layerTags()[i];
154 score->layerTagComments()[i] = oscore->layerTagComments()[i];
155 }
156 score->setCurrentLayer(oscore->currentLayer());
157 score->layer().clear();
158 foreach (const Layer& l, oscore->layer())
159 score->layer().append(l);
160
161 score->setPageNumberOffset(oscore->pageNumberOffset());
162
163 // Set instruments and create linked staves
164 for (const Part* part : parts) {
165 Part* p = new Part(score);
166 p->setInstrument(*part->instrument());
167 p->setPartName(part->partName());
168
169 for (Staff* staff : *part->staves()) {
170 Staff* s = new Staff(score);
171 s->setPart(p);
172 // s->setStaffType(0, *staff->staffType(0)); // TODO
173 s->init(staff);
174 s->setDefaultClefType(staff->defaultClefType());
175 // the order of staff - s matters as staff should be the first entry in the
176 // created link list to make primaryStaff() work
177 // TODO: change implementation, maybe create an explicit "primary" flag
178 score->undo(new Link(s, staff));
179 p->staves()->append(s);
180 score->staves().append(s);
181 srcStaves.append(staff->idx());
182 }
183 score->appendPart(p);
184 }
185
186 // Fill tracklist (map all tracks of a stave)
187 if (excerpt->tracks().isEmpty()) {
188 QMultiMap<int, int> tracks;
189 for (Staff* s : score->staves()) {
190 const LinkedElements* ls = s->links();
191 if (ls == 0)
192 continue;
193 for (auto le : *ls) {
194 Staff* ps = toStaff(le);
195 if (ps->primaryStaff()) {
196 for (int i = 0; i < VOICES; i++) {
197 tracks.insert(ps->idx() * VOICES + i % VOICES, s->idx() * VOICES + i % VOICES);
198 }
199 break;
200 }
201 }
202 }
203 excerpt->setTracks(tracks);
204 }
205
206 cloneStaves(oscore, score, srcStaves, excerpt->tracks());
207
208 // create excerpt title and title frame for all scores if not already there
209 MeasureBase* measure = oscore->first();
210
211 if (!measure || !measure->isVBox()) {
212 qDebug("original score has no header frame");
213 oscore->insertMeasure(ElementType::VBOX, measure);
214 measure = oscore->first();
215 }
216 VBox* titleFrameScore = toVBox(measure);
217
218 measure = score->first();
219 Q_ASSERT(measure->isVBox());
220
221 VBox* titleFramePart = toVBox(measure);
222 titleFramePart->copyValues(titleFrameScore);
223 QString partLabel = excerpt->title(); // parts.front()->longName();
224 if (!partLabel.isEmpty()) {
225 Text* txt = new Text(score, Tid::INSTRUMENT_EXCERPT);
226 txt->setPlainText(partLabel);
227 measure->add(txt);
228 score->setMetaTag("partName", partLabel);
229 }
230
231 // initial layout of score
232 score->addLayoutFlags(LayoutFlag::FIX_PITCH_VELO);
233 score->doLayout();
234
235 // handle transposing instruments
236 if (oscore->styleB(Sid::concertPitch) != score->styleB(Sid::concertPitch)) {
237 for (const Staff* staff : score->staves()) {
238 if (staff->staffType(Fraction(0,1))->group() == StaffGroup::PERCUSSION)
239 continue;
240
241 // if this staff has no transposition, and no instrument changes, we can skip it
242 Interval interval = staff->part()->instrument()->transpose(); //tick?
243 if (interval.isZero() && staff->part()->instruments()->size() == 1)
244 continue;
245 bool flip = false;
246 if (oscore->styleB(Sid::concertPitch)) {
247 interval.flip(); // flip the transposition for the original instrument
248 flip = true; // transposeKeys() will flip transposition for each instrument change
249 }
250
251 int staffIdx = staff->idx();
252 int startTrack = staffIdx * VOICES;
253 int endTrack = startTrack + VOICES;
254
255 Fraction endTick = Fraction(0,1);
256 if (score->lastSegment())
257 endTick = score->lastSegment()->tick();
258 score->transposeKeys(staffIdx, staffIdx+1, Fraction(0,1), endTick, interval, true, flip);
259
260 for (auto segment = score->firstSegmentMM(SegmentType::ChordRest); segment; segment = segment->next1MM(SegmentType::ChordRest)) {
261 interval = staff->part()->instrument(segment->tick())->transpose();
262 if (interval.isZero())
263 continue;
264 if (oscore->styleB(Sid::concertPitch))
265 interval.flip();
266
267 for (auto e : segment->annotations()) {
268 if (!e->isHarmony() || (e->track() < startTrack) || (e->track() >= endTrack))
269 continue;
270 Harmony* h = toHarmony(e);
271 int rootTpc = Ms::transposeTpc(h->rootTpc(), interval, true);
272 int baseTpc = Ms::transposeTpc(h->baseTpc(), interval, true);
273 // mmrests are on by default in part
274 // if this harmony is attached to an mmrest,
275 // be sure to transpose harmony in underlying measure as well
276 for (ScoreElement* se : h->linkList()) {
277 Harmony* hh = static_cast<Harmony*>(se);
278 // skip links to other staves (including in other scores)
279 if (hh->staff() != h->staff())
280 continue;
281 score->undoTransposeHarmony(hh, rootTpc, baseTpc);
282 }
283 }
284 }
285 }
286 }
287
288 // update style values if spatium different for part
289 if (oscore->spatium() != score->spatium()) {
290 //score->spatiumChanged(oscore->spatium(), score->spatium());
291 score->styleChanged();
292 }
293
294 // second layout of score
295 score->setPlaylistDirty();
296 oscore->rebuildMidiMapping();
297 oscore->updateChannel();
298
299 score->setLayoutAll();
300 score->doLayout();
301 }
302
303 //---------------------------------------------------------
304 // deleteExcerpt
305 //---------------------------------------------------------
306
deleteExcerpt(Excerpt * excerpt)307 void MasterScore::deleteExcerpt(Excerpt* excerpt)
308 {
309 Q_ASSERT(excerpt->oscore() == this);
310 Score* partScore = excerpt->partScore();
311
312 if (!partScore) {
313 qDebug("deleteExcerpt: no partScore");
314 return;
315 }
316
317 // unlink the staves in the excerpt
318 for (Staff* st : partScore->staves()) {
319 bool hasLinksInMaster = false;
320 if (st->links()) {
321 for (auto le : *st->links()) {
322 if (le->score() == this) {
323 hasLinksInMaster = true;
324 break;
325 }
326 }
327 }
328 if (hasLinksInMaster) {
329 int staffIdx = st->idx();
330 // unlink the spanners
331 for (auto i = partScore->spanner().begin(); i != partScore->spanner().cend(); ++i) {
332 Spanner* sp = i->second;
333 if (sp->staffIdx() == staffIdx)
334 sp->undoUnlink();
335 }
336 int sTrack = staffIdx * VOICES;
337 int eTrack = sTrack + VOICES;
338 // unlink elements and annotation
339 for (Segment* s = partScore->firstSegmentMM(SegmentType::All); s; s = s->next1MM()) {
340 for (int track = eTrack - 1; track >= sTrack; --track) {
341 Element* el = s->element(track);
342 if (el)
343 el->undoUnlink();
344 }
345 for (Element* e : s->annotations()) {
346 if (e->staffIdx() == staffIdx)
347 e->undoUnlink();
348 }
349 }
350 // unlink the staff
351 undo(new Unlink(st));
352 }
353 }
354 undo(new RemoveExcerpt(excerpt));
355 }
356
357 //---------------------------------------------------------
358 // cloneSpanner
359 //---------------------------------------------------------
360
cloneSpanner(Spanner * s,Score * score,int dstTrack,int dstTrack2)361 static void cloneSpanner(Spanner* s, Score* score, int dstTrack, int dstTrack2)
362 {
363 // don’t clone voltas for track != 0
364 if ((s->isVolta() || (s->isTextLine() && toTextLine(s)->systemFlag())) && s->track() != 0)
365 return;
366 Spanner* ns = toSpanner(s->linkedClone());
367 ns->setScore(score);
368 ns->setParent(0);
369 ns->setTrack(dstTrack);
370 ns->setTrack2(dstTrack2);
371
372 if (ns->isSlur()) {
373
374 // set start/end element for slur
375 ChordRest* cr1 = s->startCR();
376 ChordRest* cr2 = s->endCR();
377
378 ns->setStartElement(0);
379 ns->setEndElement(0);
380 if (cr1 && cr1->links()) {
381 for (ScoreElement* e : *cr1->links()) {
382 ChordRest* cr = toChordRest(e);
383 if (cr == cr1)
384 continue;
385 if ((cr->score() == score) && (cr->tick() == ns->tick()) && cr->track() == dstTrack) {
386 ns->setStartElement(cr);
387 break;
388 }
389 }
390 }
391 if (cr2 && cr2->links()) {
392 for (ScoreElement* e : *cr2->links()) {
393 ChordRest* cr = toChordRest(e);
394 if (cr == cr2)
395 continue;
396 if ((cr->score() == score) && (cr->tick() == ns->tick2()) && cr->track() == dstTrack2) {
397 ns->setEndElement(cr);
398 break;
399 }
400 }
401 }
402 if (!ns->startElement())
403 qDebug("clone Slur: no start element");
404 if (!ns->endElement())
405 qDebug("clone Slur: no end element");
406 }
407 score->undo(new AddElement(ns));
408 }
409
410 //---------------------------------------------------------
411 // cloneTuplets
412 //---------------------------------------------------------
413
cloneTuplets(ChordRest * ocr,ChordRest * ncr,Tuplet * ot,TupletMap & tupletMap,Measure * m,int track)414 static void cloneTuplets(ChordRest* ocr, ChordRest* ncr, Tuplet* ot, TupletMap& tupletMap, Measure* m, int track)
415 {
416 ot->setTrack(ocr->track());
417 Tuplet* nt = tupletMap.findNew(ot);
418 if (nt == 0) {
419 nt = toTuplet(ot->linkedClone());
420 nt->setTrack(track);
421 nt->setParent(m);
422 nt->setScore(ncr->score());
423 tupletMap.add(ot, nt);
424
425 Tuplet* nt1 = nt;
426 while (ot->tuplet()) {
427 Tuplet* nt2 = tupletMap.findNew(ot->tuplet());
428 if (nt2 == 0) {
429 nt2 = toTuplet(ot->tuplet()->linkedClone());
430 nt2->setTrack(track);
431 nt2->setParent(m);
432 nt2->setScore(ncr->score());
433 tupletMap.add(ot->tuplet(), nt2);
434 }
435 nt2->add(nt1);
436 nt1->setTuplet(nt2);
437 ot = ot->tuplet();
438 nt1 = nt2;
439 }
440 }
441 nt->add(ncr);
442 ncr->setTuplet(nt);
443 }
444
445 //---------------------------------------------------------
446 // processLinkedClone
447 //---------------------------------------------------------
448
processLinkedClone(Element * ne,Score * score,int strack)449 void Excerpt::processLinkedClone(Element* ne, Score* score, int strack)
450 {
451 // reset offset as most likely it will not fit
452 PropertyFlags f = ne->propertyFlags(Pid::OFFSET);
453 if (f == PropertyFlags::UNSTYLED) {
454 ne->setPropertyFlags(Pid::OFFSET, PropertyFlags::STYLED);
455 ne->resetProperty(Pid::OFFSET);
456 }
457 ne->setTrack(strack == -1 ? 0 : strack);
458 ne->setScore(score);
459 }
460
461 //---------------------------------------------------------
462 // cloneStaves
463 //---------------------------------------------------------
464
cloneStaves(Score * oscore,Score * score,const QList<int> & map,QMultiMap<int,int> & trackList)465 void Excerpt::cloneStaves(Score* oscore, Score* score, const QList<int>& map, QMultiMap<int, int>& trackList)
466 {
467 TieMap tieMap;
468
469 MeasureBaseList* nmbl = score->measures();
470 for (MeasureBase* mb = oscore->measures()->first(); mb; mb = mb->next()) {
471 MeasureBase* nmb = 0;
472 if (mb->isHBox())
473 nmb = new HBox(score);
474 else if (mb->isVBox())
475 nmb = new VBox(score);
476 else if (mb->isTBox()) {
477 nmb = new TBox(score);
478 Text* text = toTBox(mb)->text();
479 Element* ne = text->linkedClone();
480 ne->setScore(score);
481 nmb->add(ne);
482 }
483 else if (mb->isMeasure()) {
484 Measure* m = toMeasure(mb);
485 Measure* nm = new Measure(score);
486 nmb = nm;
487 nm->setTick(m->tick());
488 nm->setTicks(m->ticks());
489 nm->setTimesig(m->timesig());
490
491 nm->setRepeatCount(m->repeatCount());
492 nm->setRepeatStart(m->repeatStart());
493 nm->setRepeatEnd(m->repeatEnd());
494 nm->setRepeatJump(m->repeatJump());
495
496 nm->setIrregular(m->irregular());
497 nm->setNo(m->no());
498 nm->setNoOffset(m->noOffset());
499 nm->setBreakMultiMeasureRest(m->breakMultiMeasureRest());
500
501 for (int dstStaffIdx = 0; dstStaffIdx < map.size(); ++dstStaffIdx) {
502 nm->setStaffStemless(dstStaffIdx, m->stemless(map[dstStaffIdx]));
503 }
504
505 //TODO nm->setEndBarLineType(
506 // m->endBarLineType(),
507 // m->endBarLineGenerated(),
508 // m->endBarLineVisible(),
509 // m->endBarLineColor());
510
511 // Fraction ts = nm->len();
512 int tracks = oscore->nstaves() * VOICES;
513 for (int srcTrack = 0; srcTrack < tracks; ++srcTrack) {
514 TupletMap tupletMap; // tuplets cannot cross measure boundaries
515
516 int strack = trackList.value(srcTrack, -1);
517
518 Tremolo* tremolo = 0;
519 for (Segment* oseg = m->first(); oseg; oseg = oseg->next()) {
520 Segment* ns = nullptr; //create segment later, on demand
521 for (Element* e : oseg->annotations()) {
522 if (e->generated())
523 continue;
524 if ((e->track() == srcTrack && strack != -1) || (e->systemFlag() && srcTrack == 0)) {
525 Element* ne = e->linkedClone();
526 processLinkedClone(ne, score, strack);
527 if (!ns)
528 ns = nm->getSegment(oseg->segmentType(), oseg->tick());
529 ns->add(ne);
530 // for chord symbols,
531 // re-render with new style settings
532 if (ne->isHarmony()) {
533 Harmony* h = toHarmony(ne);
534 h->render();
535 }
536 else if (ne->isFretDiagram()) {
537 Harmony* h = toHarmony(toFretDiagram(ne)->harmony());
538 if (h) {
539 processLinkedClone(h, score, strack);
540 h->render();
541 }
542 }
543 }
544 }
545
546 //If track is not mapped skip the following
547 if (trackList.value(srcTrack, -1) == -1)
548 continue;
549
550 //There are probably more destination tracks for the same source
551 QList<int> t = trackList.values(srcTrack);
552
553 for (int track : qAsConst(t)) {
554 //Clone KeySig TimeSig and Clefs if voice 1 of source staff is not mapped to a track
555 Element* oef = oseg->element(srcTrack & ~3);
556 if (oef && !oef->generated() && (oef->isTimeSig() || oef->isKeySig())
557 && !(trackList.size() == (score->excerpt()->nstaves() * VOICES))) {
558 Element* ne = oef->linkedClone();
559 ne->setTrack(track & ~3);
560 ne->setScore(score);
561 ns = nm->getSegment(oseg->segmentType(), oseg->tick());
562 ns->add(ne);
563 }
564
565 Element* oe = oseg->element(srcTrack);
566 int adjustedBarlineSpan = 0;
567 if (srcTrack % VOICES == 0 && oseg->segmentType() == SegmentType::BarLine) {
568 // mid-measure barline segment
569 // may need to clone barline from a previous staff and/or adjust span
570 int oIdx = srcTrack / VOICES;
571 if (!oe) {
572 // no barline on this staff in original score,
573 // but check previous staves
574 for (int i = oIdx - 1; i >= 0; --i) {
575 oe = oseg->element(i * VOICES);
576 if (oe)
577 break;
578 }
579 }
580 if (oe) {
581 // barline found, now check span
582 BarLine* bl = toBarLine(oe);
583 int oSpan1 = bl->staff()->idx();
584 int oSpan2 = oSpan1 + bl->spanStaff();
585 if (oSpan1 <= oIdx && oIdx < oSpan2) {
586 // this staff is within span
587 // calculate adjusted span for excerpt
588 int oSpan = oSpan2 - oIdx;
589 adjustedBarlineSpan = qMin(oSpan, score->nstaves());
590 }
591 else {
592 // this staff is not within span
593 oe = nullptr;
594 }
595 }
596 }
597
598 if (oe && !oe->generated()) {
599 Element* ne;
600 ne = oe->linkedClone();
601 ne->setTrack(track);
602
603 if (!(ne->track() % VOICES) && ne->isRest())
604 toRest(ne)->setGap(false);
605
606 ne->setScore(score);
607 if (oe->isBarLine() && adjustedBarlineSpan) {
608 BarLine* nbl = toBarLine(ne);
609 nbl->setSpanStaff(adjustedBarlineSpan);
610 }
611 else if (oe->isChordRest()) {
612 ChordRest* ocr = toChordRest(oe);
613 ChordRest* ncr = toChordRest(ne);
614
615 if (ocr->beam() && !ocr->beam()->empty() && ocr->beam()->elements().front() == ocr) {
616 Beam* nb = ocr->beam()->clone();
617 nb->clear();
618 nb->setTrack(track);
619 nb->setScore(score);
620 nb->add(ncr);
621 ncr->setBeam(nb);
622 }
623
624 Tuplet* ot = ocr->tuplet();
625
626 if (ot)
627 cloneTuplets(ocr, ncr, ot, tupletMap, nm, track);
628
629 if (oe->isChord()) {
630 Chord* och = toChord(ocr);
631 Chord* nch = toChord(ncr);
632
633 size_t n = och->notes().size();
634 for (size_t i = 0; i < n; ++i) {
635 Note* on = och->notes().at(i);
636 Note* nn = nch->notes().at(i);
637 if (on->tieFor()) {
638 Tie* tie = toTie(on->tieFor()->linkedClone());
639 tie->setScore(score);
640 nn->setTieFor(tie);
641 tie->setStartNote(nn);
642 tie->setTrack(nn->track());
643 tieMap.add(on->tieFor(), tie);
644 }
645 if (on->tieBack()) {
646 Tie* tie = tieMap.findNew(on->tieBack());
647 if (tie) {
648 nn->setTieBack(tie);
649 tie->setEndNote(nn);
650 }
651 else {
652 qDebug("cloneStaves: cannot find tie");
653 }
654 }
655 // add back spanners (going back from end to start spanner element
656 // makes sure the 'other' spanner anchor element is already set up)
657 // 'on' is the old spanner end note and 'nn' is the new spanner end note
658 for (Spanner* oldSp : on->spannerBack()) {
659 if (oldSp->startElement() && oldSp->endElement() && oldSp->startElement()->track() > oldSp->endElement()->track())
660 continue;
661 Note* newStart = Spanner::startElementFromSpanner(oldSp, nn);
662 if (newStart != nullptr) {
663 Spanner* newSp = toSpanner(oldSp->linkedClone());
664 newSp->setNoteSpan(newStart, nn);
665 score->addElement(newSp);
666 }
667 else {
668 qDebug("cloneStaves: cannot find spanner start note");
669 }
670 }
671 for (Spanner* oldSp : on->spannerFor()) {
672 if (oldSp->startElement() && oldSp->endElement() && oldSp->startElement()->track() <= oldSp->endElement()->track())
673 continue;
674 Note* newEnd = Spanner::endElementFromSpanner(oldSp, nn);
675 if (newEnd != nullptr) {
676 Spanner* newSp = toSpanner(oldSp->linkedClone());
677 newSp->setNoteSpan(nn, newEnd);
678 score->addElement(newSp);
679 }
680 else {
681 qDebug("cloneStaves: cannot find spanner end note");
682 }
683 }
684 }
685 // two note tremolo
686 if (och->tremolo() && och->tremolo()->twoNotes()) {
687 if (och == och->tremolo()->chord1()) {
688 if (tremolo)
689 qDebug("unconnected two note tremolo");
690 tremolo = toTremolo(och->tremolo()->linkedClone());
691 tremolo->setScore(nch->score());
692 tremolo->setParent(nch);
693 tremolo->setTrack(nch->track());
694 tremolo->setChords(nch, 0);
695 nch->setTremolo(tremolo);
696 }
697 else if (och == och->tremolo()->chord2()) {
698 if (!tremolo)
699 qDebug("first note for two note tremolo missing");
700 else {
701 tremolo->setChords(tremolo->chord1(), nch);
702 nch->setTremolo(tremolo);
703 }
704 }
705 else
706 qDebug("inconsistent two note tremolo");
707 }
708 }
709 }
710 if (!ns)
711 ns = nm->getSegment(oseg->segmentType(), oseg->tick());
712 ns->add(ne);
713 }
714
715 Segment* tst = nm->segments().firstCRSegment();
716 if (srcTrack % VOICES && !(track % VOICES) && (!tst || (!tst->element(track)))) {
717 Rest* rest = new Rest(score);
718 rest->setTicks(nm->ticks());
719 rest->setDurationType(nm->ticks());
720 rest->setTrack(track);
721 Segment* segment = nm->getSegment(SegmentType::ChordRest, nm->tick());
722 segment->add(rest);
723 }
724
725 }
726 }
727 }
728 }
729
730 nmb->linkTo(mb);
731 for (Element* e : mb->el()) {
732 if (e->isLayoutBreak()) {
733 LayoutBreak::Type st = toLayoutBreak(e)->layoutBreakType();
734 if (st == LayoutBreak::Type::PAGE || st == LayoutBreak::Type::LINE)
735 continue;
736 }
737 int track = -1;
738 if (e->track() != -1) {
739 // try to map track
740 track = trackList.value(e->track(), -1);
741 if (track == -1) {
742 // even if track not in excerpt, we need to clone system elements
743 if (e->systemFlag())
744 track = 0;
745 else
746 continue;
747 }
748 }
749
750 Element* ne;
751 // link text - title, subtitle, also repeats (eg, coda/segno)
752 // measure numbers are not stored in this list, but they should not be cloned anyhow
753 // layout breaks other than section were skipped above,
754 // but section breaks do need to be cloned & linked
755 // other measure-attached elements (?) are cloned but not linked
756 if (e->isText() && toText(e)->tid() == Tid::INSTRUMENT_EXCERPT) {
757 // skip part name in score
758 continue;
759 }
760 else if (e->isTextBase() || e->isLayoutBreak()) {
761 ne = e->clone();
762 ne->setAutoplace(true);
763 ne->linkTo(e);
764 }
765 else
766 ne = e->clone();
767 ne->setScore(score);
768 ne->setTrack(track);
769 nmb->add(ne);
770 }
771 nmbl->add(nmb);
772 }
773
774 int n = map.size();
775 for (int dstStaffIdx = 0; dstStaffIdx < n; ++dstStaffIdx) {
776 Staff* srcStaff = oscore->staff(map[dstStaffIdx]);
777 Staff* dstStaff = score->staff(dstStaffIdx);
778
779 if (srcStaff->primaryStaff()) {
780 int span = srcStaff->barLineSpan();
781 int sIdx = srcStaff->idx();
782 if (dstStaffIdx == 0 && span == 0) {
783 // this is first staff of new score,
784 // but it was somewhere within a barline span in the old score
785 // so, find beginning of span
786 for (int i = 0; i <= sIdx; ++i) {
787 span = oscore->staff(i)->barLineSpan();
788 if (i + span > sIdx) {
789 sIdx = i;
790 break;
791 }
792 }
793 }
794 int eIdx = sIdx + span;
795 for (int staffIdx = sIdx; staffIdx < eIdx; ++staffIdx) {
796 if (!map.contains(staffIdx))
797 --span;
798 }
799 if (dstStaffIdx + span > n)
800 span = n - dstStaffIdx - 1;
801 dstStaff->setBarLineSpan(span);
802 int idx = 0;
803 for (BracketItem* bi : srcStaff->brackets()) {
804 dstStaff->setBracketType(idx, bi->bracketType());
805 dstStaff->setBracketSpan(idx, bi->bracketSpan());
806 ++idx;
807 }
808 }
809 }
810
811 for (auto i : oscore->spanner()) {
812 Spanner* s = i.second;
813 int dstTrack = -1;
814 int dstTrack2 = -1;
815
816 if (s->isVolta() || (s->isTextLine() && toTextLine(s)->systemFlag())) {
817 //always export voltas to first staff in part
818 dstTrack = 0;
819 dstTrack2 = 0;
820 cloneSpanner(s, score, dstTrack, dstTrack2);
821 }
822 else if (s->isHairpin()) {
823 //always export these spanners to first voice of the destination staff
824
825 QList<int> track1;
826 for (int ii = s->track(); ii < s->track() + VOICES; ii++) {
827 track1 += trackList.values(ii);
828 }
829
830 for (int track : qAsConst(track1)) {
831 if (!(track % VOICES))
832 cloneSpanner(s, score, track, track);
833 }
834
835 }
836 else {
837 if (trackList.value(s->track(), -1) == -1 || trackList.value(s->track2(), -1) == -1)
838 continue;
839 QList<int> track1 = trackList.values(s->track());
840 QList<int> track2 = trackList.values(s->track2());
841
842 if (track1.length() != track2.length())
843 continue;
844
845 //export other spanner if staffidx matches
846 for (int ii = 0; ii < track1.length(); ii++) {
847 dstTrack = track1.at(ii);
848 dstTrack2 = track2.at(ii);
849 cloneSpanner(s, score, dstTrack, dstTrack2);
850 }
851 }
852 }
853 }
854
855 //---------------------------------------------------------
856 // cloneStaff
857 // staves are in same score
858 //---------------------------------------------------------
859
cloneStaff(Staff * srcStaff,Staff * dstStaff)860 void Excerpt::cloneStaff(Staff* srcStaff, Staff* dstStaff)
861 {
862 Score* score = srcStaff->score();
863 TieMap tieMap;
864
865 score->undo(new Link(dstStaff, srcStaff));
866
867 int srcStaffIdx = srcStaff->idx();
868 int dstStaffIdx = dstStaff->idx();
869
870 for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure()) {
871 int sTrack = srcStaffIdx * VOICES;
872 int eTrack = sTrack + VOICES;
873 for (int srcTrack = sTrack; srcTrack < eTrack; ++srcTrack) {
874 TupletMap tupletMap; // tuplets cannot cross measure boundaries
875 int dstTrack = dstStaffIdx * VOICES + (srcTrack - sTrack);
876 Tremolo* tremolo = 0;
877 for (Segment* seg = m->first(); seg; seg = seg->next()) {
878 Element* oe = seg->element(srcTrack);
879 if (oe == 0 || oe->generated())
880 continue;
881 if (oe->isTimeSig())
882 continue;
883 Element* ne = 0;
884 if (oe->isClef()) {
885 // only clone clef if it matches staff group and does not exists yet
886 Clef* clef = toClef(oe);
887 Fraction tick = seg->tick();
888 if (ClefInfo::staffGroup(clef->concertClef()) == dstStaff->constStaffType(Fraction(0,1))->group()
889 && dstStaff->clefType(tick) != clef->clefTypeList()) {
890 ne = oe->clone();
891 }
892 }
893 else
894 ne = oe->linkedClone();
895 if (ne) {
896 ne->setTrack(dstTrack);
897 ne->setParent(seg);
898 ne->setScore(score);
899 if (ne->isChordRest()) {
900 ChordRest* ncr = toChordRest(ne);
901 if (ncr->tuplet()) {
902 ncr->setTuplet(0); //TODO nested tuplets
903 }
904 }
905 score->undoAddElement(ne);
906 }
907 if (oe->isChordRest()) {
908 ChordRest* ocr = toChordRest(oe);
909 ChordRest* ncr = toChordRest(ne);
910 Tuplet* ot = ocr->tuplet();
911 if (ot)
912 cloneTuplets(ocr, ncr, ot, tupletMap, m, dstTrack);
913
914 // remove lyrics from chord
915 // since only one set of lyrics is used with linked staves
916 foreach (Lyrics* l, ncr->lyrics()) {
917 if (l)
918 l->unlink();
919 }
920 qDeleteAll(ncr->lyrics());
921 ncr->lyrics().clear();
922
923 for (Element* e : seg->annotations()) {
924 if (!e) {
925 qDebug("cloneStaff: corrupted annotation found.");
926 continue;
927 }
928 if (e->generated() || e->systemFlag())
929 continue;
930 if (e->track() != srcTrack)
931 continue;
932 switch (e->type()) {
933 // exclude certain element types
934 // this should be same list excluded in Score::undoAddElement()
935 case ElementType::STAFF_TEXT:
936 case ElementType::SYSTEM_TEXT:
937 case ElementType::FRET_DIAGRAM:
938 case ElementType::HARMONY:
939 case ElementType::FIGURED_BASS:
940 case ElementType::DYNAMIC:
941 case ElementType::LYRICS: // not normally segment-attached
942 continue;
943 case ElementType::FERMATA:
944 {
945 // Fermatas are special since the belong to a segment but should
946 // be created and linked on each staff.
947 Element* ne1 = e->linkedClone();
948 ne1->setTrack(dstTrack);
949 ne1->setParent(seg);
950 ne1->setScore(score);
951 score->undo(new AddElement(ne1));
952 continue;
953 }
954 default:
955 if (toTextLine(e)->systemFlag())
956 continue;
957 Element* ne1 = e->clone();
958 ne1->setTrack(dstTrack);
959 ne1->setParent(seg);
960 ne1->setScore(score);
961 score->undoAddElement(ne1);
962 }
963 }
964 if (oe->isChord()) {
965 Chord* och = toChord(ocr);
966 Chord* nch = toChord(ncr);
967 size_t n = och->notes().size();
968 for (size_t i = 0; i < n; ++i) {
969 Note* on = och->notes().at(i);
970 Note* nn = nch->notes().at(i);
971 if (on->tieFor()) {
972 Tie* tie = toTie(on->tieFor()->linkedClone());
973 tie->setScore(score);
974 nn->setTieFor(tie);
975 tie->setStartNote(nn);
976 tie->setTrack(nn->track());
977 tieMap.add(on->tieFor(), tie);
978 }
979 if (on->tieBack()) {
980 Tie* tie = tieMap.findNew(on->tieBack());
981 if (tie) {
982 nn->setTieBack(tie);
983 tie->setEndNote(nn);
984 }
985 else {
986 qDebug("cloneStaff: cannot find tie");
987 }
988 }
989 // add back spanners (going back from end to start spanner element
990 // makes sure the 'other' spanner anchor element is already set up)
991 // 'on' is the old spanner end note and 'nn' is the new spanner end note
992 for (Spanner* oldSp : on->spannerBack()) {
993 Note* newStart = Spanner::startElementFromSpanner(oldSp, nn);
994 if (newStart != nullptr) {
995 Spanner* newSp = toSpanner(oldSp->linkedClone());
996 newSp->setNoteSpan(newStart, nn);
997 score->addElement(newSp);
998 }
999 else {
1000 qDebug("cloneStaff: cannot find spanner start note");
1001 }
1002 }
1003 }
1004 // two note tremolo
1005 if (och->tremolo() && och->tremolo()->twoNotes()) {
1006 if (och == och->tremolo()->chord1()) {
1007 if (tremolo)
1008 qDebug("unconnected two note tremolo");
1009 tremolo = toTremolo(och->tremolo()->linkedClone());
1010 tremolo->setScore(nch->score());
1011 tremolo->setParent(nch);
1012 tremolo->setTrack(nch->track());
1013 tremolo->setChords(nch, 0);
1014 nch->setTremolo(tremolo);
1015 }
1016 else if (och == och->tremolo()->chord2()) {
1017 if (!tremolo)
1018 qDebug("first note for two note tremolo missing");
1019 else {
1020 tremolo->setChords(tremolo->chord1(), nch);
1021 nch->setTremolo(tremolo);
1022 }
1023 }
1024 else
1025 qDebug("inconsistent two note tremolo");
1026 }
1027 }
1028 }
1029 }
1030 }
1031 }
1032
1033 for (auto i : score->spanner()) {
1034 Spanner* s = i.second;
1035 int staffIdx = s->staffIdx();
1036 int dstTrack = -1;
1037 int dstTrack2 = -1;
1038 if (!(s->isVolta() || (s->isTextLine() && toTextLine(s)->systemFlag()))) {
1039 //export other spanner if staffidx matches
1040 if (srcStaffIdx == staffIdx) {
1041 dstTrack = dstStaffIdx * VOICES + s->voice();
1042 dstTrack2 = dstStaffIdx * VOICES + (s->track2() % VOICES);
1043 }
1044 }
1045 if (dstTrack == -1)
1046 continue;
1047 cloneSpanner(s, score, dstTrack, dstTrack2);
1048 }
1049 }
1050
1051 //---------------------------------------------------------
1052 // cloneStaff2
1053 // staves are potentially in different scores
1054 //---------------------------------------------------------
1055
cloneStaff2(Staff * srcStaff,Staff * dstStaff,const Fraction & stick,const Fraction & etick)1056 void Excerpt::cloneStaff2(Staff* srcStaff, Staff* dstStaff, const Fraction& stick, const Fraction& etick)
1057 {
1058 Score* oscore = srcStaff->score();
1059 Score* score = dstStaff->score();
1060
1061 Excerpt* oex = oscore->excerpt();
1062 Excerpt* ex = score->excerpt();
1063 QMultiMap<int, int> otracks, tracks;
1064 if (oex)
1065 otracks = oex->tracks();
1066 if (ex)
1067 tracks = ex->tracks();
1068
1069 Measure* m1 = oscore->tick2measure(stick);
1070 Measure* m2 = oscore->tick2measure(etick);
1071
1072 if (m2->tick() < etick) // end of score
1073 m2 = 0;
1074
1075 TieMap tieMap;
1076
1077 int srcStaffIdx = srcStaff->idx();
1078 int dstStaffIdx = dstStaff->idx();
1079
1080 int sTrack = srcStaffIdx * VOICES;
1081 int eTrack = sTrack + VOICES;
1082
1083 QMap<int, int> map;
1084 for (int i = sTrack; i < eTrack; i++) {
1085 if (!oex && !ex)
1086 map.insert(i, dstStaffIdx * VOICES + i % VOICES);
1087 else if (oex && !ex) {
1088 if (otracks.key(i, -1) != -1)
1089 map.insert(i, otracks.key(i));
1090 }
1091 else if (!oex && ex) {
1092 for (int j : tracks.values(i)) {
1093 if (dstStaffIdx * VOICES <= j && j < (dstStaffIdx + 1) * VOICES) {
1094 map.insert(i, j);
1095 break;
1096 }
1097 }
1098 }
1099 else if (oex && ex) {
1100 if (otracks.key(i, -1) != -1) {
1101 for (int j : tracks.values(otracks.key(i))) {
1102 if (dstStaffIdx * VOICES <= j && j < (dstStaffIdx + 1) * VOICES) {
1103 map.insert(i, j);
1104 break;
1105 }
1106 }
1107 }
1108 }
1109 }
1110
1111
1112 for (Measure* m = m1; m && (m != m2); m = m->nextMeasure()) {
1113 Measure* nm = score->tick2measure(m->tick());
1114 for (int srcTrack : map.keys()) {
1115 TupletMap tupletMap; // tuplets cannot cross measure boundaries
1116 int dstTrack = map.value(srcTrack);
1117 for (Segment* oseg = m->first(); oseg; oseg = oseg->next()) {
1118 Element* oe = oseg->element(srcTrack);
1119 if (oe == 0 || oe->generated())
1120 continue;
1121 if (oe->isTimeSig())
1122 continue;
1123 Segment* ns = nm->getSegment(oseg->segmentType(), oseg->tick());
1124 Element* ne = oe->linkedClone();
1125 ne->setTrack(dstTrack);
1126 ne->setParent(ns);
1127 ne->setScore(score);
1128 score->undoAddElement(ne);
1129 if (oe->isChordRest()) {
1130 ChordRest* ocr = toChordRest(oe);
1131 ChordRest* ncr = toChordRest(ne);
1132 Tuplet* ot = ocr->tuplet();
1133 if (ot) {
1134 Tuplet* nt = tupletMap.findNew(ot);
1135 if (nt == 0) {
1136 // nt = new Tuplet(*ot);
1137 nt = toTuplet(ot->linkedClone());
1138 nt->clear();
1139 nt->setTrack(dstTrack);
1140 nt->setParent(m);
1141 tupletMap.add(ot, nt);
1142 }
1143 ncr->setTuplet(nt);
1144 nt->add(ncr);
1145 }
1146
1147 for (Element* e : oseg->annotations()) {
1148 if (e->generated() || e->systemFlag())
1149 continue;
1150 if (e->track() != srcTrack)
1151 continue;
1152 switch (e->type()) {
1153 // exclude certain element types
1154 // this should be same list excluded in Score::undoAddElement()
1155 case ElementType::STAFF_TEXT:
1156 case ElementType::SYSTEM_TEXT:
1157 case ElementType::FRET_DIAGRAM:
1158 case ElementType::HARMONY:
1159 case ElementType::FIGURED_BASS:
1160 case ElementType::DYNAMIC:
1161 case ElementType::LYRICS: // not normally segment-attached
1162 continue;
1163 default:
1164 if (toTextLine(e)->systemFlag())
1165 continue;
1166 Element* ne1 = e->clone();
1167 ne1->setTrack(dstTrack);
1168 ne1->setParent(ns);
1169 ne1->setScore(score);
1170 score->undoAddElement(ne1);
1171 }
1172 }
1173 if (oe->isChord()) {
1174 Chord* och = toChord(ocr);
1175 Chord* nch = toChord(ncr);
1176 size_t n = och->notes().size();
1177 for (size_t i = 0; i < n; ++i) {
1178 Note* on = och->notes().at(i);
1179 Note* nn = nch->notes().at(i);
1180 if (on->tieFor()) {
1181 Tie* tie = toTie(on->tieFor()->linkedClone());
1182 tie->setScore(score);
1183 nn->setTieFor(tie);
1184 tie->setStartNote(nn);
1185 tie->setTrack(nn->track());
1186 tieMap.add(on->tieFor(), tie);
1187 }
1188 if (on->tieBack()) {
1189 Tie* tie = tieMap.findNew(on->tieBack());
1190 if (tie) {
1191 nn->setTieBack(tie);
1192 tie->setEndNote(nn);
1193 }
1194 else {
1195 qDebug("cloneStaff2: cannot find tie");
1196 }
1197 }
1198 }
1199 }
1200 }
1201 }
1202 }
1203 }
1204
1205 for (auto i : oscore->spanner()) {
1206 Spanner* s = i.second;
1207 if (!(s->tick() >= stick && s->tick2() < etick))
1208 continue;
1209
1210 int staffIdx = s->staffIdx();
1211 int dstTrack = -1;
1212 int dstTrack2 = -1;
1213 if (!(s->isVolta() || (s->isTextLine() && s->systemFlag()))) {
1214 //export other spanner if staffidx matches
1215 if (srcStaffIdx == staffIdx) {
1216 dstTrack = dstStaffIdx * VOICES + s->voice();
1217 dstTrack2 = dstStaffIdx * VOICES + (s->track2() % VOICES);
1218 }
1219 }
1220 if (dstTrack == -1)
1221 continue;
1222 cloneSpanner(s, score, dstTrack, dstTrack2);
1223 }
1224 }
1225
1226 //---------------------------------------------------------
1227 // createAllExcerpt
1228 //---------------------------------------------------------
1229
createAllExcerpt(MasterScore * score)1230 QList<Excerpt*> Excerpt::createAllExcerpt(MasterScore *score)
1231 {
1232 QList<Excerpt*> all;
1233 for (Part* part : score->parts()) {
1234 if (part->show()) {
1235 Excerpt* e = new Excerpt(score);
1236 e->parts().append(part);
1237 for (int i = part->startTrack(), j = 0; i < part->endTrack(); i++, j++) {
1238 e->tracks().insert(i, j);
1239 }
1240 QString name = createName(part->partName(), all);
1241 e->setTitle(name);
1242 all.append(e);
1243 }
1244 }
1245 return all;
1246 }
1247
1248 //---------------------------------------------------------
1249 // createName
1250 //---------------------------------------------------------
1251
createName(const QString & partName,QList<Excerpt * > & excerptList)1252 QString Excerpt::createName(const QString& partName, QList<Excerpt*>& excerptList)
1253 {
1254 QString name = partName.simplified();
1255 int count = 0; // no of occurrences of partName
1256
1257 for (Excerpt* e : excerptList) {
1258 // if <partName> already exists, change <partName> to <partName 1>
1259 if (e->title().compare(name) == 0)
1260 e->setTitle(e->title() + " 1");
1261
1262 QRegExp rx("^(.+)\\s\\d+$");
1263 if (rx.indexIn(e->title()) > -1 && rx.cap(1) == name)
1264 count++;
1265 }
1266
1267 if (count > 0)
1268 name += QString(" %1").arg(count + 1);
1269
1270 return name;
1271 }
1272
1273 //---------------------------------------------------------
1274 // setPartScore
1275 //---------------------------------------------------------
1276
setPartScore(Score * s)1277 void Excerpt::setPartScore(Score* s)
1278 {
1279 _partScore = s;
1280 s->setExcerpt(this);
1281 }
1282
1283 }
1284