Skip to content

Commit

Permalink
New Guitar Bends
Browse files Browse the repository at this point in the history
Introduce GuitarBend class

Replace old Bend element in palette with new GuitarBend

Allow drop of GuitarBend palette element on Note

Basic layout and draw to get something on screen

Implement GuitarBend::computeUp

Implement GuitarBend::computeIsInside

Implement basic endPoint calculations

Create GuitarBendLayout class

Implement vertex point

Implement drag points

Remove vertexPointOff from layoutData

Implement read/write for vertexPointOff

Implement adjustX

Implement Direction selection in property panel

Geometry correction

Draw as a path instead of individual lines

Implement GuitarBendSegment::reset()

Implement deletion of GuitarBend element

Create ActionIcon(s) for Pre-Bend, Grace note Bend, Slight Bend

Basic implementation of Pre-bends and Grace note bends insertion

Move GuitarBend::computeUp and GuitarBend::computeIsInside to layout class

Add Direction property to Reset

Factor in Note::mag in end point calculation

Add isGuitarBendStartCue to Chord copy constructor

Introduce checkBadStaffLineIntersection

Move path into LayoutData

Improve dragging

Rename layoutData to ldata (rebase correction)

Use MiterJoin instead of BevelJoin style for drawing

Introduce GuitarBendType into GuitarBend objecy

Introduce bool helpers for Note and Chord and improve grace note spacing

Explicitely set painter to noBrush to avoid unwanted graphical glitch

Correction to Glissando::guessFinalNote and to preBend insertion

Avoid beam for grace bends and pre bends

Correct end note for grace or pre bends inserted on chords

Correction to horizontal collision checks

Allow insertion of Glissando and GuitarBend betwen two specific notes

Enforce minimum GuitarBend length during horizontal spacing

Prepare for introduction of Slight Bends

Revert change to Note::drop(Glissando)

Add Note::drop(GuitarBend)

Prepare addGuitarBend to also add standardPaletteBend

Implemented Slight Bends

Fix staff-TAB link and introduce layoutTab method

Implement GuitarBend::computeBendAmount

First basic TAB layout

Layout release-bend

lineWidth() correction

Make endnote of downbend ghost

Remove invisible or ghost end note when removing GuitarBend

Layout Slight Bend on TAB

Move setHeadParenthesis of pre-bends to GuitarBendLayout

Reset startNote property after deleting bend

Layout preBends on TAB

Grace notes size for preBends and graceNoteBends in tab

Cross-system bends in TABs

Release bend correction

Introduce GuitarBendHold class

Layout GuitarBendHold

Fix unrelated TAB layout bug

Hold layout correction

Implement GuitarBendHoldSegment::editDrag

Implement read/write for hold lines

Avoid bend-to-bend conflicts

Horizontal spacing exception for grace notes in TAb with bends

Correction to Glissando::guessFinalNote

Add bend end note if a suitable one isn't found

Introduce GuitarBend::findPrecedingBend method

Bend amount should take into account also preceding bends

Better multibends with partial bends and release

Updating grace index is necessary also in TAB not only in standard staff

Correct property progatation (avoid propagating offsets to/from linked tab)

Bounding box correction

Add GuitarBends to Skyline (with necessary layout order corrections)

Introduce dedicated GuitarBendText class

Extract isUserModified() logic for spanners out of TWrite

Implement read/write for GuitarBendText

Introduce "useFull" option

Introduce "Show hold line" property

Layout corrections

Improved layout of hold lines

System layout correction

Improved conflict-checks among bends

SlightBend correction

Improved layout of hold lines

Make some constants into Style

Fix bends jump on edit and partial refactoring

Bend startPoint correction

Code review corrections

Updated icon font and new icons for all bend-related palettes

Hoooked up all style settings to style dialog

Reordered palette elements

Correction (fix unit tests)

Improved string-fret logic for bends

Introduce Note::bendFor and Note::bendBack utilities to save repeated code

Update TAB fretting for ties and bends

Text layout correction

Ensure grace stem and flag not shown in TAB

Fix bug on auto-creating end note for bend

Fix alt+arrow navigation for GuitarBends

Correct shape for Slight Bend and add it to Note::shape
  • Loading branch information
mike-spa committed Oct 24, 2023
1 parent 5dc9152 commit 2fa5483
Show file tree
Hide file tree
Showing 75 changed files with 2,710 additions and 218 deletions.
Binary file modified fonts/mscore/MusescoreIcon.ttf
Binary file not shown.
5 changes: 5 additions & 0 deletions src/engraving/dom/actionicon.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ enum class ActionIconType {

PARENTHESES,
BRACKETS,

STANDARD_BEND,
PRE_BEND,
GRACE_NOTE_BEND,
SLIGHT_BEND,
};

//! Dummy element, used for drag&drop
Expand Down
6 changes: 6 additions & 0 deletions src/engraving/dom/bend.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ class Factory;
// @@ Bend
//---------------------------------------------------------

/**********************************************************
* OBSOLETE CLASS
* Used to represent bends before version 4.2. Now
* replaced by the GuitarBend class.
*********************************************************/

enum class BendType {
BEND = 0,
BEND_RELEASE,
Expand Down
77 changes: 75 additions & 2 deletions src/engraving/dom/chord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "chordline.h"
#include "drumset.h"
#include "factory.h"
#include "guitarbend.h"
#include "hook.h"
#include "key.h"
#include "ledgerline.h"
Expand Down Expand Up @@ -2302,7 +2303,7 @@ void Chord::setSlash(bool flag, bool stemless)
// end into this chord or no.
//---------------------------------------------------------

void Chord::updateEndsGlissando()
void Chord::updateEndsGlissandoOrGuitarBend()
{
m_endsGlissando = false; // assume no glissando ends here
// scan all chord notes for glissandi ending on this chord
Expand Down Expand Up @@ -2357,7 +2358,11 @@ double Chord::intrinsicMag() const
m *= style().styleD(Sid::smallNoteMag);
}
if (m_noteType != NoteType::NORMAL) {
m *= style().styleD(Sid::graceNoteMag);
bool tabGraceSizeException = staffType()->isTabStaff() && isPreBendOrGraceBendStart()
&& !style().styleB(Sid::useCueSizeFretForGraceBends);
if (!tabGraceSizeException) {
m *= style().styleD(Sid::graceNoteMag);
}
}
return m;
}
Expand Down Expand Up @@ -2551,6 +2556,73 @@ void Chord::toGraceAfter()
}
}

bool Chord::isPreBendOrGraceBendStart() const
{
if (!isGrace()) {
return false;
}

for (const Note* note : m_notes) {
GuitarBend* gb = note->bendFor();
if (gb && (gb->type() == GuitarBendType::PRE_BEND || gb->type() == GuitarBendType::GRACE_NOTE_BEND)) {
return true;
}
}

return false;
}

bool Chord::preOrGraceBendSpacingExceptionInTab() const
{
if (!staffType()->isTabStaff() || !isGrace()) {
return false;
}

std::vector<GuitarBend*> bends;
for (Note* note : m_notes) {
GuitarBend* bendFor = note->bendFor();
if (bendFor) {
GuitarBendType bendType = bendFor->type();
if (bendType == GuitarBendType::PRE_BEND || bendType == GuitarBendType::GRACE_NOTE_BEND) {
bends.push_back(bendFor);
break;
}
}
}

if (bends.empty() || bends.size() < m_notes.size()) {
return false;
}

Chord* endChord = bends.front()->endNote()->chord();
if (!endChord) {
return false;
}

GuitarBendType type = bends.front()->type();
for (GuitarBend* gb : bends) {
if (gb->type() != type || (gb->endNote() && gb->endNote()->chord() != endChord)) {
return false;
}
}

if (type == GuitarBendType::PRE_BEND) {
return true;
}

for (Note* note : endChord->notes()) {
GuitarBend* bendBack = note->bendBack();
if (bendBack) {
Note* startNote = bendBack->startNote();
if (!startNote || startNote->chord() != this) {
return false;
}
}
}

return bends.size() < endChord->notes().size();
}

//---------------------------------------------------------
// tremoloChordType
//---------------------------------------------------------
Expand Down Expand Up @@ -2603,6 +2675,7 @@ EngravingItem* Chord::nextElement()
break;
}

case ElementType::GUITAR_BEND_SEGMENT:
case ElementType::GLISSANDO_SEGMENT:
case ElementType::TIE_SEGMENT: {
SpannerSegment* s = toSpannerSegment(e);
Expand Down
9 changes: 6 additions & 3 deletions src/engraving/dom/chord.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ class Chord final : public ChordRest
void setTremolo(Tremolo* t, bool applyLogic = true);

ChordLine* chordLine() const;
bool endsGlissando() const { return m_endsGlissando; }
void setEndsGlissando(bool val) { m_endsGlissando = val; }
void updateEndsGlissando();
bool endsGlissandoOrGuitarBend() const { return m_endsGlissando; }
void setEndsGlissandoOrGuitarBend(bool val) { m_endsGlissando = val; }
void updateEndsGlissandoOrGuitarBend();
StemSlash* stemSlash() const { return m_stemSlash; }
bool slash();
void setSlash(bool flag, bool stemless);
Expand Down Expand Up @@ -209,6 +209,9 @@ class Chord final : public ChordRest
bool isGrace() const { return m_noteType != NoteType::NORMAL; }
void toGraceAfter();

bool isPreBendOrGraceBendStart() const;
bool preOrGraceBendSpacingExceptionInTab() const;

void setTrack(track_idx_t val) override;

double dotPosX() const { return m_dotPosX; }
Expand Down
122 changes: 122 additions & 0 deletions src/engraving/dom/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#include "drumset.h"
#include "dynamic.h"
#include "factory.h"
#include "glissando.h"
#include "guitarbend.h"
#include "hairpin.h"
#include "harmony.h"
#include "key.h"
Expand Down Expand Up @@ -834,6 +836,126 @@ Note* Score::setGraceNote(Chord* ch, int pitch, NoteType type, int len)
return note;
}

Note* Score::addEndNoteForBend(Note* startNote)
{
track_idx_t track = startNote->track();
Chord* startChord = startNote->chord();
Segment* startSegment = startChord->segment();

Segment* endSegment = startSegment->nextCR(track);
if (!endSegment) {
return nullptr;
}

EngravingItem* item = endSegment->elementAt(track);
if (!item || !item->isRest()) {
return nullptr;
}

Rest* rest = toRest(item);
Fraction duration = std::min(startChord->ticks(), rest->ticks());
NoteVal noteVal = startNote->noteVal();

endSegment = setNoteRest(endSegment, track, noteVal, duration);
Chord* endChord = endSegment ? toChord(endSegment->elementAt(track)) : nullptr;
Note* endNote = endChord ? endChord->upNote() : nullptr;
if (endNote) {
endNote->transposeDiatonic(1, true, false);
}

return endNote;
}

GuitarBend* Score::addGuitarBend(GuitarBendType type, Note* note, Note* endNote)
{
if (note->isPreBendStart()) {
return nullptr;
}

if (note->isGraceBendStart() && type != GuitarBendType::PRE_BEND) {
return nullptr;
}

Chord* chord = note->chord();

if (type == GuitarBendType::BEND) {
for (Spanner* sp : note->spannerFor()) {
if (sp->isGuitarBend() || sp->isGlissando()) {
return nullptr;
}
}

if (!endNote) {
endNote = Glissando::guessFinalNote(chord, note);
}

if (!endNote) {
endNote = addEndNoteForBend(note);
}

if (!endNote) {
return nullptr;
}
}

GuitarBend* bend = new GuitarBend(score()->dummy()->note());
bend->setAnchor(Spanner::Anchor::NOTE);
bend->setTick(chord->tick());
bend->setTrack(chord->track());

if (type == GuitarBendType::BEND) {
bend->setType(chord->isGrace() ? GuitarBendType::GRACE_NOTE_BEND : type);
bend->setStartElement(note);
bend->setTick2(endNote->tick());
bend->setTrack2(endNote->track());
bend->setEndElement(endNote);
bend->setParent(note);
GuitarBend::fixNotesFrettingForStandardBend(note, endNote);
} else {
bend->setType(type);
bend->setTick2(chord->tick());
bend->setTrack2(chord->track());

if (type == GuitarBendType::PRE_BEND || type == GuitarBendType::GRACE_NOTE_BEND) {
// Create grace note
Note* graceNote = setGraceNote(chord, note->pitch(), NoteType::APPOGGIATURA, Constants::DIVISION / 2);
graceNote->transposeDiatonic(-1, true, false);
GuitarBend::fixNotesFrettingForGraceBend(graceNote, note);

Chord* graceChord = graceNote->chord();
for (EngravingObject* item : graceChord->linkList()) {
Chord* linkedGrace = toChord(item);
linkedGrace->undoChangeProperty(Pid::NO_STEM, true);
linkedGrace->undoChangeProperty(Pid::BEAM_MODE, BeamMode::NONE);
}

// Add bend
bend->setParent(graceNote);
bend->setStartElement(graceNote);
bend->setEndElement(note);
} else if (type == GuitarBendType::SLIGHT_BEND) {
bend->setParent(note);
bend->setStartElement(note);
// Slight bends don't end on another note
bend->setEndElement(note);
}
}

Chord* startChord = bend->startNote()->chord();
if (startChord->isGrace()) {
for (EngravingObject* item : startChord->linkList()) {
Chord* linkedGrace = toChord(item);
if (linkedGrace->staffType()->isTabStaff()) {
linkedGrace->undoChangeProperty(Pid::NO_STEM, true);
linkedGrace->undoChangeProperty(Pid::BEAM_MODE, BeamMode::NONE);
}
}
}

score()->undoAddElement(bend);
return bend;
}

//---------------------------------------------------------
// createCRSequence
// Create a rest or chord of len f.
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 @@ -121,6 +121,8 @@ set(DOM_SRC
${CMAKE_CURRENT_LIST_DIR}/gradualtempochange.h
${CMAKE_CURRENT_LIST_DIR}/groups.cpp
${CMAKE_CURRENT_LIST_DIR}/groups.h
${CMAKE_CURRENT_LIST_DIR}/guitarbend.cpp
${CMAKE_CURRENT_LIST_DIR}/guitarbend.h
${CMAKE_CURRENT_LIST_DIR}/hairpin.cpp
${CMAKE_CURRENT_LIST_DIR}/hairpin.h
${CMAKE_CURRENT_LIST_DIR}/harmonicmark.cpp
Expand Down
10 changes: 6 additions & 4 deletions src/engraving/dom/edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2798,6 +2798,7 @@ void Score::deleteItem(EngravingItem* el)
case ElementType::RASGUEADO_SEGMENT:
case ElementType::HARMONIC_MARK_SEGMENT:
case ElementType::PICK_SCRAPE_SEGMENT:
case ElementType::GUITAR_BEND_SEGMENT:
{
el = toSpannerSegment(el)->spanner();
undoRemoveElement(el);
Expand Down Expand Up @@ -5866,6 +5867,7 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool
|| et == ElementType::NOTE
|| et == ElementType::TEXT
|| et == ElementType::GLISSANDO
|| et == ElementType::GUITAR_BEND
|| et == ElementType::BEND
|| (et == ElementType::CHORD && toChord(element)->isGrace())
) {
Expand All @@ -5879,7 +5881,7 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool
links = 0;
}
}
if (links == 0) {
if (links == 0 || !addToLinkedStaves) {
undo(new AddElement(element));
return;
}
Expand All @@ -5889,8 +5891,8 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool
if (e == parent) {
ne = element;
} else {
if (element->isGlissando()) { // and other spanners with Anchor::NOTE
Note* newEnd = Spanner::endElementFromSpanner(toGlissando(element), e);
if (element->isGlissando() || element->isGuitarBend()) { // and other spanners with Anchor::NOTE
Note* newEnd = Spanner::endElementFromSpanner(toSpanner(element), e);
if (newEnd) {
ne = element->linkedClone();
toSpanner(ne)->setNoteSpan(toNote(e), newEnd);
Expand Down Expand Up @@ -6267,7 +6269,7 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool
}
}
undo(new AddElement(nsp));
} else if (et == ElementType::GLISSANDO) {
} else if (et == ElementType::GLISSANDO || et == ElementType::GUITAR_BEND) {
undo(new AddElement(toSpanner(ne)));
} else if (element->isTremolo() && toTremolo(element)->twoNotes()) {
Tremolo* tremolo = toTremolo(element);
Expand Down
6 changes: 5 additions & 1 deletion src/engraving/dom/engravingitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,11 @@ PropertyPropagation EngravingItem::propertyPropagation(const EngravingItem* dest
const Score* destinationScore = destinationItem->score();
const bool isTextProperty = propertyGroup(propertyId) == PropertyGroup::TEXT;

if ((isTextProperty && isPropertyLinkedToMaster(propertyId)) || sourceScore == destinationScore) {
if (propertyGroup(propertyId) != PropertyGroup::TEXT && sourceScore == destinationScore) {
return PropertyPropagation::NONE;
}

if ((isTextProperty && isPropertyLinkedToMaster(propertyId))) {
return PropertyPropagation::PROPAGATE;
}

Expand Down
2 changes: 1 addition & 1 deletion src/engraving/dom/engravingobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ bool EngravingObject::isTextBase() const
|| type() == ElementType::MMREST_RANGE
|| type() == ElementType::STICKING
|| type() == ElementType::HARP_DIAGRAM
;
|| type() == ElementType::GUITAR_BEND_TEXT;
}

//---------------------------------------------------------
Expand Down
Loading

0 comments on commit 2fa5483

Please sign in to comment.