MuseScore/libmscore/range.cpp

718 lines
27 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2012-2016 Werner Schweer
2012-05-26 14:26:10 +02:00
//
// 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"
2013-08-22 12:18:14 +02:00
#include "tie.h"
2012-05-26 14:26:10 +02:00
#include "note.h"
#include "tuplet.h"
#include "barline.h"
2012-05-26 14:26:10 +02:00
#include "utils.h"
2014-05-14 19:19:29 +02:00
#include "staff.h"
#include "excerpt.h"
2012-05-26 14:26:10 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// cleanupTuplet
//---------------------------------------------------------
static void cleanupTuplet(Tuplet* t)
{
foreach (DurationElement* e, t->elements()) {
if (e->isTuplet())
cleanupTuplet(toTuplet(e));
2012-05-26 14:26:10 +02:00
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);
2012-05-26 14:26:10 +02:00
cleanupTuplet(t);
}
else
delete e;
}
}
//---------------------------------------------------------
// appendTuplet
//---------------------------------------------------------
void TrackList::appendTuplet(Tuplet* srcTuplet, Tuplet* dstTuplet)
{
for (DurationElement* de : srcTuplet->elements()) {
2016-11-29 09:26:43 +01:00
DurationElement* e = toDurationElement(de->clone());
dstTuplet->add(e);
if (de->isTuplet()) {
Tuplet* st = toTuplet(de);
Tuplet* dt = toTuplet(e);
appendTuplet(st, dt);
}
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// append
//---------------------------------------------------------
2013-06-19 16:25:29 +02:00
void TrackList::append(Element* e)
2012-05-26 14:26:10 +02:00
{
if (e->isDurationElement()) {
2016-11-29 09:26:43 +01:00
Fraction d = toDurationElement(e)->duration();
2012-05-26 14:26:10 +02:00
_duration += d;
bool accumulateRest = e->isRest() && !empty() && back()->isRest();
Segment* s = accumulateRest ? toRest(e)->segment() : 0;
2012-05-26 14:26:10 +02:00
if (s && !s->score()->isSpannerStartEnd(s->tick(), e->track()) && !s->annotations().size()) {
2012-05-26 14:26:10 +02:00
// akkumulate rests
Rest* rest = toRest(back());
2012-05-26 14:26:10 +02:00
Fraction d = rest->duration();
d += toRest(e)->duration();
2012-05-26 14:26:10 +02:00
rest->setDuration(d);
}
2013-06-10 11:03:34 +02:00
else
{
2012-05-26 14:26:10 +02:00
Element* element = e->clone();
QList<Element*>::append(element);
if (e->isTuplet()) {
Tuplet* srcTuplet = toTuplet(e);
Tuplet* dstTuplet = toTuplet(element);
appendTuplet(srcTuplet, dstTuplet);
2012-05-26 14:26:10 +02:00
}
else {
ChordRest* src = toChordRest(e);
2012-05-26 14:26:10 +02:00
Segment* s = src->segment();
for (Element* ee : s->annotations()) {
2012-05-26 14:26:10 +02:00
if (ee->track() == e->track())
2013-06-19 16:25:29 +02:00
_range->annotations.push_back({ s->tick(), ee->clone() });
2012-05-26 14:26:10 +02:00
}
}
}
}
else
QList<Element*>::append(e->clone());
}
//---------------------------------------------------------
// appendGap
//---------------------------------------------------------
void TrackList::appendGap(const Fraction& d)
{
2014-05-14 19:19:29 +02:00
if (d.isZero())
return;
2016-02-06 22:03:43 +01:00
Element* e = empty() ? 0 : back();
if (e && e->isRest()) {
Rest* rest = toRest(back());
2012-05-26 14:26:10 +02:00
Fraction dd = rest->duration();
dd += d;
_duration += d;
2012-05-26 14:26:10 +02:00
rest->setDuration(dd);
}
else {
Rest* rest = new Rest(0);
rest->setDuration(d);
QList<Element*>::append(rest);
2013-01-18 14:42:11 +01:00
_duration += d;
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2014-11-13 11:53:42 +01:00
void TrackList::read(const Segment* fs, const Segment* es)
2012-05-26 14:26:10 +02:00
{
int tick = fs->tick();
int gap = 0;
2016-03-30 22:33:04 +02:00
while (fs && !fs->enabled())
fs = fs->next1();
const Segment* s;
for (s = fs; s && (s != es); s = s->next1enabled()) {
2014-11-13 11:53:42 +01:00
Element* e = s->element(_track);
if (!e || e->generated()) {
for (Element* ee : s->annotations()) {
2014-11-13 11:53:42 +01:00
if (ee->track() == _track)
_range->annotations.push_back({ s->tick(), ee->clone() });
}
2013-01-18 14:42:11 +01:00
continue;
}
2013-01-18 14:42:11 +01:00
if (e->isChordRest()) {
DurationElement* de = toDurationElement(e);
2013-01-18 14:42:11 +01:00
gap = s->tick() - tick;
if (de->tuplet()) {
// find top tuplet
2013-01-18 14:42:11 +01:00
Tuplet* tuplet = de->tuplet();
while (tuplet->tuplet())
tuplet = tuplet->tuplet();
2013-01-18 14:42:11 +01:00
de = tuplet;
s = skipTuplet(tuplet);
2013-01-18 14:42:11 +01:00
// continue with first chord/rest after tuplet
2012-05-26 14:26:10 +02:00
}
2013-01-18 14:42:11 +01:00
if (gap) {
appendGap(Fraction::fromTicks(gap));
tick += gap;
}
2013-06-19 16:25:29 +02:00
append(de);
2014-11-10 13:41:25 +01:00
tick += de->duration().ticks();
2012-05-26 14:26:10 +02:00
}
else if (e->isBarLine()) {
BarLine* bl = toBarLine(e);
if (bl->barLineType() != BarLineType::NORMAL)
append(e);
}
// else if (e->type() == Element::REPEAT_MEASURE) {
// // TODO: copy previous measure contents?
// }
2013-01-18 14:42:11 +01:00
else
2013-06-19 16:25:29 +02:00
append(e);
2012-05-26 14:26:10 +02:00
}
gap = es->tick() - tick;
if (gap)
appendGap(Fraction::fromTicks(gap));
//
// connect ties
//
int n = size();
for (int i = 0; i < n; ++i) {
Element* e = at(i);
if (!e->isChord())
2012-05-26 14:26:10 +02:00
continue;
Chord* chord = toChord(e);
for (Note* n1 : chord->notes()) {
2012-05-26 14:26:10 +02:00
Tie* tie = n1->tieFor();
if (!tie)
continue;
for (int k = i+1; k < n; ++k) {
Element* ee = at(k);
if (!ee->isChord())
2012-05-26 14:26:10 +02:00
continue;
Chord* c2 = toChord(ee);
2012-05-26 14:26:10 +02:00
bool found = false;
for (Note* n2 : c2->notes()) {
2012-05-26 14:26:10 +02:00
if (n1->pitch() == n2->pitch()) {
tie->setEndNote(n2);
n2->setTieBack(tie);
found = true;
break;
}
}
if (!found)
2012-12-05 14:01:41 +01:00
qDebug("Tied note not found");
2012-05-26 14:26:10 +02:00
break;
}
}
}
}
//---------------------------------------------------------
// writeTuplet
// measure - current measure
// rest - available time in measure
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Tuplet* TrackList::writeTuplet(Tuplet* parent, Tuplet* tuplet, Measure*& measure, Fraction& rest) const
2012-05-26 14:26:10 +02:00
{
Score* score = measure->score();
Tuplet* dt = tuplet->clone();
2012-05-26 14:26:10 +02:00
dt->setParent(measure);
Fraction d = tuplet->duration();
if (d > rest) {
// we must split the tuplet
dt->setDuration(d * Fraction(1, 2));
dt->setBaseLen(tuplet->baseLen().shift(1));
}
if (parent)
parent->add(dt);
for (DurationElement* e : tuplet->elements()) {
Fraction duration = e->globalDuration();
Tuplet* tt = dt;
Fraction ratio = Fraction(1, 1);
while (tt) {
ratio *= tt->ratio();
tt = tt->tuplet();
2012-05-26 14:26:10 +02:00
}
bool firstpart = true;
while (duration > 0) {
Fraction d = qMin(rest, duration);
if (e->isChordRest()) {
Fraction dd = d * ratio;
std::vector<TDuration> dl = toDurationList(dd, false);
for (const TDuration& k : dl) {
Segment* segment = measure->getSegment(Segment::Type::ChordRest, measure->len() - rest);
Fraction gd = k.fraction() / ratio;
ChordRest* cr = toChordRest(e->clone());
cr->setScore(score);
cr->setTrack(_track);
segment->add(cr);
cr->setDuration(k.fraction());
cr->setDurationType(k);
rest -= gd;
duration -= gd;
if (cr->isChord()) {
Chord* c = toChord(cr);
if (!firstpart)
c->removeMarkings(true);
for (Note* note : c->notes()) {
if (!duration.isZero() || note->tieFor()) {
Tie* tie = new Tie(score);
note->add(tie);
}
else
note->setTieFor(0);
note->setTieBack(0);
}
}
dt->add(cr);
firstpart = false;
}
}
else if (e->isTuplet()) {
Tuplet* tt = toTuplet(e);
Tuplet* ttt = writeTuplet(dt, tt, measure, rest);
dt = ttt->tuplet();
parent = dt->tuplet();
duration = Fraction();
}
if (rest.isZero()) {
if (measure->nextMeasure()) {
measure = measure->nextMeasure();
rest = measure->len();
if (e != tuplet->elements().back()) {
// create second part of splitted tuplet
dt = dt->clone();
dt->setParent(measure);
2016-11-29 13:38:25 +01:00
Tuplet* pt = dt;
while (parent) {
Tuplet* tt = parent->clone();
tt->setParent(measure);
tt->add(pt);
pt = tt;
parent = parent->tuplet();
2016-11-29 09:26:43 +01:00
}
}
}
else {
if (!duration.isZero()) {
qFatal("Tracklist::write: premature end of measure list in track %d, rest %d/%d",
_track, duration.numerator(), duration.denominator());
}
}
}
firstpart = false;
2012-05-26 14:26:10 +02:00
}
}
return dt;
}
//---------------------------------------------------------
// canWrite
// check if list can be written to measure list m
// check for tuplets crossing barlines
//---------------------------------------------------------
bool TrackList::canWrite(const Fraction& measureLen) const
{
Fraction pos;
Fraction rest = measureLen;
for (Element* e : *this) {
if (!e->isDurationElement())
continue;
Fraction duration = toDurationElement(e)->duration();
if (duration > rest && e->isTuplet()) {
// Tuplet* t = toTuplet(e);
if (duration == rest * 2) {
// split tuplet in middle
}
else {
// cannot split tuplet
2012-05-26 14:26:10 +02:00
return false;
}
}
while (!duration.isZero()) {
if (e->isRest() && duration >= rest && rest == measureLen) {
duration -= rest;
pos = measureLen;
}
else {
Fraction d = qMin(rest, duration);
duration -= d;
rest -= d;
pos += d;
}
if (pos == measureLen) {
pos = Fraction();
rest = measureLen;
2012-05-26 14:26:10 +02:00
}
}
}
return true;
}
2013-06-19 16:25:29 +02:00
//---------------------------------------------------------
// dump
//---------------------------------------------------------
2013-06-10 11:03:34 +02:00
void TrackList::dump() const
{
2014-05-15 13:42:03 +02:00
qDebug("TrackList: elements %d, duration %d/%d", size(), _duration.numerator(), _duration.denominator());
2016-11-29 09:26:43 +01:00
for (Element* e : *this) {
2014-05-15 13:42:03 +02:00
qDebug(" %s", e->name());
2013-06-10 11:03:34 +02:00
if (e->isDurationElement()) {
2016-11-29 09:26:43 +01:00
Fraction d = toDurationElement(e)->duration();
2014-05-15 13:42:03 +02:00
qDebug(" duration %d/%d", d.numerator(), d.denominator());
2013-06-10 11:03:34 +02:00
}
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// write
2014-11-13 11:53:42 +01:00
// rewrite notes into measure list measure
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2014-11-13 11:53:42 +01:00
bool TrackList::write(Measure* measure) const
2012-05-26 14:26:10 +02:00
{
Fraction pos;
Measure* m = measure;
Score* score = m->score();
Fraction rest = m->len();
Segment* segment = 0;
for (Element* e : *this) {
2012-05-26 14:26:10 +02:00
if (e->isDurationElement()) {
Fraction duration = toDurationElement(e)->duration();
if (duration > rest && e->isTuplet()) {
// experimental: allow split of tuplet in the middle
if (duration != rest * 2) {
MScore::setError(CANNOT_SPLIT_TUPLET);
return false;
}
2012-05-26 14:26:10 +02:00
}
//
// split note/rest
//
bool firstpart = true;
while (duration > 0) {
2016-10-20 11:32:07 +02:00
if ((e->isRest() || e->isRepeatMeasure()) && (duration >= rest || e == back()) && (rest == m->len())) {
2012-05-26 14:26:10 +02:00
//
// handle full measure rest
//
segment = m->getSegment(Segment::Type::ChordRest, pos);
2014-11-13 11:53:42 +01:00
if ((_track % VOICES) == 0) {
2012-05-26 14:26:10 +02:00
// 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
2015-03-20 07:11:30 +01:00
//Fraction stretchedLen = m->stretchedLen(staff);
//r->setDuration(stretchedLen);
r->setDuration(m->len());
2014-11-13 11:53:42 +01:00
r->setTrack(_track);
2012-05-26 14:26:10 +02:00
segment->add(r);
}
duration -= m->len();
pos += m->len();
rest.set(0, 1);
}
else {
Fraction d = qMin(rest, duration);
if (e->isRest() || e->isRepeatMeasure()) {
2016-02-06 22:03:43 +01:00
for (const TDuration& k : toDurationList(d, false)) {
2014-11-25 14:38:38 +01:00
Rest* r = new Rest(score, k);
Fraction dd(k.fraction());
r->setTrack(_track);
segment = m->getSegment(Segment::Type::ChordRest, pos);
2014-11-25 14:38:38 +01:00
segment->add(r);
duration -= dd;
rest -= dd;
pos += dd;
}
2012-05-26 14:26:10 +02:00
}
2016-10-20 11:32:07 +02:00
else if (e->isChord()) {
segment = m->getSegment(Segment::Type::ChordRest, pos);
2016-10-20 11:32:07 +02:00
Chord* c = toChord(e)->clone();
if (!firstpart)
c->removeMarkings(true);
2012-05-26 14:26:10 +02:00
c->setScore(score);
2014-11-13 11:53:42 +01:00
c->setTrack(_track);
2012-05-26 14:26:10 +02:00
c->setDuration(d);
c->setDurationType(TDuration(d));
segment->add(c);
duration -= d;
rest -= d;
pos += d;
for (Note* note : c->notes()) {
2012-05-26 14:26:10 +02:00
if (!duration.isZero() || note->tieFor()) {
Tie* tie = new Tie(score);
note->add(tie);
}
else
note->setTieFor(0);
note->setTieBack(0);
}
}
else if (e->isTuplet()) {
writeTuplet(0, toTuplet(e), m, rest);
pos = m->len() - rest;
duration = Fraction();
2012-05-26 14:26:10 +02:00
}
}
if (pos == m->len()) {
if (m->nextMeasure()) {
m = m->nextMeasure();
2012-05-26 14:26:10 +02:00
rest = m->len();
pos = Fraction();
}
2013-01-18 14:42:11 +01:00
else {
if (!duration.isZero()) {
qFatal("Tracklist::write: premature end of measure list in track %d, rest %d/%d",
2014-11-13 11:53:42 +01:00
_track, duration.numerator(), duration.denominator());
2013-01-18 14:42:11 +01:00
}
}
2012-05-26 14:26:10 +02:00
}
firstpart = false;
2012-05-26 14:26:10 +02:00
}
}
2016-10-20 11:32:07 +02:00
else if (e->isBarLine()) {
if (pos.numerator() == 0 && m) {
// BarLineType t = toBarLine(e)->barLineType();
2016-01-04 14:48:58 +01:00
// Measure* pm = m->prevMeasure();
//TODO if (pm)
// pm->setEndBarLineType(t,0);
}
}
else if (e->isClef()) {
Segment* segment;
if (pos.ticks() == 0 && m->tick() > 0) {
Measure* pm = m->prevMeasure();
segment = pm->getSegment(Segment::Type::Clef, pm->len());
}
else if (!pos.isZero())
segment = m->getSegment(Segment::Type::Clef, pos);
else
segment = m->getSegment(Segment::Type::HeaderClef, pos);
Element* ne = e->clone();
ne->setScore(score);
ne->setTrack(_track);
segment->add(ne);
}
2012-05-26 14:26:10 +02:00
else {
2016-10-20 11:32:07 +02:00
if (!m)
2012-05-26 14:26:10 +02:00
break;
// add the element in its own segment;
// but KeySig has to be at start of (current) measure
Segment* segment = m->getSegment(Segment::segmentType(e->type()), e->isKeySig() ? Fraction() : pos);
2012-05-26 14:26:10 +02:00
Element* ne = e->clone();
ne->setScore(score);
2014-11-13 11:53:42 +01:00
ne->setTrack(_track);
2012-05-26 14:26:10 +02:00
segment->add(ne);
}
}
//
// connect ties
//
2014-08-11 21:17:55 +02:00
if (!segment)
return true;
2012-05-26 14:26:10 +02:00
for (Segment* s = measure->first(); s; s = s->next1()) {
Element* e = s->element(_track);
if (!e || !e->isChord())
2012-05-26 14:26:10 +02:00
continue;
Chord* chord = toChord(e);
for (Note* n : chord->notes()) {
2012-05-26 14:26:10 +02:00
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);
}
//---------------------------------------------------------
// canWrite
//---------------------------------------------------------
bool ScoreRange::canWrite(const Fraction& f) const
{
int n = tracks.size();
for (int i = 0; i < n; ++i) {
TrackList* dl = tracks[i];
if (!dl->canWrite(f))
return false;
}
return true;
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2014-05-14 19:19:29 +02:00
void ScoreRange::read(Segment* first, Segment* last)
2012-05-26 14:26:10 +02:00
{
_first = first;
_last = last;
Score* score = first->score();
2014-11-13 11:53:42 +01:00
QList<int> sl = score->uniqueStaves();
2014-05-14 19:19:29 +02:00
int startTrack = 0;
2014-11-13 11:53:42 +01:00
int endTrack = score->nstaves() * VOICES;
2013-06-19 16:25:29 +02:00
spanner.clear();
2013-06-20 13:57:15 +02:00
for (auto i : first->score()->spanner()) {
Spanner* s = i.second;
2013-06-19 16:25:29 +02:00
if (s->tick() >= first->tick() && s->tick() < last->tick() &&
s->track() >= startTrack && s->track() < endTrack) {
Spanner* ns = static_cast<Spanner*>(s->clone());
ns->setTick(ns->tick() - first->tick());
2013-10-14 11:56:54 +02:00
ns->setTick2(ns->tick2() - first->tick());
2013-06-19 16:25:29 +02:00
spanner.push_back(ns);
}
}
2014-11-13 11:53:42 +01:00
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);
}
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
2014-05-14 19:19:29 +02:00
bool ScoreRange::write(Score* score, int tick) const
2012-05-26 14:26:10 +02:00
{
2014-05-14 19:19:29 +02:00
for (TrackList* dl : tracks) {
2014-11-13 11:53:42 +01:00
int track = dl->track();
if (!dl->write(score->tick2measure(tick)))
2012-05-26 14:26:10 +02:00
return false;
if ((track % VOICES) == VOICES - 1) {
// clone staff if appropriate after all voices have been copied
2014-05-14 19:19:29 +02:00
int staffIdx = track / VOICES;
Staff* ostaff = score->staff(staffIdx);
LinkedStaves* linkedStaves = ostaff->linkedStaves();
if (linkedStaves) {
for (Staff* nstaff : linkedStaves->staves()) {
if (nstaff == ostaff)
continue;
Excerpt::cloneStaff2(ostaff, nstaff, tick, tick + dl->duration().ticks());
2014-05-14 19:19:29 +02:00
}
}
}
++track;
}
2013-06-19 16:25:29 +02:00
for (Spanner* s : spanner) {
s->setTick(s->tick() + first()->tick());
s->setTick2(s->tick2() + first()->tick());
if (s->isSlur()) {
Slur* slur = toSlur(s);
2014-07-27 18:55:05 +02:00
if (slur->startCR()->isGrace()) {
Chord* sc = slur->startChord();
int idx = sc->graceIndex();
Chord* dc = toChord(score->findCR(s->tick(), s->track()));
2014-07-27 18:55:05 +02:00
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()));
2014-07-27 18:55:05 +02:00
s->setEndElement(dc->graceNotes()[idx]);
}
else
s->setEndElement(0);
}
2013-06-19 16:25:29 +02:00
score->undoAddElement(s);
2012-05-26 14:26:10 +02:00
}
2013-06-19 16:25:29 +02:00
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);
2013-06-19 16:25:29 +02:00
if (s) {
a.e->setParent(s);
score->undoAddElement(a.e);
2013-01-18 14:42:11 +01:00
}
}
2014-05-14 19:19:29 +02:00
return true;
2013-01-18 14:42:11 +01:00
}
//---------------------------------------------------------
// fill
//---------------------------------------------------------
void ScoreRange::fill(const Fraction& f)
{
for (auto t : tracks)
t->appendGap(f);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// duration
//---------------------------------------------------------
Fraction ScoreRange::duration() const
{
2016-02-06 22:03:43 +01:00
return tracks.empty() ? Fraction() : tracks[0]->duration();
2012-05-26 14:26:10 +02:00
}
2013-05-13 18:49:17 +02:00
}