Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
10 changes: 7 additions & 3 deletions src/engraving/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
muse_create_module(engraving)

# TODO: convert to target-based variant of qt_add_resources
# (Not easy because of heavy use of aliases, which is much more cumbersome
# (Not easy because of heavy use of aliases, which is much more cumbersome
# in CMake than in .qrc files)
muse_module_add_qrc(engraving
muse_module_add_qrc(engraving
engraving.qrc
data/fonts/fonts_Smufl.qrc
)
Expand Down Expand Up @@ -337,7 +337,7 @@ else()
)
endif()

set_source_files_properties(
set_source_files_properties(
# For these files, Unity Build does not work
dom/excerpt.cpp
#api/vi/excerpt.cpp
Expand Down Expand Up @@ -422,3 +422,7 @@ endif()
if (QT_SUPPORT)
add_subdirectory(qml/MuseScore/Engraving)
endif()

if (MSVC_IDE)
target_sources(engraving PRIVATE engraving.natvis)
endif()
9 changes: 7 additions & 2 deletions src/engraving/dom/anchors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <climits>

#include "anchors.h"
#include "dom/timesig.h"
#include "dom/utils.h"
#include "factory.h"
#include "figuredbass.h"
Expand Down Expand Up @@ -86,8 +87,12 @@ void EditTimeTickAnchors::updateAnchors(Measure* measure, staff_idx_t staffIdx,
Fraction startTick = Fraction(0, 1);
Fraction endTick = measure->ticks();

Fraction timeSig = measure->timesig();
Fraction halfDivision = Fraction(1, 2 * timeSig.denominator());
TimeSig* timeSig = measure->score()->staff(staffIdx)->timeSig(measure->tick());
Fraction timeSigFrac = timeSig ? timeSig->sig() : measure->timesig();
Fraction halfDivision = Fraction(1, 2 * timeSigFrac.denominator());
if (timeSig) {
halfDivision /= timeSig->stretch();
}

std::set<Fraction> anchorTicks { additionalAnchorRelTicks };
for (Fraction tick = startTick; tick <= endTick; tick += halfDivision) {
Expand Down
14 changes: 7 additions & 7 deletions src/engraving/dom/check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,27 +260,27 @@ bool Score::checkKeys()
// fillGap
//---------------------------------------------------------

void Measure::fillGap(const Fraction& pos, const Fraction& len, track_idx_t track, const Fraction& stretch, bool useGapRests)
void Measure::fillGap(const Fraction& rtickStart, const Fraction& len, track_idx_t track, const Fraction& stretch, bool useGapRests)
{
LOGN("measure %6d pos %d, len %d/%d, stretch %d/%d track %zu",
tick().ticks(),
pos.ticks(),
rtickStart.ticks(),
len.numerator(), len.denominator(),
stretch.numerator(), stretch.denominator(),
track);

// break the gap into shorter durations if necessary
std::vector<TDuration> durationList = toRhythmicDurationList(len, true, pos, timesig(), this, 0);
std::vector<TDuration> durationList = toRhythmicDurationList(len, true, rtickStart, timesig(), this, 0, stretch);

Fraction curTick = pos;
Fraction curTick = tick() + actualTicks(rtickStart, nullptr, stretch);
for (TDuration d : durationList) {
Rest* rest = Factory::createRest(score()->dummy()->segment());
rest->setTicks(d.isMeasure() ? ticks() : d.fraction());
rest->setTicks(d.isMeasure() ? ticks() * stretch : d.fraction());
rest->setDurationType(d);
rest->setTrack(track);
rest->setGap(useGapRests);
score()->undoAddCR(rest, this, curTick + tick());
curTick += d.fraction() / stretch;
score()->undoAddCR(rest, this, curTick);
curTick += rest->actualTicks();
}
}

Expand Down
15 changes: 12 additions & 3 deletions src/engraving/dom/durationtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,8 @@ TDuration& TDuration::operator+=(const TDuration& t)

//---------------------------------------------------------
// toDurationList
// - l is in local time
// - returned durations are in local time
//---------------------------------------------------------

std::vector<TDuration> toDurationList(Fraction l, bool useDots, int maxDots, bool printRestRemains)
Expand All @@ -502,17 +504,24 @@ std::vector<TDuration> toDurationList(Fraction l, bool useDots, int maxDots, boo

//---------------------------------------------------------
// toRhythmicDurationList
// - l and rtickStart are in local (stretched) time
// - returned durations are in local time
//---------------------------------------------------------

std::vector<TDuration> toRhythmicDurationList(const Fraction& l, bool isRest, Fraction rtickStart,
const TimeSigFrac& nominal, Measure* msr, int maxDots)
const TimeSigFrac& nominal, Measure* msr, int maxDots,
const Fraction& timeStretch)
{
IF_ASSERT_FAILED(l > Fraction(0, 1)) {
return {};
}

std::vector<TDuration> dList;
dList.reserve(8);

if (msr->isAnacrusis()) {
rtickStart += msr->anacrusisOffset();
} else if (isRest && l == msr->ticks()) {
rtickStart += msr->anacrusisOffset() * timeStretch;
} else if (isRest && l == msr->ticks() * timeStretch) {
TDuration d = TDuration(DurationType::V_MEASURE);
dList.push_back(d);
return dList;
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/dom/durationtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class TDuration

std::vector<TDuration> toDurationList(Fraction l, bool useDots, int maxDots = 4, bool printRestRemains = true);
std::vector<TDuration> toRhythmicDurationList(const Fraction& l, bool isRest, Fraction rtickStart, const TimeSigFrac& nominal, Measure* msr,
int maxDots);
int maxDots, const Fraction& timeStretch = Fraction(1, 1));

bool forceRhythmicSplit(bool isRest, BeatType startBeat, BeatType endBeat, int beatsCrossed, BeatType strongestBeatCrossed,
const TimeSigFrac& nominal);
Expand Down
8 changes: 6 additions & 2 deletions src/engraving/dom/measure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1892,8 +1892,12 @@ void Measure::adjustToLen(Fraction nf, bool appendRestsIfNecessary)
/*rtickStart=*/ Fraction(0, 1),
/*nominal=*/ score()->sigmap()->timesig(tick().ticks()).nominal(),
/*measure=*/ this,
/*maxDots=*/ 0);

/*maxDots=*/ 0,
stretch);
if (durList.empty()) {
LOGD("Could not make durations for: %d/%d", (nf * stretch).numerator(), (nf * stretch).denominator());
continue;
}
// set the existing rest to the first value of the duration list
TDuration firstDur = durList[0];
rest->undoChangeProperty(Pid::DURATION, firstDur.isMeasure() ? ticks() : firstDur.fraction());
Expand Down
1 change: 1 addition & 0 deletions src/engraving/dom/mscore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ std::string MScore::errorToString(MsError err)
case MsError::CANNOT_JOIN_MEASURE_STAFFTYPE_CHANGE: return "CANNOT_JOIN_MEASURE_STAFFTYPE_CHANGE";
case MsError::CANNOT_REPEAT_SELECTION: return "CANNOT_REPEAT_SELECTION";
case MsError::TRANSPOSE_NO_FRET_DIAGRAM: return "TRANSPOSE_NO_FRET_DIAGRAM";
case MsError::CANNOT_EXPLODE_IMPLODE_LOCAL_TIMESIG: return "CANNOT_EXPLODE_IMPLODE_LOCAL_TIMESIG";
}

return {};
Expand Down
1 change: 1 addition & 0 deletions src/engraving/dom/mscore.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ enum class MsError : unsigned char {
CANNOT_JOIN_MEASURE_STAFFTYPE_CHANGE,
CANNOT_REPEAT_SELECTION,
TRANSPOSE_NO_FRET_DIAGRAM,
CANNOT_EXPLODE_IMPLODE_LOCAL_TIMESIG,
};

/// \cond PLUGIN_API \private \endcond
Expand Down
55 changes: 35 additions & 20 deletions src/engraving/dom/paste.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
Transpose::transposeChord(chord, tick);
if (chord->tremoloTwoChord()) {
twoNoteTremoloFactor = 2;
} else if (cr->durationTypeTicks() == (cr->actualTicksAt(tick) * 2)) {
} else if (cr->durationTypeTicks() == (cr->ticks() * 2)) {
// this could be the 2nd note of a two-note tremolo
// check previous CR on same track, if it has a two-note tremolo, then set twoNoteTremoloFactor to 2
Segment* seg = measure->undoGetSegment(SegmentType::ChordRest, tick);
Expand All @@ -122,7 +122,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
// otherwise, we need to convert to duration rest(s)
// and potentially split the rest up (eg, 5/4 => whole + quarter)
bool convertMeasureRest = cr->isRest() && cr->durationType().type() == DurationType::V_MEASURE
&& (tick != measure->tick() || cr->ticks() != measure->ticks());
&& (tick != measure->tick() || cr->actualTicksAt(tick) != measure->ticks());

Fraction measureEnd = measure->endTick();
bool isGrace = cr->isChord() && toChord(cr)->noteType() != NoteType::NORMAL;
Expand All @@ -145,35 +145,39 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
if (cr->isMeasureRepeat()) {
partialCopy = toMeasureRepeat(cr)->actualTicks() != measure->ticks();
} else if (!isGrace && !cr->tuplet()) {
partialCopy = cr->durationTypeTicks() != (cr->actualTicksAt(tick) * twoNoteTremoloFactor);
partialCopy = cr->durationTypeTicks() != (cr->ticks() * twoNoteTremoloFactor);
}

// if note is too long to fit in measure, split it up with a tie across the barline
// exclude tuplets from consideration
// we have already disallowed a tuplet from crossing the barline, so there is no problem here
// but due to rounding, it might appear from actualTicks() that the last note is too long by a couple of ticks

Staff* stf = cr->staff();
if (!isGrace && !cr->tuplet() && (tick + cr->actualTicksAt(tick) > measureEnd || partialCopy || convertMeasureRest)) {
if (cr->isChord()) {
// split Chord
Chord* c = toChord(cr);
Fraction rest = c->actualTicksAt(tick);
Fraction rest = c->ticks();
bool firstpart = true;
while (rest.isNotZero()) {
measure = tick2measure(tick);
Chord* c2 = firstpart ? c : toChord(c->clone());
if (!firstpart) {
c2->removeMarkings(true);
}
Fraction mlen = measure->endTick() - tick;
Fraction timeStretch = stf->timeStretch(tick);
Fraction mlen = (measure->endTick() - tick) * timeStretch;
Fraction len = mlen > rest ? rest : mlen;
std::vector<TDuration> dl = toRhythmicDurationList(len, false, tick - measure->tick(), sigmap()->timesig(
tick).nominal(), measure, MAX_DOTS);
std::vector<TDuration> dl = toRhythmicDurationList(len, false, (tick - measure->tick()) * timeStretch,
sigmap()->timesig(tick).nominal(), measure, MAX_DOTS, timeStretch);
if (dl.empty()) {
LOGD("Could not make durations for: %d/%d", len.numerator(), len.denominator());
return;
}
TDuration d = dl[0];
Fraction c2Tick(tick + c->tick());
c2->setDurationType(d);
c2->setTicks(d.fraction());
rest -= c2->actualTicksAt(c2Tick);
undoAddCR(c2, measure, tick);

std::vector<Note*> nl1 = c->notes();
Expand All @@ -196,9 +200,10 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
nl2[i]->setTieBack(tie);
}
}
c = c2;
rest -= c2->ticks();
tick += c2->actualTicksAt(tick);
firstpart = false;
tick += c->actualTicksAt(c2Tick);
c = c2;
}
} else if (cr->isRest()) {
// split Rest
Expand All @@ -209,36 +214,46 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
while (!rest.isZero()) {
Rest* r2 = firstpart ? r : toRest(r->clone());
measure = tick2measure(tick);
Fraction mlen = measure->endTick() - tick;
Fraction timeStretch = stf->timeStretch(tick);
Fraction mlen = (measure->endTick() - tick) * timeStretch;
Fraction len = rest > mlen ? mlen : rest;
std::vector<TDuration> dl = toRhythmicDurationList(len, true, tick - measure->tick(), sigmap()->timesig(
tick).nominal(), measure, MAX_DOTS);
std::vector<TDuration> dl = toRhythmicDurationList(len, true, (tick - measure->tick()) * timeStretch,
sigmap()->timesig(tick).nominal(), measure, MAX_DOTS, timeStretch);
if (dl.empty()) {
LOGD("Could not make durations for: %d/%d", len.numerator(), len.denominator());
return;
}
TDuration d = dl[0];
r2->setDurationType(d);
r2->setTicks(d.isMeasure() ? measure->ticks() : d.fraction());
r2->setTicks(d.isMeasure() ? measure->stretchedLen(stf) : d.fraction());
undoAddCR(r2, measure, tick);
rest -= r2->ticks();
tick += r2->actualTicksAt(tick);
firstpart = false;
}
} else if (cr->isMeasureRepeat()) {
MeasureRepeat* mr = toMeasureRepeat(cr);
std::vector<TDuration> list = toDurationList(mr->actualTicks(), true);
std::vector<TDuration> list = toDurationList(mr->ticks(), true);
for (auto dur : list) {
Rest* r = Factory::createRest(this->dummy()->segment(), dur);
r->setTrack(cr->track());
Fraction rest = r->ticks();
while (!rest.isZero()) {
Rest* r2 = toRest(r->clone());
measure = tick2measure(tick);
Fraction mlen = measure->endTick() - tick;
Fraction timeStretch = stf->timeStretch(tick);
Fraction mlen = (measure->endTick() - tick) * timeStretch;
Fraction len = rest > mlen ? mlen : rest;
std::vector<TDuration> dl = toDurationList(len, false);
if (dl.empty()) {
LOGD("Could not make durations for: %d/%d", len.numerator(), len.denominator());
return;
}
TDuration d = dl[0];
r2->setTicks(d.fraction());
r2->setDurationType(d);
undoAddCR(r2, measure, tick);
rest -= d.fraction();
rest -= r2->ticks();
tick += r2->actualTicksAt(tick);
}
delete r;
Expand Down Expand Up @@ -574,8 +589,8 @@ void Score::cmdPasteStaffList(muse::ByteArray& data, Fraction scale)
}

XmlReader xmlReader(data);
IF_ASSERT_FAILED(pasteStaff(xmlReader, cr->segment(), cr->staffIdx(), scale)) {
LOGE() << "Failed to paste staff";
if (!pasteStaff(xmlReader, cr->segment(), cr->staffIdx(), scale)) {
return;
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ class Score : public EngravingObject, public muse::Injectable
void createCRSequence(const Fraction& f, ChordRest* cr, const Fraction& tick);

Fraction makeGap(Segment*, track_idx_t track, const Fraction&, Tuplet*, bool keepChord = false);
bool makeGap1(const Fraction& baseTick, staff_idx_t staffIdx, const Fraction& len, int voiceOffset[VOICES]);
bool makeGap1(const Fraction& baseTick, staff_idx_t staffIdx, const Fraction& len, const Fraction voiceOffset[VOICES]);
bool makeGapVoice(Segment* seg, track_idx_t track, Fraction len, const Fraction& tick);

Rest* addRest(const Fraction& tick, track_idx_t track, TDuration, Tuplet*);
Expand Down Expand Up @@ -1004,8 +1004,8 @@ class Score : public EngravingObject, public muse::Injectable

void cmdInsertClef(Clef* clef, ChordRest* cr);

void cmdExplode();
void cmdImplode();
bool cmdExplode();
bool cmdImplode();
void cmdSlashFill();
void cmdSlashRhythm();
void cmdResequenceRehearsalMarks();
Expand Down
5 changes: 3 additions & 2 deletions src/engraving/dom/segment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,9 +1093,10 @@ void Segment::setXPosInSystemCoords(double x)
mutldata()->setPosX(x - measure()->x());
}

bool Segment::isTupletSubdivision() const
bool Segment::isTupletSubdivisionOnStaff(staff_idx_t staffIdx) const
{
int denom = tick().reduced().denominator();
Fraction timeStretch = score()->staff(staffIdx)->timeStretch(tick());
int denom = (m_tick * timeStretch).reduced().denominator();
bool denomIsPowOfTwo = (denom & (denom - 1)) == 0;
// A non-power-of-two denominator is possible only with tuplets
return !denomIsPowOfTwo;
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/dom/segment.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ class Segment final : public EngravingItem
double xPosInSystemCoords() const;
void setXPosInSystemCoords(double x);

bool isTupletSubdivision() const;
bool isTupletSubdivisionOnStaff(staff_idx_t staffIdx) const;
bool isInsideTupletOnStaff(staff_idx_t staffIdx) const;

private:
Expand Down
Loading
Loading