//============================================================================= // MuseScore // Music Composition & Notation // // Copyright (C) 2012-2016 Werner Schweer // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 // as published by the Free Software Foundation and appearing in // the file LICENCE.GPL //============================================================================= #include "range.h" #include "measure.h" #include "segment.h" #include "rest.h" #include "chord.h" #include "score.h" #include "slur.h" #include "tie.h" #include "note.h" #include "tuplet.h" #include "barline.h" #include "utils.h" #include "staff.h" #include "excerpt.h" #include "repeat.h" #include "tremolo.h" namespace Ms { //--------------------------------------------------------- // cleanupTuplet //--------------------------------------------------------- static void cleanupTuplet(Tuplet* t) { const auto elements(t->elements()); t->clear(); for (DurationElement* e : elements) { e->setTuplet(nullptr); // prevent deleting the top tuplet by its children if (e->isTuplet()) { cleanupTuplet(toTuplet(e)); } delete e; } } //--------------------------------------------------------- // TrackList //--------------------------------------------------------- TrackList::~TrackList() { int n = size(); for (int i = 0; i < n; ++i) { Element* e = at(i); if (e->isTuplet()) { Tuplet* t = toTuplet(e); cleanupTuplet(t); } else { delete e; } } } //--------------------------------------------------------- // appendTuplet //--------------------------------------------------------- void TrackList::appendTuplet(Tuplet* srcTuplet, Tuplet* dstTuplet) { for (DurationElement* de : srcTuplet->elements()) { DurationElement* e = toDurationElement(de->clone()); dstTuplet->add(e); if (de->isTuplet()) { Tuplet* st = toTuplet(de); Tuplet* dt = toTuplet(e); appendTuplet(st, dt); } } } //--------------------------------------------------------- // combineTuplet //--------------------------------------------------------- void TrackList::combineTuplet(Tuplet* dst, Tuplet* src) { dst->setTicks(dst->ticks() * 2); dst->setBaseLen(dst->baseLen().shift(-1)); // try to combine tie'd notes unsigned idx = 0; if (dst->elements().back()->isChord() && src->elements().front()->isChord()) { Chord* chord = toChord(src->elements().front()); bool akkumulateChord = true; for (Note* n : chord->notes()) { if (!n->tieBack() || !n->tieBack()->generated()) { akkumulateChord = false; break; } } if (akkumulateChord) { Chord* bc = toChord(dst->elements().back()); bc->setTicks(bc->ticks() + chord->ticks()); // forward ties int i = 0; for (Note* n : bc->notes()) { n->setTieFor(chord->notes()[i]->tieFor()); ++i; } idx = 1; // skip first src element } } for (; idx < src->elements().size(); ++idx) { DurationElement* de = src->elements()[idx]; DurationElement* e = toDurationElement(de->clone()); dst->add(e); if (de->isTuplet()) { Tuplet* st = toTuplet(de); Tuplet* dt = toTuplet(e); appendTuplet(st, dt); } } } //--------------------------------------------------------- // append //--------------------------------------------------------- void TrackList::append(Element* e) { if (e->isDurationElement()) { _duration += toDurationElement(e)->ticks(); bool accumulateRest = e->isRest() && !empty() && back()->isRest(); Segment* s = accumulateRest ? toRest(e)->segment() : 0; if (s && !s->score()->isSpannerStartEnd(s->tick(), e->track()) && !s->annotations().size()) { // akkumulate rests Rest* rest = toRest(back()); Fraction du = rest->ticks(); du += toRest(e)->ticks(); rest->setTicks(du); } else { Element* element = 0; if (e->isTuplet()) { Tuplet* src = toTuplet(e); if (src->generated() && !empty() && back()->isTuplet()) { Tuplet* b = toTuplet(back()); combineTuplet(b, src); } else { element = e->clone(); Tuplet* dst = toTuplet(element); appendTuplet(src, dst); } } else { element = e->clone(); ChordRest* src = toChordRest(e); Segment* s1 = src->segment(); for (Element* ee : s1->annotations()) { if (ee->track() == e->track()) { _range->annotations.push_back({ s1->tick(), ee->clone() }); } } if (e->isChord()) { Chord* chord = toChord(e); bool akkumulateChord = true; for (Note* n : chord->notes()) { if (!n->tieBack() || !n->tieBack()->generated()) { akkumulateChord = false; break; } } if (akkumulateChord && !empty() && back()->isChord()) { Chord* bc = toChord(back()); const Fraction du = bc->ticks() + chord->ticks(); bc->setTicks(du); // forward ties int idx = 0; for (Note* n : bc->notes()) { n->setTieFor(chord->notes()[idx]->tieFor()); ++idx; } delete element; element = 0; } } } if (element) { element->setSelected(false); QList::append(element); } } } else { Element* c = e->clone(); c->setParent(0); QList::append(c); } } //--------------------------------------------------------- // appendGap //--------------------------------------------------------- void TrackList::appendGap(const Fraction& du) { if (du.isZero()) { return; } Element* e = empty() ? 0 : back(); if (e && e->isRest()) { Rest* rest = toRest(back()); Fraction dd = rest->ticks(); dd += du; _duration += du; rest->setTicks(dd); } else { Rest* rest = new Rest(0); rest->setTicks(du); QList::append(rest); _duration += du; } } //--------------------------------------------------------- // truncate // reduce len of last gap by f //--------------------------------------------------------- bool TrackList::truncate(const Fraction& f) { if (empty()) { return true; } Element* e = back(); if (!e->isRest()) { return false; } Rest* r = toRest(e); if (r->ticks() < f) { return false; } if (r->ticks() == f) { removeLast(); delete r; } else { r->setTicks(r->ticks() - f); } _duration -= f; return true; } //--------------------------------------------------------- // read //--------------------------------------------------------- void TrackList::read(const Segment* fs, const Segment* es) { Fraction tick = fs->tick(); const Segment* s; for (s = fs; s && (s != es); s = s->next1()) { if (!s->enabled()) { continue; } Element* e = s->element(_track); if (!e || e->generated()) { for (Element* ee : s->annotations()) { if (ee->track() == _track) { _range->annotations.push_back({ s->tick(), ee->clone() }); } } continue; } if (e->isRepeatMeasure()) { // TODO: copy previous measure contents? RepeatMeasure* rm = toRepeatMeasure(e); Rest r(*rm); append(&r); tick += r.ticks(); } else if (e->isChordRest()) { DurationElement* de = toDurationElement(e); Fraction gap = s->tick() - tick; if (de->tuplet()) { Tuplet* t = de->topTuplet(); s = skipTuplet(t); // continue with first chord/rest after tuplet de = t; } if (gap.isNotZero()) { appendGap(gap); tick += gap; } append(de); tick += de->ticks(); } else if (e->isBarLine()) { BarLine* bl = toBarLine(e); if (bl->barLineType() != BarLineType::NORMAL) { append(e); } } else { append(e); } } Fraction gap = es->tick() - tick; if (gap.isNotZero()) { appendGap(gap); } // // connect ties // int n = size(); for (int i = 0; i < n; ++i) { Element* e = at(i); if (!e->isChord()) { continue; } Chord* chord = toChord(e); for (Note* n1 : chord->notes()) { Tie* tie = n1->tieFor(); if (!tie) { continue; } for (int k = i + 1; k < n; ++k) { Element* ee = at(k); if (!ee->isChord()) { continue; } Chord* c2 = toChord(ee); bool found = false; for (Note* n2 : c2->notes()) { if (n1->pitch() == n2->pitch()) { tie->setEndNote(n2); n2->setTieBack(tie); found = true; break; } } if (!found) { qDebug("Tied note not found"); } break; } } } } //--------------------------------------------------------- // checkRest //--------------------------------------------------------- static void checkRest(Fraction& rest, Measure*& m, const Fraction& d) { if (rest.isZero()) { if (m->nextMeasure()) { m = m->nextMeasure(); rest = m->ticks(); } else { qFatal("premature end of measure list, rest %d/%d", d.numerator(), d.denominator()); } } } //--------------------------------------------------------- // writeTuplet // measure - current measure // rest - available time in measure //--------------------------------------------------------- Tuplet* TrackList::writeTuplet(Tuplet* parent, Tuplet* tuplet, Measure*& measure, Fraction& rest) const { Score* score = measure->score(); Tuplet* dt = tuplet->clone(); dt->setParent(measure); Fraction du = tuplet->ticks(); if (du > rest) { // we must split the tuplet dt->setTicks(du * Fraction(1, 2)); dt->setBaseLen(tuplet->baseLen().shift(1)); } if (parent) { parent->add(dt); } for (DurationElement* e : tuplet->elements()) { Fraction duration = e->globalTicks(); Tuplet* tt = dt; Fraction ratio = Fraction(1, 1); while (tt) { ratio *= tt->ratio(); tt = tt->tuplet(); } bool firstpart = true; while (duration > Fraction(0,1)) { if (rest.isZero()) { if (measure->nextMeasure()) { measure = measure->nextMeasure(); rest = measure->ticks(); if (e != tuplet->elements().back()) { // create second part of split tuplet dt = dt->clone(); dt->setGenerated(true); dt->setParent(measure); Tuplet* pt = dt; while (parent) { Tuplet* tt1 = parent->clone(); tt1->setGenerated(true); tt1->setParent(measure); tt1->add(pt); pt = tt1; parent = parent->tuplet(); } } } else { qFatal("premature end of measure list in track %d, rest %d/%d", _track, duration.numerator(), duration.denominator()); } } if (e->isChordRest()) { Fraction dd = qMin(rest, duration) * ratio; std::vector dl = toDurationList(dd, false); for (const TDuration& k : dl) { Segment* segment = measure->undoGetSegmentR(SegmentType::ChordRest, measure->ticks() - rest); Fraction gd = k.fraction() / ratio; ChordRest* cr = toChordRest(e->clone()); if (!firstpart) { cr->removeMarkings(true); } cr->setScore(score); cr->setTrack(_track); segment->add(cr); cr->setTicks(k.fraction()); cr->setDurationType(k); rest -= gd; duration -= gd; if (cr->isChord()) { for (Note* note : toChord(cr)->notes()) { if (!duration.isZero() && !note->tieFor()) { Tie* tie = new Tie(score); tie->setGenerated(true); note->add(tie); } } } dt->add(cr); firstpart = false; } } else if (e->isTuplet()) { Tuplet* tt1 = toTuplet(e); Tuplet* ttt = writeTuplet(dt, tt1, measure, rest); dt = ttt->tuplet(); parent = dt->tuplet(); duration = Fraction(); } firstpart = false; } } return dt; } //--------------------------------------------------------- // write // rewrite notes into measure list measure //--------------------------------------------------------- bool TrackList::write(Score* score, const Fraction& tick) const { if ((_track % VOICES) && size() == 1 && at(0)->isRest()) { // don’t write rests in voice > 0 return true; } Measure* measure = score->tick2measure(tick); Measure* m = measure; Fraction remains = m->endTick() - tick; Segment* segment = 0; for (Element* e : *this) { if (e->isDurationElement()) { Fraction duration = toDurationElement(e)->ticks(); checkRest(remains, m, duration); // go to next measure, if necessary if (duration > remains && e->isTuplet()) { // experimental: allow tuplet split in the middle if (duration != remains * 2) { MScore::setError(CANNOT_SPLIT_TUPLET); return false; } } bool firstpart = true; while (duration > Fraction(0,1)) { if ((e->isRest() || e->isRepeatMeasure()) && (duration >= remains || e == back()) && (remains == m->ticks())) { // // handle full measure rest // Segment* seg = m->getSegmentR(SegmentType::ChordRest, m->ticks() - remains); if ((_track % VOICES) == 0) { // write only for voice 1 Rest* r = new Rest(score, TDuration::DurationType::V_MEASURE); // ideally we should be using stretchedLen // but this is not valid during rewrite when adding time signatures // since the time signature has not been added yet //Fraction stretchedLen = m->stretchedLen(staff); //r->setTicks(stretchedLen); r->setTicks(m->ticks()); r->setTrack(_track); seg->add(r); } duration -= m->ticks(); remains.set(0, 1); } else if (e->isChordRest()) { Fraction du = qMin(remains, duration); std::vector dl = toDurationList(du, e->isChord()); Q_ASSERT(!dl.empty()); for (const TDuration& k : dl) { segment = m->undoGetSegmentR(SegmentType::ChordRest, m->ticks() - remains); ChordRest* cr = toChordRest(e->clone()); if (!firstpart) { cr->removeMarkings(true); } cr->setTrack(_track); cr->setScore(score); Fraction gd = k.fraction(); cr->setTicks(gd); cr->setDurationType(k); segment->add(cr); duration -= gd; remains -= gd; if (cr->isChord()) { if (!firstpart && toChord(cr)->tremolo() && toChord(cr)->tremolo()->twoNotes()) { // remove partial two-note tremolo if (toChord(e)->tremolo()->chord1() == toChord(e)) { toChord(cr)->tremolo()->setChords(toChord(cr),nullptr); } else { toChord(cr)->tremolo()->setChords(nullptr,toChord(cr)); } Tremolo* tremoloPointer = toChord(cr)->tremolo(); toChord(cr)->setTremolo(nullptr); delete tremoloPointer; } for (Note* note : toChord(cr)->notes()) { if (!duration.isZero() && !note->tieFor()) { Tie* tie = new Tie(score); tie->setGenerated(true); note->add(tie); } } } } } else if (e->isTuplet()) { writeTuplet(0, toTuplet(e), m, remains); duration = Fraction(); } firstpart = false; if (duration > Fraction(0,1)) { checkRest(remains, m, duration); // go to next measure, if necessary } } } else if (e->isBarLine()) { // if (pos.numerator() == 0 && m) { // BarLineType t = toBarLine(e)->barLineType(); // Measure* pm = m->prevMeasure(); //TODO if (pm) // pm->setEndBarLineType(t,0); // } } else if (e->isClef()) { Segment* seg; if (remains == m->ticks() && m->tick() > Fraction(0,1)) { Measure* pm = m->prevMeasure(); seg = pm->getSegmentR(SegmentType::Clef, pm->ticks()); } else if (remains != m->ticks()) { seg = m->getSegmentR(SegmentType::Clef, m->ticks() - remains); } else { seg = m->getSegmentR(SegmentType::HeaderClef, Fraction(0,1)); } Element* ne = e->clone(); ne->setScore(score); ne->setTrack(_track); seg->add(ne); } else { if (!m) { break; } // add the element in its own segment; // but KeySig has to be at start of (current) measure Segment* seg = m->getSegmentR(Segment::segmentType(e->type()), e->isKeySig() ? Fraction() : m->ticks() - remains); Element* ne = e->clone(); ne->setScore(score); ne->setTrack(_track); seg->add(ne); } } // // connect ties from measure->first() to segment // for (Segment* s = measure->first(); s; s = s->next1()) { Element* e = s->element(_track); if (!e || !e->isChord()) { continue; } Chord* chord = toChord(e); for (Note* n : chord->notes()) { Tie* tie = n->tieFor(); if (!tie) { continue; } Note* nn = searchTieNote(n); if (nn) { tie->setEndNote(nn); nn->setTieBack(tie); } } if (s == segment) { break; } } return true; } //--------------------------------------------------------- // ScoreRange //--------------------------------------------------------- ScoreRange::~ScoreRange() { qDeleteAll(tracks); } //--------------------------------------------------------- // read //--------------------------------------------------------- void ScoreRange::read(Segment* first, Segment* last, bool readSpanner) { _first = first; _last = last; Score* score = first->score(); QList sl = score->uniqueStaves(); int startTrack = 0; int endTrack = score->nstaves() * VOICES; spanner.clear(); if (readSpanner) { Fraction stick = first->tick(); Fraction etick = last->tick(); for (auto i : first->score()->spanner()) { Spanner* s = i.second; if (s->tick() >= stick && s->tick() < etick && s->track() >= startTrack && s->track() < endTrack) { Spanner* ns = toSpanner(s->clone()); ns->setParent(0); ns->setStartElement(0); ns->setEndElement(0); ns->setTick(ns->tick() - stick); spanner.push_back(ns); } } } for (int staffIdx : sl) { int sTrack = staffIdx * VOICES; int eTrack = sTrack + VOICES; for (int track = sTrack; track < eTrack; ++track) { TrackList* dl = new TrackList(this); dl->setTrack(track); dl->read(first, last); tracks.append(dl); } } } //--------------------------------------------------------- // write //--------------------------------------------------------- bool ScoreRange::write(Score* score, const Fraction& tick) const { for (TrackList* dl : tracks) { int track = dl->track(); if (!dl->write(score, tick)) { return false; } if ((track % VOICES) == VOICES - 1) { // clone staff if appropriate after all voices have been copied int staffIdx = track / VOICES; Staff* ostaff = score->staff(staffIdx); const LinkedElements* linkedStaves = ostaff->links(); if (linkedStaves) { for (auto le : *linkedStaves) { Staff* nstaff = toStaff(le); if (nstaff == ostaff) { continue; } Excerpt::cloneStaff2(ostaff, nstaff, tick, (tick + dl->ticks())); } } } ++track; } for (Spanner* s : spanner) { s->setTick(s->tick() + tick); if (s->isSlur()) { Slur* slur = toSlur(s); if (slur->startCR()->isGrace()) { Chord* sc = slur->startChord(); int idx = sc->graceIndex(); Chord* dc = toChord(score->findCR(s->tick(), s->track())); s->setStartElement(dc->graceNotes()[idx]); } else { s->setStartElement(0); } if (slur->endCR()->isGrace()) { Chord* sc = slur->endChord(); int idx = sc->graceIndex(); Chord* dc = toChord(score->findCR(s->tick2(), s->track2())); s->setEndElement(dc->graceNotes()[idx]); } else { s->setEndElement(0); } } score->undoAddElement(s); } for (const Annotation& a : annotations) { Measure* tm = score->tick2measure(a.tick); Segment* op = toSegment(a.e->parent()); Segment* s = tm->undoGetSegment(op->segmentType(), a.tick); if (s) { a.e->setParent(s); score->undoAddElement(a.e); } } return true; } //--------------------------------------------------------- // fill //--------------------------------------------------------- void ScoreRange::fill(const Fraction& f) { const Fraction oldDuration = ticks(); Fraction oldEndTick = _first->tick() + oldDuration; for (auto t : tracks) { t->appendGap(f); } Fraction diff = ticks() - oldDuration; for (Spanner* sp : spanner) { if (sp->tick2() >= oldEndTick && sp->tick() < oldEndTick) { sp->setTicks(sp->ticks() + diff); } } } //--------------------------------------------------------- // truncate // reduce len of last gap by f //--------------------------------------------------------- bool ScoreRange::truncate(const Fraction& f) { for (TrackList* dl : tracks) { if (dl->empty()) { continue; } Element* e = dl->back(); if (!e->isRest()) { return false; } Rest* r = toRest(e); if (r->ticks() < f) { return false; } } for (TrackList* dl : tracks) { dl->truncate(f); } return true; } //--------------------------------------------------------- // ticks //--------------------------------------------------------- Fraction ScoreRange::ticks() const { return tracks.empty() ? Fraction() : tracks[0]->ticks(); } //--------------------------------------------------------- // dump //--------------------------------------------------------- void TrackList::dump() const { qDebug("elements %d, duration %d/%d", size(), _duration.numerator(), _duration.denominator()); for (Element* e : *this) { if (e->isDurationElement()) { Fraction du = toDurationElement(e)->ticks(); qDebug(" %s %d/%d", e->name(), du.numerator(), du.denominator()); } else { qDebug(" %s", e->name()); } } } }