Skip to content

Commit

Permalink
fix musescore#19373 move all hairpins; insert measure always acts in …
Browse files Browse the repository at this point in the history
…master score
  • Loading branch information
sammik committed Oct 2, 2023
1 parent da9cbdc commit 20d0778
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 308 deletions.
18 changes: 17 additions & 1 deletion src/engraving/dom/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,23 @@ void Box::manageExclusionFromParts(bool exclude)
if (score == this->score()) {
continue;
}
MeasureBase* newFrame = score->insertMeasure(type(), next());
MeasureBase* newMB = nullptr;
if (!excludeFromOtherParts()) {
for (auto e : linkList()) {
if (e->score() == score) {
newMB = toMeasureBase(e);
break;
}
}
}
// no linked frame found in score; use measure as insert point
if (!newMB) {
newMB = score->tick2measure(tick());
}
if (!newMB) {
LOGD("measure base not found in score");
}
MeasureBase* newFrame = score->insertMeasure(type(), newMB);
newFrame->setExcludeFromOtherParts(false);
newFrames.push_back(newFrame);
}
Expand Down
341 changes: 55 additions & 286 deletions src/engraving/dom/edit.cpp

Large diffs are not rendered by default.

5 changes: 1 addition & 4 deletions src/engraving/dom/excerpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,7 @@ void Excerpt::createExcerpt(Excerpt* excerpt)
MeasureBase* scoreMeasure = score->first();

if ((!scoreMeasure || !scoreMeasure->isVBox()) && !masterMeasure->excludeFromOtherParts()) {
Score::InsertMeasureOptions options;
options.addToAllScores = false;

score->insertMeasure(ElementType::VBOX, scoreMeasure, options);
score->insertMeasure(ElementType::VBOX, scoreMeasure);
scoreMeasure = score->first();
}

Expand Down
2 changes: 1 addition & 1 deletion src/engraving/dom/joinMeasure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void MasterScore::joinMeasure(const Fraction& tick1, const Fraction& tick2)
InsertMeasureOptions options;
options.createEmptyMeasures = true;
options.moveSignaturesClef = false;
insertMeasure(ElementType::MEASURE, next, options);
insertMeasure(next, options);

for (Score* s : scoreList()) {
Measure* sM1 = s->tick2measure(startTick);
Expand Down
292 changes: 292 additions & 0 deletions src/engraving/dom/masterscore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@
#include "engravingproject.h"

#include "audio.h"
#include "barline.h"
#include "excerpt.h"
#include "factory.h"
#include "linkedobjects.h"
#include "repeatlist.h"
#include "rest.h"
#include "sig.h"
#include "tempo.h"
#include "timesig.h"
#include "undo.h"

#include "log.h"
Expand Down Expand Up @@ -464,3 +469,290 @@ void MasterScore::rebuildAndUpdateExpressive(Synthesizer* synth)
// Rebuild midi mappings again to be safe
rebuildMidiMapping();
}

//---------------------------------------------------------
// insertMeasure
// Create a new MeasureBase of type type and insert
// before measure.
// If measure is zero, append new MeasureBase.
//---------------------------------------------------------

MeasureBase* MasterScore::insertMeasure(MeasureBase* beforeMeasure, const InsertMeasureOptions& options)
{
Fraction tick;
if (beforeMeasure) {
if (beforeMeasure->isMeasure()) {
if (toMeasure(beforeMeasure)->isMMRest()) {
beforeMeasure = toMeasure(beforeMeasure)->prev();
beforeMeasure = beforeMeasure ? beforeMeasure->next() : firstMeasure();
deselectAll();
}
for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
if (toMeasure(beforeMeasure)->isMeasureRepeatGroupWithPrevM(staffIdx)) {
MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT);
return nullptr;
}
}
}
tick = beforeMeasure->tick();
} else {
tick = last() ? last()->endTick() : Fraction(0, 1);
}

const Fraction currentTimeSig = sigmap()->timesig(tick.ticks()).nominal(); // use nominal time signature of current measure
Measure* masterMeasure = nullptr;
Fraction ticks = { 0, 1 };

MeasureBase* result = nullptr;
const bool isBeginning = tick.isZero();

for (Score* score : scoreList()) {
MeasureBase* actualBeforeMeasure = nullptr;

if (beforeMeasure) {
if (beforeMeasure->score() == score) {
actualBeforeMeasure = beforeMeasure;
} else if (!beforeMeasure->isMeasure() && beforeMeasure->links()) {
for (EngravingObject* m : *beforeMeasure->links()) {
if (m && m->isMeasureBase() && m->score() == score) {
actualBeforeMeasure = toMeasureBase(m);
break;
}
}
}
// if beforeMeasure is measure; or if din't find linked frame, use measure
if (!actualBeforeMeasure) {
actualBeforeMeasure = score->tick2measure(tick);
}

if (!actualBeforeMeasure) {
LOGD("measure not found");
}
}

MeasureBase* newMeasureBase = toMeasureBase(Factory::createMeasure(score->dummy()->system()));
newMeasureBase->setTick(tick);

if (score == this) {
result = newMeasureBase;
}

if (actualBeforeMeasure) {
actualBeforeMeasure = actualBeforeMeasure->top(); // don't try to insert in front of nested frame
}
newMeasureBase->setNext(actualBeforeMeasure);
newMeasureBase->setPrev(actualBeforeMeasure ? actualBeforeMeasure->prev() : score->last());
if (newMeasureBase->isMeasure()) {
Measure* m = toMeasure(newMeasureBase);
m->setTimesig(currentTimeSig);
m->setTicks(currentTimeSig);
}
undo(new InsertMeasures(newMeasureBase, newMeasureBase));

Measure* newMeasure = toMeasure(newMeasureBase); // new measure
ticks = newMeasure->ticks();
Measure* measureInsert = nullptr; // insert before
if (actualBeforeMeasure) {
if (actualBeforeMeasure->isMeasure()) {
measureInsert = toMeasure(actualBeforeMeasure);
} else {
measureInsert = score->tick2measure(actualBeforeMeasure->tick());
}
}

if (score->isMaster()) {
masterMeasure = newMeasure;
}

std::vector<TimeSig*> timeSigList;
std::vector<KeySig*> keySigList;
std::vector<Clef*> clefList;
std::vector<Clef*> previousClefList;
std::list<Clef*> specialCaseClefs;
std::vector<BarLine*> previousBarLinesList;

Measure* pm = newMeasure->prevMeasure();

//
// remove clef, barlines, time and key signatures
//
if (measureInsert) {
// if inserting before first measure, always preserve clefs and signatures
// at the begining of the score (move them back)
if (pm && !options.moveSignaturesClef && !isBeginning) {
Segment* ps = pm->findSegment(SegmentType::Clef, tick);
if (ps && ps->enabled()) {
for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
EngravingItem* pc = ps->element(staffIdx * VOICES);
if (pc) {
previousClefList.push_back(toClef(pc));
undo(new RemoveElement(pc));
if (ps->empty()) {
undoRemoveElement(ps);
}
}
}
}
}

if (options.moveSignaturesClef || isBeginning) {
for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
for (Segment* s = measureInsert->first(); s && s->rtick().isZero(); s = s->next()) {
if (!s->enabled()) {
continue;
}
EngravingItem* e = s->element(staffIdx * VOICES);
// if it's a clef, we only add if it's a header clef
bool moveClef = s->isHeaderClefType() && e && e->isClef() && !toClef(e)->forInstrumentChange();
// otherwise, we only add if e exists and is generated
bool moveOther = e && !e->isClef() && (!e->generated() || tick.isZero());
bool specialCase = false;
if (e && e->isClef() && !moveClef && isBeginning
&& toClef(e)->clefToBarlinePosition() != ClefToBarlinePosition::AFTER) {
// special case:
// there is a non-header clef at global tick 0, and we are inserting at the beginning of the score.
// this clef will be moved with the measure it accompanies, but it will be moved before the barline.
specialCase = true;
moveClef = true;
}
if (!moveClef && !moveOther) {
continue; // this item will remain with the old measure
}
// otherwise, this item is moved back to the new measure
EngravingItem* ee = 0;
if (e->isKeySig()) {
KeySig* ks = toKeySig(e);
if (ks->forInstrumentChange()) {
continue;
}
keySigList.push_back(ks);
// if instrument change on that place, set correct key signature for instrument change
bool ic = s->next(SegmentType::ChordRest)->findAnnotation(ElementType::INSTRUMENT_CHANGE,
e->part()->startTrack(),
e->part()->endTrack() - 1);
if (ic) {
KeySigEvent ke = ks->keySigEvent();
ke.setForInstrumentChange(true);
undoChangeKeySig(ks->staff(), e->tick(), ke);
} else {
ee = e;
}
} else if (e->isTimeSig()) {
TimeSig* ts = toTimeSig(e);
timeSigList.push_back(ts);
ee = e;
}
if (specialCase) {
specialCaseClefs.push_back(toClef(e));
ee = e;
} else if (tick.isZero() && e->isClef()) {
Clef* clef = toClef(e);
clefList.push_back(clef);
ee = e;
}
if (ee) {
undo(new RemoveElement(ee));
if (s->empty()) {
undoRemoveElement(s);
}
}
}
}

if (masterMeasure && measureInsert->repeatStart()) {
masterMeasure->undoChangeProperty(Pid::REPEAT_START, true);
measureInsert->undoChangeProperty(Pid::REPEAT_START, false);
}
}
} else if (!measureInsert && tick == Fraction(0, 1)) {
// If inserting measure into an empty score, restore default C key signature
// and 4/4 time signature
score->restoreInitialKeySigAndTimeSig();
}

if (pm && !options.moveSignaturesClef) {
Segment* pbs = pm->findSegment(SegmentType::EndBarLine, tick);
if (pbs && pbs->enabled()) {
for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
EngravingItem* pb = pbs->element(staffIdx * VOICES);
if (pb && !pb->generated()) {
previousBarLinesList.push_back(toBarLine(pb));
undo(new RemoveElement(pb));
if (pbs->empty()) {
pbs->setEnabled(false);
}
}
}
}
if (masterMeasure && pm->repeatEnd()) {
masterMeasure->undoChangeProperty(Pid::REPEAT_END, true);
pm->undoChangeProperty(Pid::REPEAT_END, false);
}
}

//
// move clef, barline, time, key signatures
//
for (TimeSig* ts : timeSigList) {
TimeSig* nts = Factory::copyTimeSig(*ts);
Segment* s = newMeasure->undoGetSegmentR(SegmentType::TimeSig, Fraction(0, 1));
nts->setParent(s);
undoAddElement(nts);
}
for (KeySig* ks : keySigList) {
KeySig* nks = Factory::copyKeySig(*ks);
Segment* s = newMeasure->undoGetSegmentR(SegmentType::KeySig, Fraction(0, 1));
nks->setParent(s);
if (!nks->isAtonal()) {
nks->setKey(nks->concertKey()); // to set correct (transposing) key
}
undoAddElement(nks);
}
for (Clef* clef : clefList) {
Clef* nClef = Factory::copyClef(*clef);
Segment* s = newMeasure->undoGetSegmentR(SegmentType::HeaderClef, Fraction(0, 1));
nClef->setParent(s);
undoAddElement(nClef);
}
for (Clef* clef : previousClefList) {
Clef* nClef = Factory::copyClef(*clef);
Segment* s = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks());
nClef->setParent(s);
undoAddElement(nClef);
}
for (Clef* clef : specialCaseClefs) {
Clef* nClef = Factory::copyClef(*clef);
Segment* s = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks());
nClef->setParent(s);
undoAddElement(nClef);
}
for (BarLine* barLine : previousBarLinesList) {
BarLine* nBarLine = Factory::copyBarLine(*barLine);
Segment* s = newMeasure->undoGetSegmentR(SegmentType::EndBarLine, newMeasure->ticks());
nBarLine->setParent(s);
undoAddElement(nBarLine);
}
}

undoInsertTime(tick, ticks);

if (masterMeasure && !options.createEmptyMeasures) {
//
// fill measure with rest
// undoAddCR adds rest to linked staves as well
for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
size_t track = staffIdx * VOICES;
Rest* rest = Factory::createRest(dummy()->segment(), TDuration(DurationType::V_MEASURE));
Fraction timeStretch(staff(staffIdx)->timeStretch(masterMeasure->tick()));
rest->setTicks(masterMeasure->ticks() * timeStretch);
rest->setTrack(track);
undoAddCR(rest, masterMeasure, tick);
}
}

if (options.needDeselectAll) {
deselectAll();
}

return result;
}
2 changes: 2 additions & 0 deletions src/engraving/dom/masterscore.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ class MasterScore : public Score
void splitMeasure(const Fraction&);
void joinMeasure(const Fraction&, const Fraction&);

MeasureBase* insertMeasure(MeasureBase* beforeMeasure = nullptr, const InsertMeasureOptions& options = InsertMeasureOptions());

IFileInfoProviderPtr fileInfo() const;
void setFileInfoProvider(IFileInfoProviderPtr fileInfoProvider);

Expand Down
5 changes: 3 additions & 2 deletions src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ class Score : public EngravingObject
NoteVal noteValForPosition(Position pos, AccidentalType at, bool& error);

Slur* addSlur(ChordRest* firstChordRest, ChordRest* secondChordRest, const Slur* slurTemplate);
TextBase* addText(TextStyleType type, EngravingItem* destinationElement = nullptr, bool addToAllScores = true);
TextBase* addText(TextStyleType type, EngravingItem* destinationElement = nullptr);

void deleteItem(EngravingItem*);
void deleteMeasures(MeasureBase* firstMeasure, MeasureBase* lastMeasure, bool preserveTies = false);
Expand Down Expand Up @@ -826,11 +826,12 @@ class Score : public EngravingObject
bool createEmptyMeasures = false;
bool moveSignaturesClef = true;
bool needDeselectAll = true;
bool addToAllScores = true;
};

MeasureBase* insertMeasure(ElementType type, MeasureBase* beforeMeasure = nullptr,
const InsertMeasureOptions& options = InsertMeasureOptions());
MeasureBase* insertBox(ElementType type, MeasureBase* beforeMeasure = nullptr,
const InsertMeasureOptions& options = InsertMeasureOptions());

Audio* audio() const { return m_audio; }
void setAudio(Audio* a) { m_audio = a; }
Expand Down
4 changes: 2 additions & 2 deletions src/engraving/dom/splitMeasure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ void MasterScore::splitMeasure(const Fraction& tick)
options.createEmptyMeasures = true;
options.moveSignaturesClef = false;

insertMeasure(ElementType::MEASURE, nm, options);
insertMeasure(nm, options);
Measure* m2 = toMeasure(nm ? nm->prev() : lastMeasure());
insertMeasure(ElementType::MEASURE, m2, options);
insertMeasure(m2, options);
Measure* m1 = toMeasure(m2->prev());

for (Score* s : scoreList()) {
Expand Down
Loading

0 comments on commit 20d0778

Please sign in to comment.