Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSoC 2020: measure repeats #6365

Merged
merged 6 commits into from
Nov 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libmscore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ add_library (
jump.h key.h keylist.h keysig.h lasso.h layout.h layoutbreak.h ledgerline.h letring.h line.h location.h
lyrics.h marker.h mcursor.h measure.h measurebase.h mmrest.h mscore.h mscoreview.h musescoreCore.h navigate.h note.h notedot.h
noteevent.h noteline.h ossia.h ottava.h page.h palmmute.h part.h pedal.h pitch.h pitchspelling.h pitchvalue.h
pos.h property.h range.h read206.h realizedharmony.h rehearsalmark.h repeat.h repeatlist.h rest.h revisions.h score.h scoreElement.h segment.h
pos.h property.h range.h read206.h realizedharmony.h rehearsalmark.h measurerepeat.h repeatlist.h rest.h revisions.h score.h scoreElement.h segment.h
segmentlist.h select.h sequencer.h shadownote.h shape.h sig.h slur.h slurtie.h spacer.h spanner.h spannermap.h spatium.h
staff.h stafflines.h staffstate.h stafftext.h stafftextbase.h stafftype.h stafftypechange.h stafftypelist.h stem.h
stemslash.h stringdata.h style.h sym.h symbol.h synthesizerstate.h system.h systemdivider.h systemtext.h tempo.h
Expand All @@ -71,7 +71,7 @@ add_library (
layoutbreak.cpp layout.cpp line.cpp lyrics.cpp measurebase.cpp
measure.cpp mmrest.cpp navigate.cpp note.cpp noteevent.cpp ottava.cpp
page.cpp part.cpp pedal.cpp letring.cpp vibrato.cpp palmmute.cpp pitch.cpp pitchspelling.cpp
rendermidi.cpp repeat.cpp repeatlist.cpp rest.cpp
rendermidi.cpp measurerepeat.cpp repeatlist.cpp rest.cpp
score.cpp scoretree.cpp segment.cpp select.cpp shadownote.cpp slur.cpp tie.cpp slurtie.cpp
spacer.cpp spanner.cpp staff.cpp staffstate.cpp
stafftextbase.cpp stafftext.cpp systemtext.cpp stafftype.cpp stem.cpp style.cpp symbol.cpp
Expand Down
18 changes: 18 additions & 0 deletions libmscore/barline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ static void undoChangeBarLineType(BarLine* bl, BarLineType barType, bool allStav
break;
case BarLineType::START_REPEAT: {
Measure* m2 = m->isMMRest() ? m->mmRestFirst() : m;
for (int staffIdx = 0; staffIdx < m2->score()->nstaves(); ++staffIdx) {
if (m2->isMeasureRepeatGroupWithPrevM(staffIdx)) {
MScore::setError(CANNOT_SPLIT_MEASURE_REPEAT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General comment: there are a ton of changes for MuseScore 4 that I have no insight into, so I'm just going to generally assume when I see something like this setError that I've never heard of before, that it's probably fine.

return;
}
}
for (Score* lscore : m2->score()->scoreList()) {
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure) {
Expand All @@ -166,6 +172,12 @@ static void undoChangeBarLineType(BarLine* bl, BarLineType barType, bool allStav
break;
case BarLineType::END_REPEAT: {
Measure* m2 = m->isMMRest() ? m->mmRestLast() : m;
for (int staffIdx = 0; staffIdx < m2->score()->nstaves(); ++staffIdx) {
if (m2->isMeasureRepeatGroupWithNextM(staffIdx)) {
MScore::setError(CANNOT_SPLIT_MEASURE_REPEAT);
return;
}
}
for (Score* lscore : m2->score()->scoreList()) {
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure) {
Expand All @@ -176,6 +188,12 @@ static void undoChangeBarLineType(BarLine* bl, BarLineType barType, bool allStav
break;
case BarLineType::END_START_REPEAT: {
Measure* m2 = m->isMMRest() ? m->mmRestLast() : m;
for (int staffIdx = 0; staffIdx < m2->score()->nstaves(); ++staffIdx) {
if (m2->isMeasureRepeatGroupWithNextM(staffIdx)) {
MScore::setError(CANNOT_SPLIT_MEASURE_REPEAT);
return;
}
}
for (Score* lscore : m2->score()->scoreList()) {
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure) {
Expand Down
2 changes: 1 addition & 1 deletion libmscore/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "text.h"
#include "score.h"
#include "barline.h"
#include "repeat.h"
#include "measurerepeat.h"
#include "symbol.h"
#include "system.h"
#include "image.h"
Expand Down
183 changes: 164 additions & 19 deletions libmscore/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
#include "tempo.h"
#include "undo.h"
#include "timesig.h"
#include "repeat.h"
#include "measurerepeat.h"
#include "tempotext.h"
#include "noteevent.h"
#include "breath.h"
Expand Down Expand Up @@ -1299,7 +1299,7 @@ void Score::changeCRlen(ChordRest* cr, const TDuration& d)

void Score::changeCRlen(ChordRest* cr, const Fraction& dstF, bool fillWithRest)
{
if (cr->isRepeatMeasure()) {
if (cr->isMeasureRepeat()) {
// it is not clear what should this
// operation mean for measure repeats.
return;
Expand Down Expand Up @@ -2602,9 +2602,9 @@ Element* Score::selectMove(const QString& cmd)

ChordRest* el = nullptr;
if (cmd == "select-next-chord") {
el = nextChordRest(cr, true);
el = nextChordRest(cr, true, false);
} else if (cmd == "select-prev-chord") {
el = prevChordRest(cr, true);
el = prevChordRest(cr, true, false);
} else if (cmd == "select-next-measure") {
el = nextMeasure(cr, true, true);
} else if (cmd == "select-prev-measure") {
Expand Down Expand Up @@ -2847,6 +2847,126 @@ void Score::cmdAddGrace(NoteType graceType, int duration)
}
}

//---------------------------------------------------------
// cmdAddMeasureRepeat
//---------------------------------------------------------

void Score::cmdAddMeasureRepeat(Measure* firstMeasure, int numMeasures, int staffIdx)
{
//
// make measures into group
//
if (!makeMeasureRepeatGroup(firstMeasure, numMeasures, staffIdx)) {
return;
}

//
// add MeasureRepeat element
//
int measureWithElementNo;
if (numMeasures % 2) {
// odd number, element anchored to center measure of group
measureWithElementNo = numMeasures / 2 + 1;
} else {
// even number, element anchored to last measure in first half of group
measureWithElementNo = numMeasures / 2;
}
Measure* measureWithElement = firstMeasure;
for (int i = 1; i < measureWithElementNo; ++i) {
measureWithElement = measureWithElement->nextMeasure();
}
// MeasureRepeat element will be positioned appropriately (in center of measure / on following barline)
// when stretchMeasure() is called on measureWithElement
MeasureRepeat* mr = addMeasureRepeat(measureWithElement->tick(), staff2track(staffIdx), numMeasures);
select(mr, SelectType::SINGLE, 0);
}

//---------------------------------------------------------
// makeMeasureRepeatGroup
/// clear measures, apply noBreak, set measureRepeatCount
/// returns false if these measures won't work or user aborted
//---------------------------------------------------------

bool Score::makeMeasureRepeatGroup(Measure* firstMeasure, int numMeasures, int staffIdx)
{
//
// check that sufficient measures exist, with equal durations
//
std::vector<Measure*> measures;
Measure* measure = firstMeasure;
for (int i = 1; i <= numMeasures; ++i) {
if (!measure || measure->ticks() != firstMeasure->ticks()) {
MScore::setError(INSUFFICIENT_MEASURES);
return false;
}
measures.push_back(measure);
measure = measure->nextMeasure();
}

//
// warn user if things will have to be deleted to make room for measure repeat
//
bool empty = true;
for (auto m : measures) {
if (m != measures.back()) {
if (m->endBarLineType() != BarLineType::NORMAL) {
empty = false;
break;
}
}
for (auto seg = m->first(); seg && empty; seg = seg->next()) {
if (seg->segmentType() & SegmentType::ChordRest) {
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* e = seg->element(track);
if (e && !e->generated() && !e->isRest()) {
empty = false;
break;
}
}
}
}
}

if (!empty) {
auto b = QMessageBox::warning(0, QObject::tr("Current contents of measures will be replaced"),
// QMessageBox titles aren't being shown, so include in message
QObject::tr("Current contents of measures will be replaced.")
+ QObject::tr("\nContinue with inserting measure repeat?"),
QMessageBox::Cancel | QMessageBox::Ok,
QMessageBox::Ok);
if (b == QMessageBox::Cancel) {
return false;
}
}

//
// group measures and clear current contents
//

deselectAll();
int i = 1;
for (auto m : measures) {
select(m, SelectType::RANGE, staffIdx);
if (m->isMeasureRepeatGroup(staffIdx)) {
deleteItem(m->measureRepeatElement(staffIdx)); // reset measures related to an earlier MeasureRepeat
}
undoChangeMeasureRepeatCount(m, i++, staffIdx);
if (m != measures.front()) {
m->undoChangeProperty(Pid::REPEAT_START, false);
}
if (m != measures.back()) {
m->undoSetNoBreak(true);
Segment* seg = m->findSegmentR(SegmentType::EndBarLine, m->ticks());
BarLine* endBarLine = toBarLine(seg->element(staff2track(staffIdx)));
deleteItem(endBarLine); // also takes care of Pid::REPEAT_END
}
}
cmdDeleteSelection();
return true;
}

//---------------------------------------------------------
// cmdExplode
/// explodes contents of top selected staff into subsequent staves
Expand Down Expand Up @@ -3847,6 +3967,7 @@ void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
{
// find measure(s)
QList<MeasureBase*> mbl;
bool allNoBreaks = true; // NOBREAK is not removed unless every measure in selection already has one
if (selection().isRange()) {
Measure* startMeasure = nullptr;
Measure* endMeasure = nullptr;
Expand All @@ -3856,23 +3977,33 @@ void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
if (!startMeasure || !endMeasure) {
return;
}
#if 1
// toggle break on the last measure of the range
mbl.append(endMeasure);
// if more than one measure selected,
// also toggle break *before* the range (to try to fit selection on a single line)
if (startMeasure != endMeasure && startMeasure->prev()) {
mbl.append(startMeasure->prev());
}
#else
// toggle breaks throughout the selection
for (Measure* m = startMeasure; m; m = m->nextMeasure()) {
mbl.append(m);
if (m == endMeasure) {
break;
if (type == LayoutBreak::Type::NOBREAK) {
// add throughout the selection
// or remove if already on every measure
if (startMeasure == endMeasure) {
mbl.append(startMeasure);
allNoBreaks = startMeasure->noBreak();
} else {
for (Measure* m = startMeasure; m; m = m->nextMeasureMM()) {
mbl.append(m);
if (m == endMeasure) {
mbl.pop_back();
break;
}
if (!toMeasureBase(m)->noBreak()) {
allNoBreaks = false;
}
}
}
} else {
// toggle break on the last measure of the range
mbl.append(endMeasure);
// if more than one measure selected,
// also toggle break *before* the range (to try to fit selection on a single line)
if (startMeasure != endMeasure && startMeasure->prev()) {
mbl.append(startMeasure->prev());
}
}
#endif
} else {
MeasureBase* mb = nullptr;
for (Element* el : selection().elements()) {
Expand All @@ -3896,6 +4027,7 @@ void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
if (measure) {
mb = measure->isMMRest() ? measure->mmRestLast() : measure;
}
allNoBreaks = mb->noBreak();
}
}
}
Expand Down Expand Up @@ -3928,6 +4060,19 @@ void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
val = !mb->sectionBreak();
mb->undoSetBreak(val, type);
break;
case LayoutBreak::Type::NOBREAK:
mb->undoSetBreak(!allNoBreaks, type);
// remove other breaks if appropriate
if (!mb->noBreak()) {
if (mb->pageBreak()) {
mb->undoSetBreak(false, LayoutBreak::Type::PAGE);
} else if (mb->lineBreak()) {
mb->undoSetBreak(false, LayoutBreak::Type::LINE);
} else if (mb->sectionBreak()) {
mb->undoSetBreak(false, LayoutBreak::Type::SECTION);
}
}
break;
default:
break;
}
Expand Down
Loading