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

Implement partial slurs #25883

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 3 additions & 4 deletions src/engraving/api/v1/apitypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef MU_ENGRAVING_APIV1_APITYPES_H
#define MU_ENGRAVING_APIV1_APITYPES_H
#pragma once

#include <QObject>

Expand Down Expand Up @@ -227,6 +226,8 @@ enum class ElementType {
TIE_SEGMENT = int(mu::engraving::ElementType::TIE_SEGMENT),
LAISSEZ_VIB_SEGMENT = int(mu::engraving::ElementType::LAISSEZ_VIB_SEGMENT),
LAISSEZ_VIB = int(mu::engraving::ElementType::LAISSEZ_VIB),
PARTIAL_TIE_SEGMENT = int(mu::engraving::ElementType::PARTIAL_TIE_SEGMENT),
PARTIAL_TIE = int(mu::engraving::ElementType::PARTIAL_TIE),
BAR_LINE = int(mu::engraving::ElementType::BAR_LINE),
STAFF_LINES = int(mu::engraving::ElementType::STAFF_LINES),
SYSTEM_DIVIDER = int(mu::engraving::ElementType::SYSTEM_DIVIDER),
Expand Down Expand Up @@ -3599,5 +3600,3 @@ Q_DECLARE_METATYPE(mu::engraving::apiv1::enums::Tid);
Q_DECLARE_METATYPE(mu::engraving::apiv1::enums::Syllabic);
Q_DECLARE_METATYPE(mu::engraving::apiv1::enums::Anchor);
Q_DECLARE_METATYPE(mu::engraving::apiv1::enums::SymId);

#endif // MU_ENGRAVING_APIV1_APITYPES_H
2 changes: 1 addition & 1 deletion src/engraving/compat/midi/compatmidirender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ std::set<size_t> CompatMidiRender::getNotesIndexesToRender(Chord* chord)
}

auto noteShouldBeRendered = [](Note* n) {
while (n->tieBack() && n != n->tieBack()->startNote()) {
while (n->tieBackNonPartial() && n != n->tieBack()->startNote()) {
n = n->tieBack()->startNote();
if (findFirstTrill(n->chord())) {
// The previous tied note probably has events for this note too.
Expand Down
2 changes: 2 additions & 0 deletions src/engraving/dom/barline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ static void undoChangeBarLineType(BarLine* bl, BarLineType barType, bool allStav
// createMMRest will then set for the mmrest directly
Measure* m2 = m->isMMRest() ? m->mmRestLast() : m;

BarLineType prevBarType = bl->barLineType();

switch (barType) {
case BarLineType::END:
case BarLineType::NORMAL:
Expand Down
9 changes: 0 additions & 9 deletions src/engraving/dom/beam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,15 +485,6 @@ void Beam::startEdit(EditData& ed)
initBeamEditData(ed);
}

//---------------------------------------------------------
// endEdit
//---------------------------------------------------------

void Beam::endEdit(EditData& ed)
{
EngravingItem::endEdit(ed);
}

//---------------------------------------------------------
// triggerLayout
//---------------------------------------------------------
Expand Down
5 changes: 1 addition & 4 deletions src/engraving/dom/beam.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef MU_ENGRAVING_BEAM_H
#define MU_ENGRAVING_BEAM_H
#pragma once

#include "beambase.h"
#include "engravingitem.h"
Expand Down Expand Up @@ -64,7 +63,6 @@ class Beam final : public BeamBase

bool isEditable() const override { return true; }
void startEdit(EditData&) override;
void endEdit(EditData&) override;
void editDrag(EditData&) override;

Fraction tick() const override;
Expand Down Expand Up @@ -226,4 +224,3 @@ class Beam final : public BeamBase
std::vector<TremAnchor> m_tremAnchors;
};
} // namespace mu::engraving
#endif
5 changes: 3 additions & 2 deletions src/engraving/dom/chord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1672,7 +1672,7 @@ void Chord::cmdUpdateNotes(AccidentalState* as, staff_idx_t staffIdx)
if (vStaffIdx() == staffIdx) {
std::vector<Note*> lnotes(notes()); // we need a copy!
for (Note* note : lnotes) {
if (note->tieBack() && note->tpc() == note->tieBack()->startNote()->tpc()) {
if (note->tieBackNonPartial() && note->tpc() == note->tieBack()->startNote()->tpc()) {
// same pitch
if (note->accidental() && note->accidental()->role() == AccidentalRole::AUTO) {
// not courtesy
Expand Down Expand Up @@ -2618,7 +2618,7 @@ static bool noteIsBefore(const Note* n1, const Note* n2)
}

if (n1->tieBack()) {
if (n2->tieBack()) {
if (n2->tieBack() && !n2->incomingPartialTie()) {
const Note* sn1 = n1->tieBack()->startNote();
const Note* sn2 = n2->tieBack()->startNote();
if (sn1->chord() == sn2->chord()) {
Expand Down Expand Up @@ -2853,6 +2853,7 @@ EngravingItem* Chord::nextElement()
case ElementType::GLISSANDO_SEGMENT:
case ElementType::NOTELINE_SEGMENT:
case ElementType::LAISSEZ_VIB_SEGMENT:
case ElementType::PARTIAL_TIE_SEGMENT:
case ElementType::TIE_SEGMENT: {
SpannerSegment* s = toSpannerSegment(e);
Spanner* sp = s->spanner();
Expand Down
136 changes: 133 additions & 3 deletions src/engraving/dom/chordrest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "instrchange.h"
#include "keysig.h"
#include "lyrics.h"
#include "marker.h"
#include "measure.h"
#include "navigate.h"
#include "note.h"
Expand All @@ -54,6 +55,7 @@
#include "system.h"
#include "tuplet.h"
#include "utils.h"
#include "volta.h"

#include "log.h"

Expand Down Expand Up @@ -1207,17 +1209,29 @@ void ChordRest::removeMarkings(bool /* keepTremolo */)
// isBefore
//---------------------------------------------------------

bool ChordRest::isBefore(const ChordRest* o) const
bool ChordRest::isBefore(const EngravingItem* o) const
{
if (!o || this == o) {
return false;
}

const ChordRest* otherCr = nullptr;
if (o->isChordRest()) {
otherCr = toChordRest(o);
} else if (o->isNote()) {
otherCr = toNote(o)->chord();
}

if (!otherCr) {
return EngravingItem::isBefore(o);
}

int otick = o->tick().ticks();
int t = tick().ticks();
if (t == otick) { // At least one of the chord is a grace, order the grace notes
bool oGraceAfter = o->isGraceAfter();
bool oGraceAfter = otherCr->isGraceAfter();
bool graceAfter = isGraceAfter();
bool oGrace = o->isGrace();
bool oGrace = otherCr->isGrace();
bool grace = isGrace();
// normal note are initialized at graceIndex 0 and graceIndex is 0 based
size_t oGraceIndex = oGrace ? toChord(o)->graceIndex() + 1 : 0;
Expand Down Expand Up @@ -1291,4 +1305,120 @@ void ChordRest::checkStaffMoveValidity()
m_storedStaffMove = 0;
}
}

bool ChordRest::hasFollowingJumpItem() const
{
const Segment* seg = segment();
const Measure* measure = seg->measure();
const Fraction nextTick = seg->tick() + actualTicks();

if (measure->lastChordRest(track()) != this) {
return false;
}

// Jumps & markers
for (const EngravingItem* e : measure->el()) {
if (!e->isJump() && !e->isMarker()) {
continue;
}

if (e->isJump()) {
return true;
}

const Marker* marker = toMarker(e);

if (muse::contains(Marker::RIGHT_MARKERS, marker->markerType())) {
return true;
}
}

// Voltas
auto spanners = score()->spannerMap().findOverlapping(measure->endTick().ticks(), measure->endTick().ticks());
for (auto& spanner : spanners) {
if (!spanner.value->isVolta() || Fraction::fromTicks(spanner.start) != nextTick) {
continue;
}

return true;
}

// Repeats
if (measure->repeatEnd()) {
return true;
}

for (Segment* nextSeg = seg->next(SegmentType::BarLineType); nextSeg && nextSeg->tick() == nextTick;
nextSeg = nextSeg->next(SegmentType::BarLineType)) {
const EngravingItem* el = nextSeg->element(track());
if (!el || !el->isBarLine()) {
continue;
}
const BarLine* bl = toBarLine(el);

if (bl->barLineType() & (BarLineType::END_REPEAT | BarLineType::END_START_REPEAT)) {
return true;
}
}

return false;
}

bool ChordRest::hasPrecedingJumpItem() const
{
const Segment* seg = segment();
const Measure* measure = seg->measure();

if (measure->firstChordRest(track()) != this) {
return false;
}

if (seg->score()->firstSegment(SegmentType::ChordRest) == seg) {
return true;
}

// Markers
for (const EngravingItem* e : measure->el()) {
if (!e->isMarker()) {
continue;
}

const Marker* marker = toMarker(e);
if (muse::contains(Marker::RIGHT_MARKERS, marker->markerType())) {
continue;
}

return true;
}

// Voltas
auto spanners = score()->spannerMap().findOverlapping(measure->tick().ticks(), measure->tick().ticks());
for (auto& spanner : spanners) {
if (!spanner.value->isVolta() || Fraction::fromTicks(spanner.start) != tick()) {
continue;
}

return true;
}

// Repeat barlines
if (measure->repeatStart()) {
return true;
}

for (Segment* prevSeg = seg->prev(SegmentType::BarLineType); prevSeg && prevSeg->tick() == seg->tick();
prevSeg = prevSeg->prev(SegmentType::BarLineType)) {
EngravingItem* el = prevSeg->element(track());
if (!el || !el->isBarLine()) {
continue;
}

BarLine* bl = toBarLine(el);
if (bl->barLineType() & (BarLineType::START_REPEAT | BarLineType::END_START_REPEAT)) {
return true;
}
}

return false;
}
}
5 changes: 4 additions & 1 deletion src/engraving/dom/chordrest.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class ChordRest : public DurationElement
bool isFullMeasureRest() const { return m_durationType == DurationType::V_MEASURE; }
virtual void removeMarkings(bool keepTremolo = false);

bool isBefore(const ChordRest*) const;
bool isBefore(const EngravingItem*) const override;

void undoAddAnnotation(EngravingItem*);

Expand All @@ -202,6 +202,9 @@ class ChordRest : public DurationElement

bool isBelowCrossBeam(const BeamBase* beamBase) const;

bool hasFollowingJumpItem() const;
bool hasPrecedingJumpItem() const;

struct LayoutData : public DurationElement::LayoutData {
ld_field<bool> up = { "[ChordRest] up", true }; // actual stem direction
};
Expand Down
18 changes: 11 additions & 7 deletions src/engraving/dom/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,16 +330,17 @@ void Score::startCmd(const TranslatableString& actionName)
LOGD("===startCmd()");
}

if (undoStack()->hasActiveCommand()) {
LOGD("Score::startCmd(): cmd already active");
return;
}

MScore::setError(MsError::MS_NO_ERROR);

cmdState().reset();

// Start collecting low-level undo operations for a
// user-visible undo action.
if (undoStack()->hasActiveCommand()) {
LOGD("Score::startCmd(): cmd already active");
return;
}
undoStack()->beginMacro(this, actionName);
}

Expand Down Expand Up @@ -1691,8 +1692,11 @@ void Score::changeCRlen(ChordRest* cr, const Fraction& dstF, bool fillWithRest)
undoRemoveElement(c->tremoloTwoChord());
}
for (Note* n : c->notes()) {
if (n->tieFor()) {
undoRemoveElement(n->tieFor());
if (Tie* tie = n->tieFor()) {
if (tie->tieJumpPoints()) {
tie->undoRemoveTiesFromJumpPoints();
}
undoRemoveElement(tie);
}
for (Spanner* sp : n->spannerFor()) {
if (sp->isGlissando() || sp->isGuitarBend()) {
Expand Down Expand Up @@ -3789,7 +3793,7 @@ void Score::cmdImplode()
// see if we are tying in to this chord
Chord* tied = 0;
for (Note* n : dstChord->notes()) {
if (n->tieBack()) {
if (n->tieBackNonPartial()) {
tied = n->tieBack()->startNote()->chord();
break;
}
Expand Down
2 changes: 2 additions & 0 deletions src/engraving/dom/dom.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ set(DOM_SRC
${CMAKE_CURRENT_LIST_DIR}/ottava.h
${CMAKE_CURRENT_LIST_DIR}/page.cpp
${CMAKE_CURRENT_LIST_DIR}/page.h
${CMAKE_CURRENT_LIST_DIR}/partialtie.cpp
${CMAKE_CURRENT_LIST_DIR}/partialtie.h
${CMAKE_CURRENT_LIST_DIR}/palmmute.cpp
${CMAKE_CURRENT_LIST_DIR}/palmmute.h
${CMAKE_CURRENT_LIST_DIR}/part.cpp
Expand Down
Loading
Loading