LCOV - code coverage report
Current view: top level - src/engraving/dom - chord.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 61.5 % 1529 941
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "chord.h"
      24              : 
      25              : #include <cmath>
      26              : #include <vector>
      27              : 
      28              : #include "containers.h"
      29              : 
      30              : #include "../editing/addremoveelement.h"
      31              : #include "../editing/editchord.h"
      32              : #include "../editing/editnote.h"
      33              : #include "../editing/navigation.h"
      34              : 
      35              : #include "accidental.h"
      36              : #include "arpeggio.h"
      37              : #include "chordbracket.h"
      38              : #include "articulation.h"
      39              : #include "beam.h"
      40              : #include "chordline.h"
      41              : #include "dom/parenthesis.h"
      42              : #include "drumset.h"
      43              : #include "factory.h"
      44              : #include "guitarbend.h"
      45              : #include "hook.h"
      46              : #include "key.h"
      47              : #include "ledgerline.h"
      48              : #include "measure.h"
      49              : #include "mscore.h"
      50              : #include "note.h"
      51              : #include "notedot.h"
      52              : #include "noteevent.h"
      53              : #include "noteline.h"
      54              : #include "ornament.h"
      55              : #include "part.h"
      56              : #include "rest.h"
      57              : #include "score.h"
      58              : #include "segment.h"
      59              : #include "staff.h"
      60              : #include "stafftype.h"
      61              : #include "stem.h"
      62              : #include "stemslash.h"
      63              : #include "stringdata.h"
      64              : #include "system.h"
      65              : #include "tie.h"
      66              : #include "tremolosinglechord.h"
      67              : #include "tremolotwochord.h"
      68              : #include "trill.h"
      69              : #include "tuplet.h"
      70              : #include "utils.h"
      71              : 
      72              : #ifndef ENGRAVING_NO_ACCESSIBILITY
      73              : #include "accessibility/accessibleitem.h"
      74              : #endif
      75              : 
      76              : #include "log.h"
      77              : 
      78              : using namespace mu;
      79              : using namespace mu::engraving;
      80              : 
      81              : namespace mu::engraving {
      82          212 : NoteParenthesisInfo::NoteParenthesisInfo (Parenthesis* lParen, Parenthesis* rParen, std::vector<Note*> nList)
      83          212 :     : m_leftParen(lParen), m_rightParen(rParen), m_notes(nList)
      84              : {
      85          212 :     std::sort(m_notes.begin(), m_notes.end(), noteIsBefore);
      86          212 : }
      87              : 
      88          174 : NoteParenthesisInfo::~NoteParenthesisInfo()
      89              : {
      90          174 :     delete m_leftParen;
      91          174 :     delete m_rightParen;
      92          174 : }
      93              : 
      94            9 : void NoteParenthesisInfo::insertNote(Note* note)
      95              : {
      96            9 :     m_notes.insert(std::upper_bound(m_notes.begin(), m_notes.end(), note, noteIsBefore), note);
      97            9 : }
      98              : 
      99           12 : void NoteParenthesisInfo::removeNote(Note* note)
     100              : {
     101           12 :     muse::remove(m_notes, note);
     102           12 : }
     103              : 
     104              : //---------------------------------------------------------
     105              : //   upNote
     106              : //---------------------------------------------------------
     107              : 
     108       963630 : Note* Chord::upNote() const
     109              : {
     110       963630 :     assert(!m_notes.empty());
     111              : 
     112       963630 :     Note* result = m_notes.back();
     113       963630 :     const Staff* stf = staff();
     114       963630 :     if (!stf) {
     115            0 :         return result;
     116              :     }
     117              : 
     118       963630 :     const StaffType* st  = stf->staffTypeForElement(this);
     119       963630 :     if (st->isDrumStaff()) {
     120        39670 :         for (Note* n : m_notes) {
     121        20449 :             if (n->line() < result->line()) {
     122            0 :                 result = n;
     123              :             }
     124              :         }
     125       944409 :     } else if (st->isTabStaff()) {
     126         2349 :         int line = st->lines();          // start at bottom line
     127              :         int noteLine;
     128              :         // scan each note: if TAB strings are not in sequential order,
     129              :         // visual order of notes might not correspond to pitch order
     130         5301 :         for (Note* n : m_notes) {
     131         2952 :             if (n->shouldHideFret()) {
     132            2 :                 continue;
     133              :             }
     134         2950 :             noteLine = st->physStringToVisual(n->string());
     135         2950 :             if (noteLine < line) {
     136         2931 :                 line   = noteLine;
     137         2931 :                 result = n;
     138              :             }
     139              :         }
     140              :     }
     141       963630 :     return result;
     142              : }
     143              : 
     144              : //---------------------------------------------------------
     145              : //   downNote
     146              : //---------------------------------------------------------
     147              : 
     148       935842 : Note* Chord::downNote() const
     149              : {
     150       935842 :     assert(!m_notes.empty());
     151              : 
     152       935842 :     Note* result = m_notes.front();
     153       935842 :     const Staff* stf = staff();
     154       935842 :     if (!stf) {
     155            0 :         return result;
     156              :     }
     157              : 
     158       935842 :     const StaffType* st  = stf->staffTypeForElement(this);
     159       935842 :     if (st->isDrumStaff()) {
     160        28527 :         for (Note* n : m_notes) {
     161        14653 :             if (n->line() > result->line()) {
     162            0 :                 result = n;
     163              :             }
     164              :         }
     165       921968 :     } else if (st->isTabStaff()) {
     166         1322 :         int line        = 0;          // start at top line
     167              :         int noteLine;
     168              :         // scan each note: if TAB strings are not in sequential order,
     169              :         // visual order of notes might not correspond to pitch order
     170         3095 :         for (Note* n : m_notes) {
     171         1773 :             if (n->shouldHideFret()) {
     172            4 :                 continue;
     173              :             }
     174         1769 :             noteLine = st->physStringToVisual(n->string());
     175         1769 :             if (noteLine > line) {
     176         1055 :                 line = noteLine;
     177         1055 :                 result = n;
     178              :             }
     179              :         }
     180              :     }
     181       935842 :     return result;
     182              : }
     183              : 
     184              : //---------------------------------------------------------
     185              : //   upLine / downLine
     186              : //---------------------------------------------------------
     187              : 
     188       386588 : int Chord::upLine() const
     189              : {
     190       386588 :     return onTabStaff() ? upString() * 2 : upNote()->line();
     191              : }
     192              : 
     193       374751 : int Chord::downLine() const
     194              : {
     195       374751 :     return onTabStaff() ? downString() * 2 : downNote()->line();
     196              : }
     197              : 
     198              : //---------------------------------------------------------
     199              : //   upString / downString
     200              : //
     201              : //    return the topmost / bottommost string used by chord
     202              : //    Top and bottom refer to the DRAWN position, not the position in the instrument
     203              : //    (i.e., upside-down TAB are taken into account)
     204              : //
     205              : //    If no staff, always return 0
     206              : //    If staff is not a TAB, always returns TOP and BOTTOM staff lines
     207              : //---------------------------------------------------------
     208              : 
     209          979 : int Chord::upString() const
     210              : {
     211              :     // if no staff or staff not a TAB, return 0 (=topmost line)
     212          979 :     const Staff* st = staff();
     213          979 :     if (!st) {
     214            0 :         return 0;
     215              :     }
     216              : 
     217          979 :     const StaffType* tab = st->staffTypeForElement(this);
     218          979 :     if (!tab->isTabStaff()) {
     219            0 :         return 0;
     220              :     }
     221              : 
     222          979 :     int line = tab->lines() - 1;              // start at bottom line
     223              :     int noteLine;
     224              :     // scan each note: if TAB strings are not in sequential order,
     225              :     // visual order of notes might not correspond to pitch order
     226          979 :     size_t n = m_notes.size();
     227         2221 :     for (size_t i = 0; i < n; ++i) {
     228         1242 :         noteLine = tab->physStringToVisual(m_notes.at(i)->string());
     229         1242 :         if (noteLine < line) {
     230         1068 :             line = noteLine;
     231              :         }
     232              :     }
     233          979 :     return line;
     234              : }
     235              : 
     236         2284 : int Chord::downString() const
     237              : {
     238         2284 :     const Staff* st = staff();
     239         2284 :     if (!st) {                                         // if no staff, return 0
     240            0 :         return 0;
     241              :     }
     242              : 
     243         2284 :     const StaffType* tab = st->staffTypeForElement(this);
     244         2284 :     if (!tab->isTabStaff()) {                // if staff not a TAB, return bottom line
     245            0 :         return st->lines(tick()) - 1;
     246              :     }
     247              : 
     248         2284 :     int line = 0;           // start at top line
     249              :     int noteLine;
     250         2284 :     size_t n = m_notes.size();
     251         4943 :     for (size_t i = 0; i < n; ++i) {
     252         2659 :         noteLine = tab->physStringToVisual(m_notes.at(i)->string());
     253         2659 :         if (noteLine > line) {
     254         1786 :             line = noteLine;
     255              :         }
     256              :     }
     257         2284 :     return line;
     258              : }
     259              : 
     260              : //---------------------------------------------------------
     261              : //   noteDistances
     262              : //---------------------------------------------------------
     263              : 
     264        44780 : std::vector<int> Chord::noteDistances() const
     265              : {
     266        44780 :     const StaffType* staffType = this->staffType();
     267        44780 :     assert(staffType);
     268        44780 :     bool isTabStaff = staffType->isTabStaff();
     269        44780 :     int staffMiddleLine = staffType->middleLine();
     270              : 
     271        44780 :     std::vector<int> distances;
     272        44780 :     distances.reserve(m_notes.size());
     273        95827 :     for (Note* note : m_notes) {
     274        51047 :         int noteLine = isTabStaff ? note->string() : note->line();
     275        51047 :         distances.push_back(noteLine - staffMiddleLine);
     276              :     }
     277        44780 :     return distances;
     278            0 : }
     279              : 
     280              : //---------------------------------------------------------
     281              : //   Chord
     282              : //---------------------------------------------------------
     283              : 
     284        30391 : Chord::Chord(DummyParentOr<Segment> parent)
     285        30391 :     : ChordRest(ElementType::CHORD, parent)
     286              : {
     287        30391 :     m_stem             = 0;
     288        30391 :     m_hook             = 0;
     289        30391 :     m_stemDirection    = DirectionV::AUTO;
     290        30391 :     m_arpeggio         = 0;
     291        30391 :     m_spanArpeggio     = 0;
     292        30391 :     m_endsNoteAnchoredLine    = false;
     293        30391 :     m_noteType         = NoteType::NORMAL;
     294        30391 :     m_stemSlash        = 0;
     295        30391 :     m_noStem           = false;
     296        30391 :     m_showStemSlash    = m_noteType == NoteType::ACCIACCATURA;
     297        30391 :     m_playEventType    = PlayEventType::Auto;
     298        30391 :     m_spaceLw          = 0.;
     299        30391 :     m_spaceRw          = 0.;
     300        30391 :     m_crossMeasure     = CrossMeasure::UNKNOWN;
     301        30391 :     m_graceIndex       = 0;
     302        30391 :     m_combineVoice     = AutoOnOff::AUTO;
     303        30391 : }
     304              : 
     305         3512 : Chord::Chord(const Chord& c, bool link)
     306         3512 :     : ChordRest(c, link)
     307              : {
     308         3512 :     if (link) {
     309         1037 :         score()->undo(new Link(this, const_cast<Chord*>(&c)));
     310              :     }
     311              : 
     312         8989 :     for (Note* onote : c.m_notes) {
     313         5477 :         Note* nnote = Factory::copyNote(*onote, link);
     314         5477 :         add(nnote);
     315              :     }
     316         3535 :     for (Chord* gn : c.graceNotes()) {
     317           23 :         Chord* nc = new Chord(*gn, link);
     318           23 :         add(nc);
     319              :     }
     320         3600 :     for (Articulation* a : c.m_articulations) {      // make deep copy
     321           88 :         Articulation* na = a->clone();
     322           88 :         if (link) {
     323           27 :             score()->undo(new Link(na, a));
     324              :         }
     325           88 :         na->setOwnershipParent(this);
     326           88 :         na->setTrack(track());
     327           88 :         m_articulations.push_back(na);
     328              :     }
     329         3512 :     m_stem          = 0;
     330         3512 :     m_hook          = 0;
     331         3512 :     m_endsNoteAnchoredLine = false;
     332         3512 :     m_arpeggio      = 0;
     333         3512 :     m_stemSlash     = 0;
     334              : 
     335         3512 :     m_spanArpeggio   = c.m_spanArpeggio;
     336         3512 :     m_graceIndex     = c.m_graceIndex;
     337         3512 :     m_noStem         = c.m_noStem;
     338         3512 :     m_showStemSlash  = c.m_showStemSlash;
     339         3512 :     m_playEventType  = c.m_playEventType;
     340         3512 :     m_stemDirection  = c.m_stemDirection;
     341         3512 :     m_noteType       = c.m_noteType;
     342         3512 :     m_crossMeasure   = CrossMeasure::UNKNOWN;
     343         3512 :     m_combineVoice     = c.m_combineVoice;
     344              : 
     345         3512 :     if (c.m_stem) {
     346         2514 :         add(Factory::copyStem(*(c.m_stem)));
     347              :     }
     348         3512 :     if (c.m_hook) {
     349          428 :         add(new Hook(*(c.m_hook)));
     350              :     }
     351         3512 :     if (c.m_stemSlash) {
     352            0 :         add(Factory::copyStemSlash(*(c.m_stemSlash)));
     353              :     }
     354         3512 :     if (c.m_arpeggio) {
     355           22 :         Arpeggio* a = c.m_arpeggio->isChordBracket() ? new ChordBracket(*toChordBracket(c.m_arpeggio)) : new Arpeggio(*(c.m_arpeggio));
     356           22 :         add(a);
     357           22 :         if (link) {
     358           22 :             score()->undo(new Link(a, const_cast<Arpeggio*>(c.m_arpeggio)));
     359              :         }
     360              :     }
     361              : 
     362         3512 :     if (c.m_tremoloSingleChord) {
     363            2 :         TremoloSingleChord* t = Factory::copyTremoloSingleChord(*(c.m_tremoloSingleChord));
     364            2 :         if (link) {
     365            2 :             score()->undo(new Link(t, const_cast<TremoloSingleChord*>(c.m_tremoloSingleChord)));
     366              :         }
     367            2 :         add(t);
     368         3510 :     } else if (c.m_tremoloTwoChord) {
     369           14 :         if (c.m_tremoloTwoChord->chord1() == &c) {
     370            8 :             TremoloTwoChord* t = Factory::copyTremoloTwoChord(*(c.m_tremoloTwoChord));
     371            8 :             if (link) {
     372            4 :                 score()->undo(new Link(t, const_cast<TremoloTwoChord*>(c.m_tremoloTwoChord)));
     373              :             }
     374            8 :             t->setChords(this, nullptr);
     375            8 :             add(t);
     376              :         }
     377              :     }
     378              : 
     379         3516 :     for (EngravingItem* e : c.el()) {
     380            4 :         if (e->isChordLine()) {
     381            4 :             ChordLine* cl = toChordLine(e);
     382            4 :             ChordLine* ncl = Factory::copyChordLine(*cl);
     383            4 :             add(ncl);
     384            4 :             if (cl->note()) {
     385            2 :                 ncl->setNote(findNote(cl->note()->pitch()));
     386              :             }
     387            4 :             if (link) {
     388            4 :                 score()->undo(new Link(ncl, cl));
     389              :             }
     390              :         }
     391              :     }
     392              : 
     393         3516 :     for (EngravingItem* e : c.el()) {
     394            4 :         if (e->isChordBracket()) {
     395            0 :             EngravingItem* clonedChordBracket = e->linkedClone();
     396            0 :             add(clonedChordBracket);
     397              :         }
     398              :     }
     399              : 
     400         3512 :     if (!c.noteParentheses().empty()) {
     401           12 :         for (const NoteParenthesisInfo* info : c.noteParentheses()) {
     402            6 :             Parenthesis* newLeftParen = toParenthesis(info->leftParen()->clone());
     403            6 :             newLeftParen->setOwnershipParent(this);
     404            6 :             Parenthesis* newRightParen = toParenthesis(info->rightParen()->clone());
     405            6 :             newRightParen->setOwnershipParent(this);
     406              : 
     407            6 :             if (link && !info->leftParen()->generated()) {
     408            2 :                 score()->undo(new Link(newLeftParen, info->leftParen()));
     409              :             }
     410            6 :             if (link && !info->rightParen()->generated()) {
     411            2 :                 score()->undo(new Link(newRightParen, info->rightParen()));
     412              :             }
     413              : 
     414            6 :             std::vector<Note*> newNotes;
     415            6 :             newNotes.reserve(info->notes().size());
     416           12 :             for (Note* note : info->notes()) {
     417            6 :                 newNotes.push_back(findNote(note->pitch()));
     418              :             }
     419              : 
     420            6 :             m_noteParens.push_back(new NoteParenthesisInfo(newLeftParen, newRightParen, newNotes));
     421            6 :         }
     422              :     }
     423         3512 : }
     424              : 
     425              : //---------------------------------------------------------
     426              : //   undoUnlink
     427              : //---------------------------------------------------------
     428              : 
     429          179 : void Chord::undoUnlink()
     430              : {
     431          179 :     ChordRest::undoUnlink();
     432          360 :     for (Note* n : m_notes) {
     433          181 :         n->undoUnlink();
     434              :     }
     435          181 :     for (Chord* gn : graceNotes()) {
     436            2 :         gn->undoUnlink();
     437              :     }
     438          188 :     for (Articulation* a : m_articulations) {
     439            9 :         a->undoUnlink();
     440              :     }
     441              : /*      if (_glissando)
     442              :             _glissando->undoUnlink(); */
     443          179 :     if (m_arpeggio) {
     444            1 :         m_arpeggio->undoUnlink();
     445              :     }
     446              : 
     447          179 :     if (tremoloSingleChord()) {
     448            0 :         tremoloSingleChord()->undoUnlink();
     449              :     }
     450              : 
     451          179 :     for (EngravingItem* e : el()) {
     452            0 :         if (e->isChordLine()) {
     453            0 :             e->undoUnlink();
     454              :         }
     455              :     }
     456          179 : }
     457              : 
     458              : //---------------------------------------------------------
     459              : //   ~Chord
     460              : //---------------------------------------------------------
     461              : 
     462        60138 : Chord::~Chord()
     463              : {
     464        30069 :     muse::DeleteAll(m_articulations);
     465              : 
     466        30069 :     if (tremoloTwoChord()) {
     467          122 :         if (tremoloTwoChord()->chord1() == this) {
     468           62 :             tremoloTwoChord()->setChord1(nullptr);
     469           60 :         } else if (tremoloTwoChord()->chord2() == this) {
     470           60 :             tremoloTwoChord()->setChord2(nullptr);
     471              :         }
     472              :     }
     473              : 
     474        30069 :     delete m_arpeggio;
     475        30069 :     delete m_stemSlash;
     476        30069 :     delete m_stem;
     477        30069 :     delete m_hook;
     478        30069 :     muse::DeleteAll(m_ledgerLines);
     479        30069 :     muse::DeleteAll(m_graceNotes);
     480        30069 :     muse::DeleteAll(m_notes);
     481        30069 :     muse::DeleteAll(m_noteParens);
     482        60138 : }
     483              : 
     484              : #ifndef ENGRAVING_NO_ACCESSIBILITY
     485            0 : AccessibleItemPtr Chord::createAccessible()
     486              : {
     487            0 :     return std::make_shared<AccessibleItem>(this, AccessibleItem::Group);
     488              : }
     489              : 
     490              : #endif
     491              : 
     492              : //---------------------------------------------------------
     493              : //   noteHeadWidth
     494              : //---------------------------------------------------------
     495              : 
     496       195607 : double Chord::noteHeadWidth() const
     497              : {
     498       195607 :     return score()->noteHeadWidth() * mag();
     499              : }
     500              : 
     501              : //---------------------------------------------------------
     502              : //   rightEdge
     503              : //---------------------------------------------------------
     504              : 
     505            0 : double Chord::rightEdge() const
     506              : {
     507            0 :     double right = 0.0;
     508            0 :     for (Note* n : notes()) {
     509            0 :         right = std::max(right, x() + n->x() + n->bboxRightPos());
     510              :     }
     511              : 
     512            0 :     return right;
     513              : }
     514              : 
     515         5182 : TremoloType Chord::tremoloType() const
     516              : {
     517         5182 :     if (tremoloSingleChord()) {
     518          117 :         return tremoloSingleChord()->tremoloType();
     519         5065 :     } else if (tremoloTwoChord()) {
     520           22 :         return tremoloTwoChord()->tremoloType();
     521              :     } else {
     522         5043 :         return TremoloType::INVALID_TREMOLO;
     523              :     }
     524              : }
     525              : 
     526      1138463 : TremoloTwoChord* Chord::tremoloTwoChord() const
     527              : {
     528      1138463 :     return m_tremoloTwoChord;
     529              : }
     530              : 
     531       519362 : TremoloSingleChord* Chord::tremoloSingleChord() const
     532              : {
     533       519362 :     return m_tremoloSingleChord;
     534              : }
     535              : 
     536          262 : void Chord::setTremoloTwoChord(TremoloTwoChord* tr, bool applyLogic)
     537              : {
     538          262 :     if (m_tremoloTwoChord && tr && tr == m_tremoloTwoChord) {
     539           74 :         return;
     540              :     }
     541              : 
     542          188 :     if (m_tremoloTwoChord) {
     543           30 :         TDuration d;
     544           30 :         const Fraction f = ticks();
     545           30 :         if (f.numerator() > 0) {
     546           30 :             d = TDuration(f);
     547              :         } else {
     548            0 :             d = m_tremoloTwoChord->durationType();
     549            0 :             const int dots = d.dots();
     550            0 :             d = d.shift(1);
     551            0 :             d.setDots(dots);
     552              :         }
     553              : 
     554           30 :         setDurationType(d);
     555           30 :         Chord* other = m_tremoloTwoChord->chord1() == this ? m_tremoloTwoChord->chord2() : m_tremoloTwoChord->chord1();
     556           30 :         m_tremoloTwoChord = nullptr;
     557           30 :         if (other) {
     558           10 :             other->setTremoloTwoChord(nullptr);
     559              :         }
     560              :     }
     561          188 :     m_tremoloSingleChord = nullptr;
     562              : 
     563          188 :     if (tr && applyLogic) {
     564          140 :         TDuration d = tr->durationType();
     565          140 :         if (!d.isValid()) {
     566           52 :             d = durationType();
     567           52 :             const int dots = d.dots();
     568           52 :             d = d.shift(-1);
     569           52 :             d.setDots(dots);
     570           52 :             tr->setDurationType(d);
     571              :         }
     572              : 
     573          140 :         setDurationType(d);
     574          140 :         Chord* other = tr->chord1() == this ? tr->chord2() : tr->chord1();
     575          140 :         m_tremoloTwoChord = tr;
     576          140 :         if (other) {
     577          102 :             other->setTremoloTwoChord(tr);
     578              :         }
     579              :     }
     580              : 
     581          188 :     m_tremoloTwoChord = tr;
     582              : }
     583              : 
     584          166 : void Chord::setTremoloSingleChord(TremoloSingleChord* tr)
     585              : {
     586          166 :     if (m_tremoloSingleChord && tr && tr == m_tremoloSingleChord) {
     587            0 :         return;
     588              :     }
     589              : 
     590          166 :     if (m_tremoloTwoChord) {
     591            0 :         TDuration d;
     592            0 :         const Fraction f = ticks();
     593            0 :         if (f.numerator() > 0) {
     594            0 :             d = TDuration(f);
     595              :         } else {
     596            0 :             d = m_tremoloTwoChord->durationType();
     597            0 :             const int dots = d.dots();
     598            0 :             d = d.shift(1);
     599            0 :             d.setDots(dots);
     600              :         }
     601              : 
     602            0 :         setDurationType(d);
     603            0 :         Chord* other = m_tremoloTwoChord->chord1() == this ? m_tremoloTwoChord->chord2() : m_tremoloTwoChord->chord1();
     604            0 :         m_tremoloTwoChord = nullptr;
     605            0 :         if (other) {
     606            0 :             other->setTremoloTwoChord(nullptr);
     607              :         }
     608              :     }
     609              : 
     610          166 :     m_tremoloSingleChord = tr;
     611              : }
     612              : 
     613              : //---------------------------------------------------------
     614              : //   add
     615              : //---------------------------------------------------------
     616              : 
     617        77380 : void Chord::add(EngravingItem* e)
     618              : {
     619        77380 :     if (e->ownershipParent() != this) {
     620         9802 :         e->setOwnershipParent(this);
     621              :     }
     622        77380 :     e->setTrack(track());
     623        77380 :     switch (e->type()) {
     624        41413 :     case ElementType::NOTE:
     625              :     {
     626        41413 :         Note* note = toNote(e);
     627        41413 :         bool tab = staff() && staff()->isTabStaff(tick());
     628        41413 :         bool found = false;
     629              : 
     630        46985 :         for (unsigned idx = 0; idx < m_notes.size(); ++idx) {
     631        10250 :             if (tab) {
     632              :                 // _notes should be sorted by string
     633          116 :                 if (note->string() > m_notes[idx]->string()) {
     634            9 :                     m_notes.insert(m_notes.begin() + idx, note);
     635            9 :                     found = true;
     636            9 :                     break;
     637              :                 }
     638              :             } else {
     639              :                 // _notes should be sorted by line position,
     640              :                 // but it's often not yet possible since line is unknown
     641              :                 // use pitch instead, and line as a second sort criteria.
     642        10134 :                 if (note->pitch() <= m_notes[idx]->pitch()) {
     643         4669 :                     if (note->pitch() == m_notes[idx]->pitch() && note->line() >= m_notes[idx]->line()) {
     644           55 :                         m_notes.insert(m_notes.begin() + idx + 1, note);
     645              :                     } else {
     646         4614 :                         m_notes.insert(m_notes.begin() + idx, note);
     647              :                     }
     648         4669 :                     found = true;
     649         4669 :                     break;
     650              :                 }
     651              :             }
     652              :         }
     653        41413 :         if (!found) {
     654        36735 :             m_notes.push_back(note);
     655              :         }
     656        41413 :         note->connectTiedNotes();
     657        41413 :         if (voice() && measure() && note->visible()) {
     658         2667 :             measure()->setHasVoices(staffIdx(), true);
     659              :         }
     660              :     }
     661        41413 :     break;
     662           86 :     case ElementType::ARPEGGIO:
     663           86 :         m_arpeggio = toArpeggio(e);
     664           86 :         break;
     665            0 :     case ElementType::CHORD_BRACKET:
     666            0 :         addEl(e);
     667            0 :         break;
     668           41 :     case ElementType::TREMOLO_TWOCHORD:
     669           41 :         setTremoloTwoChord(item_cast<TremoloTwoChord*>(e));
     670           41 :         break;
     671           77 :     case ElementType::TREMOLO_SINGLECHORD:
     672           77 :         setTremoloSingleChord(item_cast<TremoloSingleChord*>(e));
     673           77 :         break;
     674            0 :     case ElementType::GLISSANDO:
     675            0 :         m_endsNoteAnchoredLine = true;
     676            0 :         break;
     677        30023 :     case ElementType::STEM:
     678        30023 :         assert(!m_stem);
     679        30023 :         m_stem = toStem(e);
     680        30023 :         break;
     681         1697 :     case ElementType::HOOK:
     682         1697 :         m_hook = toHook(e);
     683         1697 :         break;
     684          158 :     case ElementType::CHORDLINE:
     685          158 :         addEl(e);
     686          158 :         break;
     687          142 :     case ElementType::STEM_SLASH:
     688          142 :         assert(!m_stemSlash);
     689          142 :         m_stemSlash = toStemSlash(e);
     690          142 :         break;
     691          671 :     case ElementType::CHORD:
     692              :     {
     693          671 :         Chord* gc = toChord(e);
     694          671 :         assert(gc->noteType() != NoteType::NORMAL);
     695          671 :         size_t idx = gc->graceIndex();
     696          671 :         gc->setFlag(ElementFlag::MOVABLE, true);
     697          671 :         m_graceNotes.insert(m_graceNotes.begin() + idx, gc);
     698              :     }
     699          671 :     break;
     700            0 :     case ElementType::LEDGER_LINE:
     701            0 :         ASSERT_X("Chord::add ledgerline");
     702              :         break;
     703         1289 :     case ElementType::ARTICULATION:
     704              :     case ElementType::ORNAMENT:
     705              :     case ElementType::TAPPING:
     706              :     {
     707         1289 :         Articulation* a = toArticulation(e);
     708         1289 :         if (a->layoutCloseToNote()) {
     709          417 :             if (a->isStaccato()) {
     710              :                 // staccato is always the first articulation
     711          295 :                 m_articulations.insert(m_articulations.begin(), a);
     712              :             } else {
     713          122 :                 auto i = m_articulations.begin();
     714          151 :                 while (i != m_articulations.end() && (*i)->layoutCloseToNote()) {
     715           29 :                     i++;
     716              :                 }
     717          122 :                 m_articulations.insert(i, a);
     718              :             }
     719              :         } else {
     720          872 :             m_articulations.push_back(a);
     721              :         }
     722              :     }
     723         1289 :     break;
     724         1783 :     default:
     725         1783 :         ChordRest::add(e);
     726         1783 :         return;
     727              :     }
     728              : 
     729        75597 :     e->added();
     730              : }
     731              : 
     732              : //---------------------------------------------------------
     733              : //   remove
     734              : //---------------------------------------------------------
     735              : 
     736         1237 : void Chord::remove(EngravingItem* e)
     737              : {
     738         1237 :     if (!e) {
     739            0 :         return;
     740              :     }
     741              : 
     742         1237 :     switch (e->type()) {
     743          376 :     case ElementType::NOTE:
     744              :     {
     745          376 :         Note* note = toNote(e);
     746          376 :         auto i = std::find(m_notes.begin(), m_notes.end(), note);
     747          376 :         if (i != m_notes.end()) {
     748          376 :             m_notes.erase(i);
     749          376 :             note->disconnectTiedNotes();
     750          376 :             for (Spanner* s : note->spannerBack()) {
     751            0 :                 note->removeSpannerBack(s);
     752              :             }
     753          376 :             for (Spanner* s : note->spannerFor()) {
     754            0 :                 note->removeSpannerFor(s);
     755              :             }
     756         1128 :             EditChord::removeChordParentheses(this, { note });
     757              :         } else {
     758            0 :             LOGD("Chord::remove() note %p not found!", e);
     759              :         }
     760          376 :         if (voice() && measure() && note->visible()) {
     761           99 :             measure()->checkMultiVoices(staffIdx());
     762              :         }
     763              :     }
     764          376 :     break;
     765              : 
     766            0 :     case ElementType::ARPEGGIO:
     767            0 :         if (m_spanArpeggio == m_arpeggio) {
     768            0 :             m_spanArpeggio = nullptr;
     769              :         }
     770            0 :         m_arpeggio = nullptr;
     771            0 :         break;
     772            0 :     case ElementType::CHORD_BRACKET:
     773            0 :         removeEl(e);
     774            0 :         break;
     775            1 :     case ElementType::TREMOLO_TWOCHORD:
     776            1 :         setTremoloTwoChord(nullptr);
     777            1 :         break;
     778            0 :     case ElementType::TREMOLO_SINGLECHORD:
     779            0 :         setTremoloSingleChord(nullptr);
     780            0 :         break;
     781            0 :     case ElementType::GLISSANDO:
     782            0 :         m_endsNoteAnchoredLine = false;
     783            0 :         break;
     784          567 :     case ElementType::STEM:
     785          567 :         m_stem = 0;
     786          567 :         break;
     787           30 :     case ElementType::HOOK:
     788           30 :         m_hook = 0;
     789           30 :         break;
     790           11 :     case ElementType::STEM_SLASH:
     791           11 :         assert(m_stemSlash);
     792           11 :         if (m_stemSlash->selected() && score()) {
     793            0 :             score()->deselect(m_stemSlash);
     794              :         }
     795           11 :         m_stemSlash = 0;
     796           11 :         break;
     797           12 :     case ElementType::CHORDLINE:
     798           12 :         removeEl(e);
     799           12 :         break;
     800            9 :     case ElementType::CHORD:
     801              :     {
     802            9 :         auto i = std::find(m_graceNotes.begin(), m_graceNotes.end(), toChord(e));
     803            9 :         IF_ASSERT_FAILED(i != m_graceNotes.end()) {
     804            0 :             break;
     805              :         }
     806            9 :         Chord* grace = *i;
     807            9 :         grace->setGraceIndex(i - m_graceNotes.begin());
     808            9 :         m_graceNotes.erase(i);
     809              :     }
     810            9 :     break;
     811          213 :     case ElementType::ARTICULATION:
     812              :     case ElementType::ORNAMENT:
     813              :     case ElementType::TAPPING:
     814              :     {
     815          213 :         Articulation* a = toArticulation(e);
     816          213 :         if (!muse::remove(m_articulations, a)) {
     817            0 :             LOGD("Chord::remove(): articulation not found");
     818              :         }
     819              :     }
     820          213 :     break;
     821            0 :     case ElementType::PARENTHESIS: {
     822            0 :         NoteParenthesisInfo* parenInfo = findNoteParenthesisInfo(toParenthesis(e));
     823            0 :         IF_ASSERT_FAILED(parenInfo) {
     824            0 :             LOGD() << "Chord::remove(): This parenthesis does not belong to this chord";
     825            0 :             return;
     826              :         }
     827            0 :         EditChord::removeChordParentheses(this, parenInfo->notes());
     828            0 :         break;
     829              :     }
     830              :     break;
     831           18 :     default:
     832           18 :         ChordRest::remove(e);
     833           18 :         return;
     834              :     }
     835              : 
     836         1219 :     e->removed();
     837              : }
     838              : 
     839              : //---------------------------------------------------------
     840              : //   maxHeadWidth
     841              : //---------------------------------------------------------
     842              : 
     843            0 : double Chord::maxHeadWidth() const
     844              : {
     845              :     // determine max head width in chord
     846            0 :     double hw = 0;
     847            0 :     for (const Note* n : m_notes) {
     848            0 :         double t = n->headWidth();
     849            0 :         if (t > hw) {
     850            0 :             hw = t;
     851              :         }
     852              :     }
     853            0 :     return hw;
     854              : }
     855              : 
     856              : //---------------------------------------------------------
     857              : //   selectedNote
     858              : //---------------------------------------------------------
     859              : 
     860            0 : Note* Chord::selectedNote() const
     861              : {
     862            0 :     Note* note = 0;
     863            0 :     size_t n = m_notes.size();
     864            0 :     for (size_t i = 0; i < n; ++i) {
     865            0 :         Note* currentNote = m_notes.at(i);
     866            0 :         if (currentNote->selected()) {
     867            0 :             if (note) {
     868            0 :                 return 0;
     869              :             }
     870            0 :             note = currentNote;
     871              :         }
     872              :     }
     873            0 :     return note;
     874              : }
     875              : 
     876              : //---------------------------------------------------------
     877              : //   upPos
     878              : //---------------------------------------------------------
     879              : 
     880         3508 : double Chord::upPos() const
     881              : {
     882         3508 :     return upNote()->pos().y();
     883              : }
     884              : 
     885              : //---------------------------------------------------------
     886              : //   downPos
     887              : //---------------------------------------------------------
     888              : 
     889         3497 : double Chord::downPos() const
     890              : {
     891         3497 :     return downNote()->pos().y();
     892              : }
     893              : 
     894            0 : bool Chord::allNotesTiedToNext() const
     895              : {
     896            0 :     Chord* tiedChord = nullptr;
     897            0 :     for (Note* note : m_notes) {
     898            0 :         if (!note->tieFor()) {
     899            0 :             return false;
     900              :         }
     901              : 
     902            0 :         Note* endNote = note->tieFor()->endNote();
     903            0 :         Chord* endChord = endNote ? endNote->chord() : nullptr;
     904            0 :         if (!endChord) {
     905            0 :             return false;
     906              :         }
     907              : 
     908            0 :         if (!tiedChord) {
     909            0 :             tiedChord = endChord;
     910            0 :             continue;
     911              :         }
     912              : 
     913            0 :         if (endChord != tiedChord) {
     914            0 :             return false;
     915              :         }
     916              :     }
     917              : 
     918            0 :     return true;
     919              : }
     920              : 
     921         8281 : bool Chord::allElementsInvisible() const
     922              : {
     923         8353 :     for (EngravingObject* child : getChildren()) {
     924         8321 :         if (toEngravingItem(child)->visible()) {
     925         8249 :             return false;
     926              :         }
     927         8281 :     }
     928              : 
     929           32 :     for (Chord* grace : m_graceNotes) {
     930            0 :         if (!grace->allElementsInvisible()) {
     931            0 :             return false;
     932              :         }
     933              :     }
     934              : 
     935           32 :     return true;
     936              : }
     937              : 
     938              : //---------------------------------------------------------
     939              : //   processSiblings
     940              : //---------------------------------------------------------
     941              : 
     942        40053 : void Chord::processSiblings(std::function<void(EngravingItem*)> func, bool includeTemporarySiblings) const
     943              : {
     944        40053 :     if (m_hook) {
     945          649 :         func(m_hook);
     946              :     }
     947        40053 :     if (m_stem) {
     948         4561 :         func(m_stem);
     949              :     }
     950        40053 :     if (m_stemSlash) {
     951           90 :         func(m_stemSlash);
     952              :     }
     953        40053 :     if (m_arpeggio) {
     954           71 :         func(m_arpeggio);
     955              :     }
     956        40053 :     if (m_tremoloTwoChord) {
     957           16 :         func(m_tremoloTwoChord);
     958              :     }
     959        40053 :     if (m_tremoloSingleChord) {
     960            8 :         func(m_tremoloSingleChord);
     961              :     }
     962        40053 :     if (includeTemporarySiblings) {
     963        40160 :         for (LedgerLine* ll : m_ledgerLines) {
     964          108 :             func(ll);
     965              :         }
     966              :     }
     967        40222 :     for (Articulation* a : m_articulations) {
     968          169 :         func(a);
     969              :     }
     970        57741 :     for (Note* note : m_notes) {
     971        17688 :         func(note);
     972              :     }
     973        40133 :     for (Chord* chord : m_graceNotes) {    // process grace notes last, needed for correct shape calculation
     974           80 :         func(chord);
     975              :     }
     976        40053 : }
     977              : 
     978              : //---------------------------------------------------------
     979              : //   setTrack
     980              : //---------------------------------------------------------
     981              : 
     982        36708 : void Chord::setTrack(track_idx_t val)
     983              : {
     984        36708 :     ChordRest::setTrack(val);
     985        52438 :     processSiblings([val](EngravingItem* e) { e->setTrack(val); }, true);
     986        36708 : }
     987              : 
     988       101857 : bool Chord::shouldCombineVoice() const
     989              : {
     990       101857 :     return combineVoice() == AutoOnOff::ON || (combineVoice() == AutoOnOff::AUTO && style().styleB(Sid::combineVoice));
     991              : }
     992              : 
     993         1376 : bool Chord::combineVoice(const Chord* chord1, const Chord* chord2)
     994              : {
     995         1376 :     return chord1->shouldCombineVoice() && chord2->shouldCombineVoice();
     996              : }
     997              : 
     998              : //---------------------------------------------------------
     999              : //   setScore
    1000              : //---------------------------------------------------------
    1001              : 
    1002         3344 : void Chord::setScore(Score* s)
    1003              : {
    1004         3344 :     ChordRest::setScore(s);
    1005        11052 :     processSiblings([s](EngravingItem* e) { e->setScore(s); }, true);
    1006         3344 : }
    1007              : 
    1008            0 : Fraction Chord::endTickIncludingTied() const
    1009              : {
    1010            0 :     const Chord* lastTied = this;
    1011            0 :     while (lastTied) {
    1012            0 :         const Chord* next = lastTied->nextTiedChord();
    1013            0 :         if (next) {
    1014            0 :             lastTied = next;
    1015              :         } else {
    1016            0 :             break;
    1017              :         }
    1018              :     }
    1019            0 :     return lastTied->endTick();
    1020              : }
    1021              : 
    1022          263 : Chord* Chord::prev() const
    1023              : {
    1024          263 :     ChordRest* prev = Navigation::prevChordRest(const_cast<Chord*>(this));
    1025          263 :     if (prev && prev->isChord()) {
    1026          257 :         return toChord(prev);
    1027              :     }
    1028            6 :     return nullptr;
    1029              : }
    1030              : 
    1031          338 : Chord* Chord::next() const
    1032              : {
    1033          338 :     ChordRest* next = Navigation::nextChordRest(const_cast<Chord*>(this));
    1034          338 :     if (next && next->isChord()) {
    1035          219 :         return toChord(next);
    1036              :     }
    1037          119 :     return nullptr;
    1038              : }
    1039              : 
    1040         7839 : void Chord::resizeLedgerLinesTo(size_t newSize)
    1041              : {
    1042         7839 :     int ledgerLineCountDiff = static_cast<int>(newSize - m_ledgerLines.size());
    1043         7839 :     if (ledgerLineCountDiff > 0) {
    1044       207911 :         for (int i = 0; i < ledgerLineCountDiff; ++i) {
    1045       202101 :             m_ledgerLines.push_back(new LedgerLine(this));
    1046              :         }
    1047              :     } else {
    1048        22039 :         for (int i = 0; i < std::abs(ledgerLineCountDiff); ++i) {
    1049        20010 :             delete m_ledgerLines.back();
    1050        20010 :             m_ledgerLines.pop_back();
    1051              :         }
    1052              :     }
    1053              : 
    1054         7839 :     assert(m_ledgerLines.size() == newSize);
    1055         7839 : }
    1056              : 
    1057        30226 : void Chord::setBeamExtension(double extension)
    1058              : {
    1059        30226 :     if (m_stem) {
    1060        30226 :         double baseLength = m_stem->absoluteFromSpatium(m_stem->baseLength());
    1061        30226 :         m_stem->setBaseLength(std::max(Spatium::fromAbsolute(baseLength + extension, spatium()), 0.0_sp));
    1062        30226 :         m_defaultStemLength = std::max(m_defaultStemLength + extension, m_stem->absoluteFromSpatium(m_stem->baseLength()));
    1063              :     }
    1064        30226 : }
    1065              : 
    1066        84067 : bool Chord::shouldHaveStem() const
    1067              : {
    1068        84067 :     const Staff* staff = this->staff();
    1069        84067 :     const StaffType* staffType = staff ? staff->staffTypeForElement(this) : nullptr;
    1070              : 
    1071        84067 :     return !m_noStem
    1072        83335 :            && durationType().hasStem()
    1073       159119 :            && !(durationType().type() == DurationType::V_HALF && staffType && staffType->isTabStaff()
    1074          417 :                 && staffType->minimStyle() == TablatureMinimStyle::NONE)
    1075        74248 :            && !(measure() && measure()->stemless(staffIdx()))
    1076       251469 :            && !(staffType && staffType->isTabStaff() && staffType->stemless());
    1077              : }
    1078              : 
    1079        34216 : bool Chord::shouldHaveHook() const
    1080              : {
    1081        34216 :     return shouldHaveStem()
    1082        63824 :            && durationType().hooks() > 0
    1083         2360 :            && !beam()
    1084        98040 :            && !tremoloTwoChord();
    1085              : }
    1086              : 
    1087        22727 : void Chord::createStem()
    1088              : {
    1089        22727 :     Stem* stem = Factory::createStem(this);
    1090        22727 :     stem->setGenerated(true);
    1091              :     //! score()->undoAddElement calls add(), which assigns this created stem to _stem
    1092        22727 :     score()->doUndoAddElement(stem);
    1093        22727 : }
    1094              : 
    1095         5203 : void Chord::removeStem()
    1096              : {
    1097         5203 :     if (m_stem) {
    1098          567 :         score()->undoRemoveElement(m_stem);
    1099              :     }
    1100         5203 :     if (m_hook) {
    1101            0 :         score()->undoRemoveElement(m_hook);
    1102              :     }
    1103         5203 :     if (m_stemSlash) {
    1104            0 :         score()->undoRemoveElement(m_stemSlash);
    1105              :     }
    1106         5203 : }
    1107              : 
    1108         1269 : void Chord::createHook()
    1109              : {
    1110         1269 :     Hook* hook = new Hook(this);
    1111         1269 :     hook->setGenerated(true);
    1112         1269 :     score()->doUndoAddElement(hook);
    1113         1269 : }
    1114              : 
    1115              : //---------------------------------------------------------
    1116              : //    underBeam: true, if grace note is placed under a beam.
    1117              : //---------------------------------------------------------
    1118              : 
    1119            0 : bool Chord::underBeam() const
    1120              : {
    1121            0 :     if (m_noteType == NoteType::NORMAL) {
    1122            0 :         return false;
    1123              :     }
    1124            0 :     const Chord* cr = toChord(ownershipParent());
    1125            0 :     Beam* beam = cr->beam();
    1126            0 :     if (!beam || !cr->beam()->up()) {
    1127            0 :         return false;
    1128              :     }
    1129            0 :     size_t s = beam->elements().size();
    1130            0 :     if (isGraceBefore()) {
    1131            0 :         if (beam->elements()[0] != cr) {
    1132            0 :             return true;
    1133              :         }
    1134              :     }
    1135            0 :     if (isGraceAfter()) {
    1136            0 :         if (beam->elements()[s - 1] != cr) {
    1137            0 :             return true;
    1138              :         }
    1139              :     }
    1140            0 :     return false;
    1141              : }
    1142              : 
    1143              : //---------------------------------------------------------
    1144              : //   cmdUpdateNotes
    1145              : //---------------------------------------------------------
    1146              : 
    1147        59965 : void Chord::cmdUpdateNotes(AccidentalState* as, staff_idx_t staffIdx)
    1148              : {
    1149              :     // TAB_STAFF is different, as each note has to be fretted
    1150              :     // in the context of the all of the chords of the whole segment
    1151              : 
    1152        59965 :     const Staff* st = staff();
    1153        59965 :     StaffGroup staffGroup = st->staffTypeForElement(this)->group();
    1154        59965 :     if (staffGroup == StaffGroup::TAB) {
    1155         1426 :         Fraction tick = this->tick();
    1156         1426 :         const StringData* stringData = originPart()->stringData(tick, st->idx());
    1157         1486 :         for (Chord* ch : graceNotes()) {
    1158           60 :             stringData->fretChords(ch);
    1159              :         }
    1160         1426 :         stringData->fretChords(this);
    1161         1426 :         return;
    1162              :     } else {
    1163              :         // if not tablature, use instrument->useDrumset to set staffGroup (to allow pitched to unpitched in same staff)
    1164        58539 :         staffGroup = originPart()->instrument(this->tick())->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
    1165              :     }
    1166              : 
    1167              :     // PITCHED_ and PERCUSSION_STAFF can go note by note
    1168              : 
    1169        58539 :     if (staffGroup == StaffGroup::STANDARD) {
    1170        57423 :         const std::vector<Chord*> gnb(graceNotesBefore());
    1171        58190 :         for (Chord* ch : gnb) {
    1172          767 :             if (ch->vStaffIdx() != staffIdx) {
    1173          133 :                 continue;
    1174              :             }
    1175          634 :             std::vector<Note*> notes(ch->notes());        // we need a copy!
    1176         1358 :             for (Note* note : notes) {
    1177          724 :                 note->updateAccidental(as);
    1178              :             }
    1179          634 :             ch->sortNotes();
    1180          634 :         }
    1181        57423 :         if (vStaffIdx() == staffIdx) {
    1182        46212 :             std::vector<Note*> lnotes(notes());      // we need a copy!
    1183       101085 :             for (Note* note : lnotes) {
    1184        54873 :                 if (note->tieBackNonPartial() && note->tpc() == note->tieBack()->startNote()->tpc()) {
    1185              :                     // same pitch
    1186         2119 :                     if (note->accidental() && note->accidental()->role() == AccidentalRole::AUTO) {
    1187              :                         // not courtesy
    1188              :                         // TODO: remove accidental only if note is not
    1189              :                         // on new system
    1190           30 :                         score()->undoRemoveElement(note->accidental());
    1191              :                     }
    1192              :                 }
    1193        54873 :                 note->updateAccidental(as);
    1194              :             }
    1195        47860 :             for (Articulation* art : m_articulations) {
    1196         1648 :                 if (!art->isOrnament()) {
    1197         1340 :                     continue;
    1198              :                 }
    1199          308 :                 Ornament* ornament = toOrnament(art);
    1200          308 :                 ornament->computeNotesAboveAndBelow(as);
    1201              :             }
    1202        47993 :             for (Spanner* spanner : startingSpanners()) {
    1203         1781 :                 if (spanner->isTrill()) {
    1204          113 :                     Ornament* ornament = toTrill(spanner)->ornament();
    1205          113 :                     if (ornament) {
    1206          113 :                         ornament->setOwnershipParent(this);
    1207          113 :                         ornament->computeNotesAboveAndBelow(as);
    1208              :                     }
    1209              :                 }
    1210              :             }
    1211        46212 :             sortNotes();
    1212        46212 :         }
    1213        57423 :         const std::vector<Chord*> gna(graceNotesAfter());
    1214        57673 :         for (Chord* ch : gna) {
    1215          250 :             if (ch->vStaffIdx() != staffIdx) {
    1216           23 :                 continue;
    1217              :             }
    1218          227 :             std::vector<Note*> notes(ch->notes());        // we need a copy!
    1219          476 :             for (Note* note : notes) {
    1220          249 :                 note->updateAccidental(as);
    1221              :             }
    1222          227 :             ch->sortNotes();
    1223          227 :         }
    1224        58539 :     } else if (staffGroup == StaffGroup::PERCUSSION) {
    1225         1116 :         const Instrument* instrument = originPart()->instrument(this->tick());
    1226         1116 :         const Drumset* drumset = instrument->drumset();
    1227         1116 :         if (!drumset) {
    1228            0 :             LOGW("no drumset");
    1229              :         }
    1230         1116 :         updatePercussionNotes(this, drumset);
    1231         1116 :         sortNotes();
    1232              :     }
    1233              : }
    1234              : 
    1235              : //---------------------------------------------------------
    1236              : //   pagePos
    1237              : //---------------------------------------------------------
    1238              : 
    1239       261401 : PointF Chord::pagePos() const
    1240              : {
    1241       261401 :     if (!isGrace()) {
    1242       255096 :         return EngravingItem::pagePos();
    1243              :     }
    1244              : 
    1245         6305 :     PointF p(pos());
    1246         6305 :     if (!ownershipParent()) {
    1247            0 :         return p;
    1248              :     }
    1249         6305 :     p.rx() = pageX();
    1250              : 
    1251         6305 :     const Chord* pc = toChord(ownershipParent());
    1252         6305 :     System* system = pc->segment()->system();
    1253         6305 :     if (!system) {
    1254            3 :         return p;
    1255              :     }
    1256         6302 :     p.ry() += system->staffYpage(vStaffIdx()) + staffOffsetY();
    1257         6302 :     return p;
    1258              : }
    1259              : 
    1260              : //---------------------------------------------------------
    1261              : //   scanElements
    1262              : //---------------------------------------------------------
    1263              : 
    1264        14250 : void Chord::scanElements(std::function<void(EngravingItem*)> func)
    1265              : {
    1266        14554 :     for (Articulation* a : m_articulations) {
    1267          304 :         a->scanElements(func);
    1268              :     }
    1269        14250 :     if (m_hook) {
    1270         1039 :         func(m_hook);
    1271              :     }
    1272        14250 :     if (m_stem) {
    1273        13610 :         func(m_stem);
    1274              :     }
    1275        14250 :     if (m_stemSlash) {
    1276           32 :         func(m_stemSlash);
    1277              :     }
    1278        14250 :     if (m_arpeggio) {
    1279           96 :         func(m_arpeggio);
    1280              :     }
    1281        14250 :     if (m_tremoloTwoChord && (tremoloChordType() != TremoloChordType::TremoloSecondChord)) {
    1282            4 :         func(m_tremoloTwoChord);
    1283              :     }
    1284        14250 :     if (m_tremoloSingleChord) {
    1285           27 :         func(m_tremoloSingleChord);
    1286              :     }
    1287        14250 :     const Staff* st = staff();
    1288        14250 :     if ((st && st->showLedgerLines(tick())) || !st) {       // also for palette
    1289        18863 :         for (LedgerLine* ll : m_ledgerLines) {
    1290         4613 :             func(ll);
    1291              :         }
    1292              :     }
    1293        32590 :     for (Note* note : m_notes) {
    1294        18340 :         note->scanElements(func);
    1295              :     }
    1296        14348 :     for (Chord* chord : m_graceNotes) {
    1297           98 :         chord->scanElements(func);
    1298              :     }
    1299        14302 :     for (EngravingItem* e : el()) {
    1300           52 :         e->scanElements(func);
    1301              :     }
    1302              : 
    1303        14261 :     for (auto& p : m_noteParens) {
    1304           11 :         p->leftParen()->scanElements(func);
    1305           11 :         p->rightParen()->scanElements(func);
    1306              :     }
    1307        14250 :     ChordRest::scanElements(func);
    1308        14250 : }
    1309              : 
    1310          463 : NoteParenthesisInfo* Chord::findNoteParenthesisInfo(const Parenthesis* paren)
    1311              : {
    1312          485 :     for (NoteParenthesisInfo* infoPtr : m_noteParens) {
    1313          485 :         if (paren == infoPtr->leftParen() || paren == infoPtr->rightParen()) {
    1314          463 :             return infoPtr;
    1315              :         }
    1316              :     }
    1317              : 
    1318            0 :     return nullptr;
    1319              : }
    1320              : 
    1321        72261 : const NoteParenthesisInfo* Chord::findNoteParenthesisInfo(const Note* note) const
    1322              : {
    1323        72320 :     for (const NoteParenthesisInfo* infoPtr : m_noteParens) {
    1324          892 :         for (const Note* parenNote : infoPtr->notes()) {
    1325          833 :             if (parenNote == note) {
    1326          482 :                 return infoPtr;
    1327              :             }
    1328              :         }
    1329              :     }
    1330              : 
    1331        71779 :     DO_ASSERT(u"Parentheses are not in chord");
    1332        71779 :     return nullptr;
    1333              : }
    1334              : 
    1335          206 : void Chord::addNoteParenthesisInfo(NoteParenthesisInfo* noteParenInfo)
    1336              : {
    1337          206 :     m_noteParens.push_back(noteParenInfo);
    1338          206 : }
    1339              : 
    1340           13 : void Chord::removeNoteParenthesisInfo(const NoteParenthesisInfo* noteParenInfo)
    1341              : {
    1342           13 :     if (m_noteParens.empty()) {
    1343            0 :         return;
    1344              :     }
    1345              : 
    1346           13 :     if (!noteParenInfo) {
    1347            0 :         return;
    1348              :     }
    1349              : 
    1350           13 :     auto it = std::find_if(m_noteParens.begin(), m_noteParens.end(), [noteParenInfo](const NoteParenthesisInfo* ptr) {
    1351           16 :         return ptr == noteParenInfo;
    1352              :     });
    1353              : 
    1354           13 :     if (it != m_noteParens.end()) {
    1355           13 :         m_noteParens.erase(it);
    1356              :     }
    1357              : }
    1358              : 
    1359            9 : void Chord::addNoteToParenthesisInfo(Note* note, const Parenthesis* paren)
    1360              : {
    1361            9 :     NoteParenthesisInfo* noteParenInfo = findNoteParenthesisInfo(paren);
    1362              : 
    1363            9 :     if (!noteParenInfo) {
    1364            0 :         return;
    1365              :     }
    1366              : 
    1367            9 :     noteParenInfo->insertNote(note);
    1368              : }
    1369              : 
    1370           12 : void Chord::removeNoteFromParenthesisInfo(Note* note, const Parenthesis* paren)
    1371              : {
    1372           12 :     NoteParenthesisInfo* noteParenInfo = findNoteParenthesisInfo(paren);
    1373              : 
    1374           12 :     if (!noteParenInfo) {
    1375            0 :         return;
    1376              :     }
    1377              : 
    1378           12 :     noteParenInfo->removeNote(note);
    1379              : }
    1380              : 
    1381              : //---------------------------------------------------------
    1382              : //   isChordPlayable
    1383              : //   @note Now every related to chord element has it's own "PLAY" property,
    1384              : //         However, there is no way to control these properties outside the scope of the chord since the new Properties panel.
    1385              : //         So we'll use a chord as a proxy entity for "PLAY" property handling
    1386              : //---------------------------------------------------------
    1387              : 
    1388           79 : bool Chord::isChordPlayable() const
    1389              : {
    1390           79 :     if (!m_notes.empty()) {
    1391           79 :         if (m_notes.front()->isPreBendOrDiveStart()) {
    1392           10 :             return false;
    1393              :         }
    1394              : 
    1395           69 :         return m_notes.front()->getProperty(Pid::PLAY).toBool();
    1396            0 :     } else if (tremoloTwoChord()) {
    1397            0 :         return tremoloTwoChord()->getProperty(Pid::PLAY).toBool();
    1398            0 :     } else if (tremoloSingleChord()) {
    1399            0 :         return tremoloSingleChord()->getProperty(Pid::PLAY).toBool();
    1400            0 :     } else if (m_arpeggio) {
    1401            0 :         return m_arpeggio->getProperty(Pid::PLAY).toBool();
    1402              :     }
    1403              : 
    1404            0 :     return false;
    1405              : }
    1406              : 
    1407              : //---------------------------------------------------------
    1408              : //   setIsChordPlayable
    1409              : //---------------------------------------------------------
    1410              : 
    1411            0 : void Chord::setIsChordPlayable(const bool isPlayable)
    1412              : {
    1413            0 :     for (Note* note : m_notes) {
    1414            0 :         note->undoChangeProperty(Pid::PLAY, isPlayable);
    1415              :     }
    1416              : 
    1417            0 :     if (m_arpeggio) {
    1418            0 :         m_arpeggio->undoChangeProperty(Pid::PLAY, isPlayable);
    1419              :     }
    1420              : 
    1421            0 :     if (tremoloTwoChord()) {
    1422            0 :         tremoloTwoChord()->undoChangeProperty(Pid::PLAY, isPlayable);
    1423              :     }
    1424              : 
    1425            0 :     if (tremoloSingleChord()) {
    1426            0 :         tremoloSingleChord()->undoChangeProperty(Pid::PLAY, isPlayable);
    1427              :     }
    1428              : 
    1429            0 :     triggerLayout();
    1430            0 : }
    1431              : 
    1432              : //---------------------------------------------------------
    1433              : //   findNote
    1434              : //---------------------------------------------------------
    1435              : 
    1436          827 : Note* Chord::findNote(int pitch, int skip) const
    1437              : {
    1438          827 :     size_t ns = m_notes.size();
    1439          934 :     for (size_t i = 0; i < ns; ++i) {
    1440          898 :         Note* n = m_notes.at(i);
    1441          898 :         if (n->pitch() == pitch) {
    1442          791 :             if (skip == 0) {
    1443          791 :                 return n;
    1444              :             } else {
    1445            0 :                 --skip;
    1446              :             }
    1447              :         }
    1448              :     }
    1449           36 :     return 0;
    1450              : }
    1451              : 
    1452          311 : void Chord::undoChangeSpanArpeggio(Arpeggio* a)
    1453              : {
    1454          311 :     if (m_spanArpeggio == a) {
    1455          230 :         return;
    1456              :     }
    1457              : 
    1458              :     // TODO: change arpeggio for links
    1459           81 :     score()->undo(new ChangeSpanArpeggio(this, a));
    1460              : }
    1461              : 
    1462        14132 : ChordLine* Chord::chordLine() const
    1463              : {
    1464        14132 :     for (EngravingItem* item : el()) {
    1465            4 :         if (item && item->isChordLine()) {
    1466            4 :             return toChordLine(item);
    1467              :         }
    1468              :     }
    1469              : 
    1470        14128 :     return nullptr;
    1471              : }
    1472              : 
    1473              : //---------------------------------------------------------
    1474              : //   drop
    1475              : //---------------------------------------------------------
    1476              : 
    1477           24 : EngravingItem* Chord::drop(Transaction& tx, EditData& data)
    1478              : {
    1479           24 :     EngravingItem* e = data.dropElement;
    1480           24 :     switch (e->type()) {
    1481            0 :     case ElementType::ARTICULATION:
    1482              :     case ElementType::ORNAMENT:
    1483              :     case ElementType::TAPPING:
    1484              :     {
    1485            0 :         Articulation* atr = toArticulation(e);
    1486            0 :         Articulation* oa = hasArticulation(atr);
    1487            0 :         if (oa) {
    1488            0 :             delete atr;
    1489            0 :             atr = 0;
    1490              :             // if attribute is already there, remove
    1491              :             // score()->cmdRemove(oa); // unexpected behaviour?
    1492            0 :             score()->select(oa, SelectType::SINGLE, 0);
    1493              :         } else {
    1494              :             // intuit anchor for this accidental based on other accidentals in the chord
    1495            0 :             int aboveBelow = 0;
    1496            0 :             bool mixed = false;
    1497            0 :             for (Articulation* a : m_articulations) {
    1498            0 :                 PropertyFlags pf = a->propertyFlags(Pid::ARTICULATION_ANCHOR);
    1499            0 :                 if (pf == PropertyFlags::STYLED) {
    1500            0 :                     continue;
    1501              :                 }
    1502            0 :                 if (a->anchor() == ArticulationAnchor::TOP) {
    1503            0 :                     if (aboveBelow < 0) {
    1504            0 :                         mixed = true;
    1505            0 :                         break;
    1506              :                     }
    1507            0 :                     ++aboveBelow;
    1508            0 :                 } else if (a->anchor() == ArticulationAnchor::BOTTOM) {
    1509            0 :                     if (aboveBelow > 0) {
    1510            0 :                         mixed = true;
    1511            0 :                         break;
    1512              :                     }
    1513            0 :                     --aboveBelow;
    1514              :                 }
    1515              :             }
    1516            0 :             if (!mixed && aboveBelow != 0) {
    1517            0 :                 if (aboveBelow > 0) {
    1518            0 :                     atr->setAnchor(ArticulationAnchor::TOP);
    1519              :                 } else {
    1520            0 :                     atr->setAnchor(ArticulationAnchor::BOTTOM);
    1521              :                 }
    1522            0 :                 atr->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
    1523              :             }
    1524            0 :             atr->setOwnershipParent(this);
    1525            0 :             atr->setTrack(track());
    1526              : 
    1527              :             // Immediately add if the chord has no existing articulations, toggle otherwise...
    1528            0 :             if (m_articulations.empty()) {
    1529            0 :                 score()->undoAddElement(atr);
    1530              :             } else {
    1531            0 :                 EditChord::toggleArticulation(score(), this, atr);
    1532              :             }
    1533              :         }
    1534            0 :         return atr;
    1535              :     }
    1536              : 
    1537            3 :     case ElementType::CHORDLINE:
    1538            3 :         e->setOwnershipParent(this);
    1539            3 :         e->setTrack(track());
    1540            3 :         score()->undoAddElement(e);
    1541            3 :         break;
    1542              : 
    1543            0 :     case ElementType::TREMOLO_SINGLECHORD:
    1544            0 :         if (tremoloSingleChord()) {
    1545            0 :             bool sameType = (e->subtype() == tremoloSingleChord()->subtype());
    1546            0 :             score()->undoRemoveElement(tremoloSingleChord());
    1547            0 :             if (sameType) {
    1548            0 :                 delete e;
    1549            0 :                 return nullptr;
    1550              :             }
    1551              :         }
    1552            0 :         e->setOwnershipParent(this);
    1553            0 :         e->setTrack(track());
    1554            0 :         score()->undoAddElement(e);
    1555            0 :         break;
    1556              : 
    1557            0 :     case ElementType::TREMOLO_TWOCHORD:
    1558              :     {
    1559            0 :         TremoloTwoChord* t = item_cast<TremoloTwoChord*>(e);
    1560            0 :         Segment* s = segment()->next();
    1561            0 :         while (s) {
    1562            0 :             if (s->element(track()) && s->element(track())->isChord()) {
    1563            0 :                 break;
    1564              :             }
    1565            0 :             s = s->next();
    1566              :         }
    1567            0 :         if (s == 0) {
    1568            0 :             LOGD("no segment for second note of tremolo found");
    1569            0 :             delete e;
    1570            0 :             return 0;
    1571              :         }
    1572            0 :         Chord* ch2 = toChord(s->element(track()));
    1573            0 :         if (ch2->ticks() != ticks()) {
    1574            0 :             LOGD("no matching chord for second note of tremolo found");
    1575            0 :             delete e;
    1576            0 :             return 0;
    1577              :         }
    1578            0 :         t->setChords(this, ch2);
    1579              :     }
    1580            0 :         if (tremoloTwoChord()) {
    1581            0 :             bool sameType = (e->subtype() == tremoloTwoChord()->subtype());
    1582            0 :             score()->undoRemoveElement(tremoloTwoChord());
    1583            0 :             if (sameType) {
    1584            0 :                 delete e;
    1585            0 :                 return 0;
    1586              :             }
    1587              :         }
    1588            0 :         e->setOwnershipParent(this);
    1589            0 :         e->setTrack(track());
    1590            0 :         score()->undoAddElement(e);
    1591            0 :         break;
    1592              : 
    1593            0 :     case ElementType::ARPEGGIO:
    1594              :     case ElementType::CHORD_BRACKET:
    1595              :     {
    1596            0 :         Arpeggio* a = toArpeggio(e);
    1597            0 :         if (arpeggio() && a->isArpeggio()) {
    1598            0 :             score()->undoRemoveElement(arpeggio());
    1599              :         }
    1600            0 :         a->setTrack(track());
    1601            0 :         a->setOwnershipParent(this);
    1602            0 :         score()->undoAddElement(a);
    1603              :     }
    1604            0 :         return e;
    1605              : 
    1606           21 :     default:
    1607           21 :         return ChordRest::drop(tx, data);
    1608              :     }
    1609            3 :     return 0;
    1610              : }
    1611              : 
    1612            0 : void Chord::setColor(const Color& color)
    1613              : {
    1614            0 :     ChordRest::setColor(color);
    1615              : 
    1616            0 :     for (Note* note : m_notes) {
    1617            0 :         note->undoChangeProperty(Pid::COLOR, PropertyValue::fromValue(color));
    1618              :     }
    1619            0 : }
    1620              : 
    1621              : //---------------------------------------------------------
    1622              : //   setStemDirection
    1623              : //---------------------------------------------------------
    1624              : 
    1625         6260 : void Chord::setStemDirection(DirectionV d)
    1626              : {
    1627         6260 :     m_stemDirection = d;
    1628         6260 : }
    1629              : 
    1630              : //---------------------------------------------------------
    1631              : //   localSpatiumChanged
    1632              : //---------------------------------------------------------
    1633              : 
    1634            0 : void Chord::localSpatiumChanged(double oldValue, double newValue)
    1635              : {
    1636            0 :     ChordRest::localSpatiumChanged(oldValue, newValue);
    1637            0 :     for (EngravingItem* e : graceNotes()) {
    1638            0 :         e->localSpatiumChanged(oldValue, newValue);
    1639              :     }
    1640            0 :     if (m_hook) {
    1641            0 :         m_hook->localSpatiumChanged(oldValue, newValue);
    1642              :     }
    1643            0 :     if (m_stem) {
    1644            0 :         m_stem->localSpatiumChanged(oldValue, newValue);
    1645              :     }
    1646            0 :     if (m_stemSlash) {
    1647            0 :         m_stemSlash->localSpatiumChanged(oldValue, newValue);
    1648              :     }
    1649            0 :     if (m_arpeggio) {
    1650            0 :         m_arpeggio->localSpatiumChanged(oldValue, newValue);
    1651              :     }
    1652              : 
    1653            0 :     if (m_tremoloSingleChord) {
    1654            0 :         m_tremoloSingleChord->localSpatiumChanged(oldValue, newValue);
    1655            0 :     } else if (m_tremoloTwoChord && (tremoloChordType() != TremoloChordType::TremoloSecondChord)) {
    1656            0 :         m_tremoloTwoChord->localSpatiumChanged(oldValue, newValue);
    1657              :     }
    1658              : 
    1659            0 :     for (EngravingItem* e : articulations()) {
    1660            0 :         e->localSpatiumChanged(oldValue, newValue);
    1661              :     }
    1662            0 :     for (Note* note : notes()) {
    1663            0 :         note->localSpatiumChanged(oldValue, newValue);
    1664              :     }
    1665            0 : }
    1666              : 
    1667              : //---------------------------------------------------------
    1668              : //   getProperty
    1669              : //---------------------------------------------------------
    1670              : 
    1671       302749 : PropertyValue Chord::getProperty(Pid propertyId) const
    1672              : {
    1673       302749 :     switch (propertyId) {
    1674          136 :     case Pid::NO_STEM:         return noStem();
    1675            3 :     case Pid::SHOW_STEM_SLASH: return showStemSlash();
    1676        19084 :     case Pid::STEM_DIRECTION:  return PropertyValue::fromValue<DirectionV>(stemDirection());
    1677            0 :     case Pid::PLAY: return isChordPlayable();
    1678        18753 :     case Pid::COMBINE_VOICE: return PropertyValue::fromValue<AutoOnOff>(combineVoice());
    1679        18756 :     case Pid::VISIBLE: return true; // Chord cannot be set invisible, only its elements can
    1680       246017 :     default:
    1681       246017 :         return ChordRest::getProperty(propertyId);
    1682              :     }
    1683              : }
    1684              : 
    1685              : //---------------------------------------------------------
    1686              : //   propertyDefault
    1687              : //---------------------------------------------------------
    1688              : 
    1689       263616 : PropertyValue Chord::propertyDefault(Pid propertyId) const
    1690              : {
    1691       263616 :     switch (propertyId) {
    1692            0 :     case Pid::NO_STEM:         return false;
    1693        19415 :     case Pid::SHOW_STEM_SLASH: return noteType() == NoteType::ACCIACCATURA;
    1694        37506 :     case Pid::STEM_DIRECTION:  return PropertyValue::fromValue<DirectionV>(DirectionV::AUTO);
    1695            0 :     case Pid::PLAY: return true;
    1696        37506 :     case Pid::COMBINE_VOICE: return AutoOnOff::AUTO;
    1697       206695 :     default:
    1698       206695 :         return ChordRest::propertyDefault(propertyId);
    1699              :     }
    1700              : }
    1701              : 
    1702            0 : bool Chord::isUserModified() const
    1703              : {
    1704            0 :     if (showStemSlash() != propertyDefault(Pid::SHOW_STEM_SLASH).toBool()) {
    1705            0 :         return true;
    1706              :     }
    1707              : 
    1708            0 :     return EngravingItem::isUserModified();
    1709              : }
    1710              : 
    1711              : //---------------------------------------------------------
    1712              : //   setProperty
    1713              : //---------------------------------------------------------
    1714              : 
    1715         2184 : bool Chord::setProperty(Pid propertyId, const PropertyValue& v)
    1716              : {
    1717         2184 :     switch (propertyId) {
    1718           64 :     case Pid::NO_STEM:
    1719           64 :         setNoStem(v.toBool());
    1720           64 :         break;
    1721          663 :     case Pid::SHOW_STEM_SLASH:
    1722          663 :         requestShowStemSlash(v.toBool());
    1723          663 :         break;
    1724          675 :     case Pid::STEM_DIRECTION:
    1725          675 :         setStemDirection(v.value<DirectionV>());
    1726          675 :         break;
    1727            0 :     case Pid::PLAY:
    1728            0 :         setIsChordPlayable(v.toBool());
    1729            0 :         break;
    1730            0 :     case Pid::COMBINE_VOICE:
    1731            0 :         setCombineVoice(v.value<AutoOnOff>());
    1732            0 :         break;
    1733          782 :     default:
    1734          782 :         return ChordRest::setProperty(propertyId, v);
    1735              :     }
    1736         1402 :     triggerLayout();
    1737         1402 :     return true;
    1738              : }
    1739              : 
    1740              : //---------------------------------------------------------
    1741              : //   hasArticulation
    1742              : //---------------------------------------------------------
    1743              : 
    1744          313 : Articulation* Chord::hasArticulation(const Articulation* aa)
    1745              : {
    1746          462 :     for (Articulation* a : m_articulations) {
    1747          160 :         if (a->subtype() == aa->subtype()) {
    1748           11 :             return a;
    1749              :         }
    1750              :     }
    1751          302 :     return 0;
    1752              : }
    1753              : 
    1754         1163 : Tapping* Chord::tapping() const
    1755              : {
    1756         1163 :     std::vector<Tapping*> tappings;
    1757         1163 :     tappings.reserve(1);
    1758         1177 :     for (Articulation* a : m_articulations) {
    1759           14 :         if (a->isTapping()) {
    1760            0 :             tappings.push_back(toTapping(a));
    1761              :         }
    1762              :     }
    1763         1163 :     DO_ASSERT(tappings.size() <= 1);
    1764              : 
    1765         2326 :     return tappings.size() > 0 ? tappings.front() : nullptr;
    1766         1163 : }
    1767              : 
    1768           18 : void Chord::updateArticulations(const std::set<SymId>& newArticulationIds, ArticulationsUpdateMode updateMode)
    1769              : {
    1770           18 :     Articulation* staccato = nullptr;
    1771           18 :     Articulation* accent = nullptr;
    1772           18 :     Articulation* marcato = nullptr;
    1773           18 :     Articulation* tenuto = nullptr;
    1774           18 :     ArticulationAnchor overallAnchor = ArticulationAnchor::AUTO;
    1775           18 :     bool mixedDirections = false;
    1776           18 :     if (!m_articulations.empty()) {
    1777            0 :         std::vector<Articulation*> articsToRemove;
    1778              :         // split all articulations
    1779            0 :         for (Articulation* artic : m_articulations) {
    1780            0 :             if (!artic->isDouble()) {
    1781            0 :                 continue;
    1782              :             }
    1783            0 :             auto splitSyms = splitArticulations({ artic->symId() });
    1784            0 :             for (const SymId& id : splitSyms) {
    1785            0 :                 Articulation* newArticulation = Factory::createArticulation(this);
    1786            0 :                 newArticulation->setSymId(id);
    1787            0 :                 newArticulation->setAnchor(artic->anchor());
    1788            0 :                 newArticulation->setPropertyFlags(Pid::ARTICULATION_ANCHOR, artic->propertyFlags(Pid::ARTICULATION_ANCHOR));
    1789            0 :                 if (!hasArticulation(newArticulation)) {
    1790            0 :                     EditChord::toggleArticulation(score(), this, newArticulation);
    1791              :                 } else {
    1792            0 :                     delete newArticulation;
    1793              :                 }
    1794              :             }
    1795            0 :             articsToRemove.push_back(artic);
    1796            0 :         }
    1797            0 :         for (Articulation* artic : articsToRemove) {
    1798            0 :             score()->undoRemoveElement(artic);
    1799              :         }
    1800              :         // now we have guaranteed no more combined artics
    1801              :         // take an inventory of which articulations are already present
    1802            0 :         for (Articulation* artic : m_articulations) {
    1803            0 :             PropertyFlags pf = artic->propertyFlags(Pid::ARTICULATION_ANCHOR);
    1804            0 :             if (!mixedDirections && pf == PropertyFlags::UNSTYLED && artic->anchor() != ArticulationAnchor::AUTO) {
    1805            0 :                 if (overallAnchor != ArticulationAnchor::AUTO && artic->anchor() != overallAnchor) {
    1806            0 :                     mixedDirections = true;
    1807            0 :                     overallAnchor = ArticulationAnchor::AUTO;
    1808              :                 } else {
    1809            0 :                     overallAnchor = artic->anchor();
    1810              :                 }
    1811              :             }
    1812            0 :             if (artic->isStaccato()) {
    1813            0 :                 staccato = artic;
    1814            0 :             } else if (artic->isAccent()) {
    1815            0 :                 accent = artic;
    1816            0 :             } else if (artic->isMarcato()) {
    1817            0 :                 marcato = artic;
    1818            0 :             } else if (artic->isTenuto()) {
    1819            0 :                 tenuto = artic;
    1820              :             }
    1821              :         }
    1822            0 :     }
    1823           18 :     std::set<SymId> newArtics;
    1824              :     // get symbol id's for correct direction
    1825           18 :     for (const SymId& id : newArticulationIds) {
    1826            0 :         if (id == SymId::articAccentAbove || id == SymId::articAccentBelow) {
    1827            0 :             if (marcato && updateMode == ArticulationsUpdateMode::Insert) {
    1828              :                 // adding an accent, which replaces marcato
    1829            0 :                 score()->undoRemoveElement(marcato);
    1830              :             }
    1831            0 :         } else if (id == SymId::articMarcatoAbove || id == SymId::articMarcatoBelow) {
    1832            0 :             if (accent && updateMode == ArticulationsUpdateMode::Insert) {
    1833              :                 // adding a marcato, which replaces accent
    1834            0 :                 score()->undoRemoveElement(accent);
    1835              :             }
    1836              :         }
    1837            0 :         newArtics.insert(id);
    1838              :     }
    1839              : 
    1840              :     // newArtics now contains the articulations in the correct direction
    1841           18 :     if (updateMode == ArticulationsUpdateMode::Remove) {
    1842              :         // remove articulations from _articulations that are found in newArtics
    1843            0 :         for (const SymId& id : newArtics) {
    1844            0 :             switch (id) {
    1845            0 :             case SymId::articAccentAbove:
    1846              :             case SymId::articAccentBelow:
    1847            0 :                 score()->undoRemoveElement(accent);
    1848            0 :                 accent = nullptr;
    1849            0 :                 break;
    1850            0 :             case SymId::articMarcatoAbove:
    1851              :             case SymId::articMarcatoBelow:
    1852            0 :                 score()->undoRemoveElement(marcato);
    1853            0 :                 marcato = nullptr;
    1854            0 :                 break;
    1855            0 :             case SymId::articTenutoAbove:
    1856              :             case SymId::articTenutoBelow:
    1857            0 :                 score()->undoRemoveElement(tenuto);
    1858            0 :                 tenuto = nullptr;
    1859            0 :                 break;
    1860            0 :             case SymId::articStaccatoAbove:
    1861              :             case SymId::articStaccatoBelow:
    1862            0 :                 score()->undoRemoveElement(staccato);
    1863            0 :                 staccato = nullptr;
    1864            0 :                 break;
    1865            0 :             default:
    1866            0 :                 break;
    1867              :             }
    1868              :         }
    1869              :     } else {
    1870              :         // add articulations from newArtics that are not found in m_articulations
    1871           18 :         for (const SymId& id : newArtics) {
    1872            0 :             Articulation* newArticulation = Factory::createArticulation(this);
    1873            0 :             newArticulation->setSymId(id);
    1874            0 :             if (overallAnchor != ArticulationAnchor::AUTO) {
    1875            0 :                 newArticulation->setAnchor(overallAnchor);
    1876            0 :                 newArticulation->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
    1877              :             }
    1878            0 :             if (!hasArticulation(newArticulation)) {
    1879            0 :                 EditChord::toggleArticulation(score(), this, newArticulation);
    1880              :             } else {
    1881            0 :                 delete newArticulation;
    1882              :             }
    1883              :         }
    1884              :     }
    1885           18 : }
    1886              : 
    1887              : //---------------------------------------------------------
    1888              : //   reset
    1889              : //---------------------------------------------------------
    1890              : 
    1891            0 : void Chord::reset()
    1892              : {
    1893            0 :     undoChangeProperty(Pid::STEM_DIRECTION, DirectionV::AUTO);
    1894            0 :     ChordRest::reset();
    1895            0 : }
    1896              : 
    1897              : //---------------------------------------------------------
    1898              : //   slash
    1899              : //---------------------------------------------------------
    1900              : 
    1901         2223 : bool Chord::slash()
    1902              : {
    1903         2223 :     Note* n = upNote();
    1904         2223 :     return n->fixed();
    1905              : }
    1906              : 
    1907              : //---------------------------------------------------------
    1908              : //   setSlash
    1909              : //---------------------------------------------------------
    1910              : 
    1911           90 : void Chord::setSlash(bool flag, bool stemless)
    1912              : {
    1913           90 :     int line = 0;
    1914           90 :     NoteHeadGroup head = NoteHeadGroup::HEAD_SLASH;
    1915              : 
    1916           90 :     if (!flag) {
    1917              :         // restore to normal
    1918            0 :         undoChangeProperty(Pid::NO_STEM, false);
    1919            0 :         undoChangeProperty(Pid::SMALL, false);
    1920            0 :         undoChangeProperty(Pid::OFFSET, PointF());
    1921            0 :         for (Note* n : m_notes) {
    1922            0 :             n->undoChangeProperty(Pid::HEAD_GROUP, NoteHeadGroup::HEAD_NORMAL);
    1923            0 :             n->undoChangeProperty(Pid::FIXED, false);
    1924            0 :             n->undoChangeProperty(Pid::FIXED_LINE, 0);
    1925            0 :             n->undoChangeProperty(Pid::PLAY, true);
    1926            0 :             n->undoChangeProperty(Pid::VISIBLE, true);
    1927            0 :             for (NoteDot* dot : n->dots()) {
    1928            0 :                 dot->undoChangeProperty(Pid::VISIBLE, true);
    1929              :             }
    1930            0 :             if (staff()->isDrumStaff(tick())) {
    1931            0 :                 const Drumset* ds = originPart()->instrument(tick())->drumset();
    1932            0 :                 int pitch = n->pitch();
    1933            0 :                 if (ds && ds->isValid(pitch)) {
    1934            0 :                     undoChangeProperty(Pid::STEM_DIRECTION, ds->stemDirection(pitch));
    1935            0 :                     n->undoChangeProperty(Pid::HEAD_GROUP, ds->noteHead(pitch));
    1936              :                 }
    1937              :             }
    1938              :         }
    1939            0 :         return;
    1940              :     }
    1941              : 
    1942              :     // make stemless if asked
    1943           90 :     if (stemless) {
    1944           36 :         undoChangeProperty(Pid::NO_STEM, true);
    1945           36 :         undoChangeProperty(Pid::BEAM_MODE, BeamMode::NONE);
    1946              :     }
    1947              : 
    1948           90 :     const StaffType* staffType = this->staffType();
    1949              : 
    1950              :     // voice-dependent attributes - line, size, offset, head
    1951           90 :     if (track() % VOICES < 2) {
    1952              :         // use middle line
    1953           64 :         line = staffType->middleLine();
    1954           64 :         undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::DOWN));
    1955              :     } else {
    1956              :         // set small
    1957           26 :         undoChangeProperty(Pid::SMALL, true);
    1958              :         // set outside the staff
    1959           26 :         double y = 0.0;
    1960           26 :         if (track() % 2) {
    1961           12 :             line = staffType->bottomLine() + 1;
    1962           12 :             y    = 0.5 * spatium();
    1963           12 :             undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::DOWN));
    1964              :         } else {
    1965           14 :             line = -1;
    1966           14 :             if (!staffType->isDrumStaff()) {
    1967            9 :                 y = -0.5 * spatium();
    1968              :             }
    1969           14 :             undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::UP));
    1970              :         }
    1971              :         // for non-drum staves, add an additional offset
    1972              :         // for drum staves, no offset, but use normal head
    1973           26 :         if (!staffType->isDrumStaff()) {
    1974           15 :             mutldata()->moveY(y);
    1975              :         } else {
    1976           11 :             head = NoteHeadGroup::HEAD_NORMAL;
    1977              :         }
    1978              :     }
    1979              : 
    1980           90 :     size_t ns = m_notes.size();
    1981          180 :     for (size_t i = 0; i < ns; ++i) {
    1982           90 :         Note* n = m_notes[i];
    1983           90 :         n->undoChangeProperty(Pid::HEAD_GROUP, head);
    1984           90 :         n->undoChangeProperty(Pid::FIXED, true);
    1985           90 :         n->undoChangeProperty(Pid::FIXED_LINE, line);
    1986           90 :         n->undoChangeProperty(Pid::PLAY, false);
    1987              :         // hide all but first notehead
    1988           90 :         if (i) {
    1989            0 :             n->undoChangeProperty(Pid::VISIBLE, false);
    1990            0 :             for (NoteDot* dot : n->dots()) {
    1991            0 :                 dot->undoChangeProperty(Pid::VISIBLE, false);
    1992              :             }
    1993              :         }
    1994              :     }
    1995              : }
    1996              : 
    1997              : //---------------------------------------------------------
    1998              : //  updateEndsNoteAnchoredLine
    1999              : //    sets/resets the chord m_endsNoteAnchoredLine according any note anchored line
    2000              : //    end into this chord or no.
    2001              : //---------------------------------------------------------
    2002              : 
    2003            0 : void Chord::updateEndsNoteAnchoredLine()
    2004              : {
    2005            0 :     m_endsNoteAnchoredLine = false;         // assume no note anchored line ends here
    2006              :     // scan all chord notes for note anchored lines ending on this chord
    2007            0 :     for (Note* note : notes()) {
    2008            0 :         for (Spanner* sp : note->spannerBack()) {
    2009            0 :             if (sp->isGlissando() || (sp->isNoteLine() && toNoteLine(sp)->enforceMinLength())) {
    2010            0 :                 m_endsNoteAnchoredLine = true;
    2011            0 :                 return;
    2012              :             }
    2013              :         }
    2014              :     }
    2015              : }
    2016              : 
    2017              : //---------------------------------------------------------
    2018              : //   removeMarkings
    2019              : //    - this is normally called after cloning a chord to tie a note over the barline
    2020              : //    - there is no special undo handling; the assumption is that undo will simply remove the cloned chord
    2021              : //    - two note tremolos are converted into simple notes
    2022              : //    - single note tremolos are optionally retained
    2023              : //---------------------------------------------------------
    2024              : 
    2025          122 : void Chord::removeMarkings(bool keepTremolo)
    2026              : {
    2027          122 :     if (m_tremoloSingleChord && !keepTremolo) {
    2028            0 :         remove(m_tremoloSingleChord);
    2029              :     }
    2030              : 
    2031          122 :     if (m_tremoloTwoChord && !keepTremolo) {
    2032            0 :         remove(m_tremoloTwoChord);
    2033              :     }
    2034              : 
    2035          122 :     if (arpeggio()) {
    2036            0 :         remove(arpeggio());
    2037              :     }
    2038              : 
    2039          122 :     if (m_spanArpeggio) {
    2040            0 :         m_spanArpeggio = nullptr;
    2041              :     }
    2042              : 
    2043          122 :     muse::DeleteAll(graceNotes());
    2044          122 :     graceNotes().clear();
    2045          122 :     muse::DeleteAll(articulations());
    2046          122 :     articulations().clear();
    2047          246 :     for (Note* n : notes()) {
    2048          124 :         for (EngravingItem* e : n->el()) {
    2049            0 :             n->remove(e);
    2050              :         }
    2051              :     }
    2052          122 :     ChordRest::removeMarkings(keepTremolo);
    2053          122 : }
    2054              : 
    2055              : //---------------------------------------------------------
    2056              : //   intrinsicMag
    2057              : //   returns the INTRINSIC mag of the chord (i.e. NOT scaled
    2058              : //   by staff size)
    2059              : //---------------------------------------------------------
    2060              : 
    2061      5411939 : double Chord::intrinsicMag() const
    2062              : {
    2063      5411939 :     double m = 1.0;
    2064      5411939 :     if (isSmall()) {
    2065        42108 :         m *= style().styleD(Sid::smallNoteMag);
    2066              :     }
    2067      5411939 :     if (m_noteType != NoteType::NORMAL) {
    2068       160397 :         bool tabGraceSizeException = staffType()->isTabStaff() && isPreBendOrGraceBendStart()
    2069       160397 :                                      && !style().styleB(Sid::useCueSizeFretForGraceBends);
    2070       159400 :         if (!tabGraceSizeException) {
    2071       159109 :             m *= style().styleD(Sid::graceNoteMag);
    2072              :         }
    2073              :     }
    2074      5411939 :     return m;
    2075              : }
    2076              : 
    2077              : //---------------------------------------------------------
    2078              : //   mag
    2079              : //---------------------------------------------------------
    2080              : 
    2081      4480676 : double Chord::mag() const
    2082              : {
    2083      4480676 :     const Staff* st = staff();
    2084      4480676 :     return (st ? st->staffMag(this) : 1.0) * intrinsicMag();
    2085              : }
    2086              : 
    2087              : //---------------------------------------------------------
    2088              : //   segment
    2089              : //---------------------------------------------------------
    2090              : 
    2091       630877 : Segment* Chord::segment() const
    2092              : {
    2093       630877 :     EngravingObject* e = ownershipParent();
    2094       638564 :     for (; e && !e->isSegment(); e = e->ownershipParent()) {
    2095              :     }
    2096       630877 :     return toSegment(e);
    2097              : }
    2098              : 
    2099              : //---------------------------------------------------------
    2100              : //   measure
    2101              : //---------------------------------------------------------
    2102              : 
    2103      5512670 : Measure* Chord::measure() const
    2104              : {
    2105      5512670 :     EngravingObject* e = ownershipParent();
    2106     11126460 :     for (; e && !e->isMeasure(); e = e->ownershipParent()) {
    2107              :     }
    2108      5512670 :     return toMeasure(e);
    2109              : }
    2110              : 
    2111              : //---------------------------------------------------------
    2112              : //   graceNotesBefore
    2113              : //---------------------------------------------------------
    2114              : 
    2115       308575 : GraceNotesGroup& Chord::graceNotesBefore(bool filterUnplayable) const
    2116              : {
    2117       308575 :     m_graceNotesBefore.clear();
    2118       316789 :     for (Chord* c : m_graceNotes) {
    2119         8214 :         assert(c->noteType() != NoteType::NORMAL && c->noteType() != NoteType::INVALID);
    2120         8214 :         if (c->noteType() & (
    2121              :                 NoteType::ACCIACCATURA
    2122              :                 | NoteType::APPOGGIATURA
    2123              :                 | NoteType::GRACE4
    2124              :                 | NoteType::GRACE16
    2125              :                 | NoteType::GRACE32)) {
    2126         6117 :             if (filterUnplayable && !c->isChordPlayable()) {
    2127            9 :                 continue;
    2128              :             }
    2129              : 
    2130         6108 :             m_graceNotesBefore.push_back(c);
    2131              :         }
    2132              :     }
    2133       308575 :     return m_graceNotesBefore;
    2134              : }
    2135              : 
    2136              : //---------------------------------------------------------
    2137              : //   graceNotesAfter
    2138              : //---------------------------------------------------------
    2139              : 
    2140       307663 : GraceNotesGroup& Chord::graceNotesAfter(bool filterUnplayable) const
    2141              : {
    2142       307663 :     m_graceNotesAfter.clear();
    2143       315193 :     for (int i = static_cast<int>(m_graceNotes.size()) - 1; i >= 0; i--) {
    2144         7530 :         Chord* c = m_graceNotes[i];
    2145         7530 :         assert(c->noteType() != NoteType::NORMAL && c->noteType() != NoteType::INVALID);
    2146         7530 :         if (c->noteType() & (NoteType::GRACE8_AFTER | NoteType::GRACE16_AFTER | NoteType::GRACE32_AFTER)) {
    2147         1968 :             if (filterUnplayable && !c->isChordPlayable()) {
    2148            0 :                 continue;
    2149              :             }
    2150              : 
    2151         1968 :             m_graceNotesAfter.push_back(c);
    2152              :         }
    2153              :     }
    2154       307663 :     return m_graceNotesAfter;
    2155              : }
    2156              : 
    2157           22 : Chord* Chord::graceNoteAt(size_t idx) const
    2158              : {
    2159           22 :     if (idx > m_graceNotes.size()) {
    2160            0 :         return nullptr;
    2161              :     }
    2162              : 
    2163           22 :     return m_graceNotes.at(idx);
    2164              : }
    2165              : 
    2166              : //---------------------------------------------------------
    2167              : //   allGraceChordsOfMainChord
    2168              : //   returns a list containing all grace notes (chords) attached to the main chord and the main chord itself, in order
    2169              : //---------------------------------------------------------
    2170            0 : std::vector<Chord*> Chord::allGraceChordsOfMainChord()
    2171              : {
    2172            0 :     Chord* mainChord = isGrace() ? toChord(ownershipParent()) : this;
    2173            0 :     std::vector<Chord*> chords = { mainChord };
    2174            0 :     const GraceNotesGroup& gnBefore = mainChord->graceNotesBefore();
    2175            0 :     const GraceNotesGroup& gnAfter = mainChord->graceNotesAfter();
    2176            0 :     chords.insert(chords.begin(), gnBefore.begin(), gnBefore.end());
    2177            0 :     chords.insert(chords.end(), gnAfter.begin(), gnAfter.end());
    2178            0 :     return chords;
    2179            0 : }
    2180              : 
    2181              : //---------------------------------------------------------
    2182              : //   setShowStemSlashInAdvance
    2183              : //---------------------------------------------------------
    2184              : 
    2185           70 : void Chord::setShowStemSlashInAdvance()
    2186              : {
    2187           70 :     if (m_noteType == NoteType::NORMAL) {
    2188            0 :         return;
    2189              :     }
    2190           70 :     if (isGraceBefore()) {
    2191           69 :         GraceNotesGroup& graceBefore = toChord(ownershipParent())->graceNotesBefore();
    2192           69 :         Chord* grace = graceBefore.empty() ? nullptr : graceBefore.front();
    2193           69 :         if (grace && grace->beamMode() != BeamMode::NONE && grace->beamMode() != BeamMode::BEGIN) {
    2194            2 :             grace->requestShowStemSlash(showStemSlash());
    2195              :         }
    2196              :     }
    2197           70 :     if (isGraceAfter()) {
    2198            1 :         GraceNotesGroup& graceAfter = toChord(ownershipParent())->graceNotesAfter();
    2199            1 :         Chord* grace = graceAfter.empty() ? nullptr : graceAfter.back();
    2200            1 :         if (grace && grace->beamMode() != BeamMode::NONE) {
    2201            0 :             grace->requestShowStemSlash(showStemSlash());
    2202              :         }
    2203              :     }
    2204              : }
    2205              : 
    2206              : //---------------------------------------------------------
    2207              : //   requestShowStemSlash
    2208              : //---------------------------------------------------------
    2209              : 
    2210          665 : void Chord::requestShowStemSlash(bool show)
    2211              : {
    2212          665 :     if (m_noteType == NoteType::NORMAL) {
    2213            2 :         return;
    2214              :     }
    2215          663 :     if (beam()) {
    2216            0 :         for (ChordRest* chordRest : beam()->elements()) {
    2217            0 :             if (chordRest->isChord()) {
    2218            0 :                 Chord* chord = toChord(chordRest);
    2219            0 :                 chord->setShowStemSlash(show);
    2220              :             }
    2221              :         }
    2222              :     } else {
    2223          663 :         setShowStemSlash(show);
    2224              :     }
    2225              : }
    2226              : 
    2227              : //---------------------------------------------------------
    2228              : //   sortNotes
    2229              : //---------------------------------------------------------
    2230              : 
    2231        50325 : void Chord::sortNotes()
    2232              : {
    2233        50325 :     std::sort(notes().begin(), notes().end(), noteIsBefore);
    2234        50325 : }
    2235              : 
    2236              : //---------------------------------------------------------
    2237              : //   nextTiedChord
    2238              : //    Return next chord if all notes in this chord are tied to it.
    2239              : //    Set backwards=true to return the previous chord instead.
    2240              : //
    2241              : //    Note: the next chord might have extra notes that are not tied
    2242              : //    back to this one. Set sameSize=true to return 0 in this case.
    2243              : //---------------------------------------------------------
    2244              : 
    2245         1776 : Chord* Chord::nextTiedChord(bool backwards, bool sameSize) const
    2246              : {
    2247         1776 :     Segment* nextSeg = backwards ? segment()->prev1(SegmentType::ChordRest) : segment()->next1(SegmentType::ChordRest);
    2248         1776 :     if (!nextSeg) {
    2249           91 :         return 0;
    2250              :     }
    2251         1685 :     ChordRest* nextCR = nextSeg->nextChordRest(track(), backwards);
    2252         1685 :     if (!nextCR || !nextCR->isChord()) {
    2253          428 :         return 0;
    2254              :     }
    2255         1257 :     Chord* next = toChord(nextCR);
    2256         1257 :     if (sameSize && notes().size() != next->notes().size()) {
    2257            6 :         return 0;     // sizes don't match so some notes can't be tied
    2258              :     }
    2259         1251 :     if (tuplet() != next->tuplet()) {
    2260            2 :         return 0;     // next chord belongs to a different tuplet
    2261              :     }
    2262         2055 :     for (Note* n : m_notes) {
    2263         1260 :         Tie* tie = backwards ? n->tieBack() : n->tieFor();
    2264         1260 :         if (!tie) {
    2265          454 :             return 0;       // not tied
    2266              :         }
    2267          806 :         Note* nn = backwards ? tie->startNote() : tie->endNote();
    2268          806 :         if (!nn || nn->chord() != next) {
    2269            0 :             return 0;       // tied to note in wrong voice, or tied over rest
    2270              :         }
    2271              :     }
    2272          795 :     return next;   // all notes in this chord are tied to notes in next chord
    2273              : }
    2274              : 
    2275              : //---------------------------------------------------------
    2276              : //   setNoteType
    2277              : //---------------------------------------------------------
    2278              : 
    2279          662 : void Chord::setNoteType(NoteType t)
    2280              : {
    2281          662 :     m_noteType = t;
    2282          662 :     setProperty(Pid::SHOW_STEM_SLASH, propertyDefault(Pid::SHOW_STEM_SLASH));
    2283          662 : }
    2284              : 
    2285              : //---------------------------------------------------------
    2286              : //   toGraceAfter
    2287              : //---------------------------------------------------------
    2288              : 
    2289           13 : void Chord::toGraceAfter()
    2290              : {
    2291           13 :     switch (noteType()) {
    2292           13 :     case NoteType::APPOGGIATURA:  setNoteType(NoteType::GRACE8_AFTER);
    2293           13 :         break;
    2294            0 :     case NoteType::GRACE16:       setNoteType(NoteType::GRACE16_AFTER);
    2295            0 :         break;
    2296            0 :     case NoteType::GRACE32:       setNoteType(NoteType::GRACE32_AFTER);
    2297            0 :         break;
    2298            0 :     default: break;
    2299              :     }
    2300           13 : }
    2301              : 
    2302          997 : bool Chord::isPreBendOrGraceBendStart() const
    2303              : {
    2304          997 :     if (!isGrace()) {
    2305            0 :         return false;
    2306              :     }
    2307              : 
    2308         1703 :     for (const Note* note : m_notes) {
    2309          997 :         GuitarBend* gb = note->bendFor();
    2310          997 :         if (gb && (gb->bendType() == GuitarBendType::PRE_BEND || gb->bendType() == GuitarBendType::GRACE_NOTE_BEND
    2311            0 :                    || gb->bendType() == GuitarBendType::PRE_DIVE)) {
    2312          291 :             return true;
    2313              :         }
    2314              :     }
    2315              : 
    2316          706 :     return false;
    2317              : }
    2318              : 
    2319          413 : bool Chord::isGraceBendEnd() const
    2320              : {
    2321          413 :     if (isGrace() || m_graceNotes.empty()) {
    2322          400 :         return false;
    2323              :     }
    2324              : 
    2325           22 :     for (const Note* note : m_notes) {
    2326           13 :         GuitarBend* bendBack = note->bendBack();
    2327           13 :         if (bendBack && bendBack->bendType() == GuitarBendType::GRACE_NOTE_BEND) {
    2328            4 :             return true;
    2329              :         }
    2330              :     }
    2331              : 
    2332            9 :     return false;
    2333              : }
    2334              : 
    2335           18 : void Chord::setIsTrillCueNote(bool v)
    2336              : {
    2337           18 :     m_isTrillCueNote = v;
    2338           18 : }
    2339              : 
    2340              : //---------------------------------------------------------
    2341              : //   tremoloChordType
    2342              : //---------------------------------------------------------
    2343              : 
    2344         7869 : TremoloChordType Chord::tremoloChordType() const
    2345              : {
    2346         7869 :     if (m_tremoloTwoChord) {
    2347          260 :         if (m_tremoloTwoChord->chord1() == this) {
    2348          127 :             return TremoloChordType::TremoloFirstChord;
    2349          133 :         } else if (m_tremoloTwoChord->chord2() == this) {
    2350          133 :             return TremoloChordType::TremoloSecondChord;
    2351              :         } else {
    2352            0 :             ASSERT_X(String(u"Chord::tremoloChordType(): inconsistency"));
    2353              :         }
    2354         7609 :     } else if (m_tremoloSingleChord) {
    2355          134 :         return TremoloChordType::TremoloSingle;
    2356              :     }
    2357              : 
    2358         7475 :     return TremoloChordType::TremoloNone;
    2359              : }
    2360              : 
    2361              : //---------------------------------------------------------
    2362              : //   nextElement
    2363              : //---------------------------------------------------------
    2364              : 
    2365            0 : EngravingItem* Chord::nextElement()
    2366              : {
    2367            0 :     EngravingItem* e = score()->selection().element();
    2368            0 :     if (!e && !score()->selection().elements().empty()) {
    2369            0 :         e = score()->selection().elements().front();
    2370              :     }
    2371              : 
    2372            0 :     switch (e->type()) {
    2373            0 :     case ElementType::SYMBOL:
    2374              :     case ElementType::IMAGE:
    2375              :     case ElementType::FINGERING:
    2376              :     case ElementType::TEXT:
    2377              :     case ElementType::BEND: {
    2378            0 :         Note* n = toNote(e->ownershipParent());
    2379            0 :         if (n == m_notes.front()) {
    2380            0 :             if (m_arpeggio) {
    2381            0 :                 return m_arpeggio;
    2382            0 :             } else if (m_tremoloTwoChord) {
    2383            0 :                 return m_tremoloTwoChord;
    2384            0 :             } else if (m_tremoloSingleChord) {
    2385            0 :                 return m_tremoloSingleChord;
    2386              :             }
    2387            0 :             break;
    2388              :         }
    2389            0 :         for (auto& i : m_notes) {
    2390            0 :             if (i == n) {
    2391            0 :                 return *(&i - 1);
    2392              :             }
    2393              :         }
    2394            0 :         break;
    2395              :     }
    2396              : 
    2397            0 :     case ElementType::GUITAR_BEND_SEGMENT:
    2398              :     case ElementType::GLISSANDO_SEGMENT:
    2399              :     case ElementType::NOTELINE_SEGMENT:
    2400              :     case ElementType::LAISSEZ_VIB_SEGMENT:
    2401              :     case ElementType::PARTIAL_TIE_SEGMENT:
    2402              :     case ElementType::TIE_SEGMENT: {
    2403            0 :         SpannerSegment* s = toSpannerSegment(e);
    2404            0 :         Spanner* sp = s->spanner();
    2405            0 :         EngravingItem* elSt = sp->startElement();
    2406            0 :         assert(elSt->isNote());
    2407            0 :         Note* n = toNote(elSt);
    2408            0 :         assert(n != NULL);
    2409            0 :         if (n == m_notes.front()) {
    2410            0 :             if (m_arpeggio) {
    2411            0 :                 return m_arpeggio;
    2412            0 :             } else if (m_tremoloTwoChord) {
    2413            0 :                 return m_tremoloTwoChord;
    2414            0 :             } else if (m_tremoloSingleChord) {
    2415            0 :                 return m_tremoloSingleChord;
    2416              :             }
    2417            0 :             break;
    2418              :         }
    2419            0 :         for (auto& i : m_notes) {
    2420            0 :             if (i == n) {
    2421            0 :                 return *(&i - 1);
    2422              :             }
    2423              :         }
    2424            0 :         break;
    2425              :     }
    2426            0 :     case ElementType::ARPEGGIO:
    2427              :     case ElementType::CHORD_BRACKET:
    2428            0 :         if (m_tremoloTwoChord) {
    2429            0 :             return m_tremoloTwoChord;
    2430            0 :         } else if (m_tremoloSingleChord) {
    2431            0 :             return m_tremoloSingleChord;
    2432              :         }
    2433            0 :         break;
    2434              : 
    2435            0 :     case ElementType::ACCIDENTAL:
    2436            0 :         e = toAccidental(e)->note();
    2437              :     // fall through
    2438              : 
    2439            0 :     case ElementType::NOTE: {
    2440            0 :         if (e == m_notes.front()) {
    2441            0 :             if (m_arpeggio) {
    2442            0 :                 return m_arpeggio;
    2443            0 :             } else if (m_tremoloTwoChord) {
    2444            0 :                 return m_tremoloTwoChord;
    2445            0 :             } else if (m_tremoloSingleChord) {
    2446            0 :                 return m_tremoloSingleChord;
    2447              :             }
    2448            0 :             break;
    2449              :         }
    2450            0 :         for (auto& i : m_notes) {
    2451            0 :             if (i == e) {
    2452            0 :                 return *(&i - 1);
    2453              :             }
    2454              :         }
    2455              :     }
    2456            0 :     break;
    2457              : 
    2458            0 :     case ElementType::CHORD:
    2459            0 :         return m_notes.back();
    2460              : 
    2461            0 :     default:
    2462            0 :         break;
    2463              :     }
    2464              : 
    2465            0 :     return ChordRest::nextElement();
    2466              : }
    2467              : 
    2468              : //---------------------------------------------------------
    2469              : //   prevElement
    2470              : //---------------------------------------------------------
    2471              : 
    2472            0 : EngravingItem* Chord::prevElement()
    2473              : {
    2474            0 :     EngravingItem* e = score()->selection().element();
    2475            0 :     if (!e && !score()->selection().elements().empty()) {
    2476            0 :         e = score()->selection().elements().back();
    2477              :     }
    2478            0 :     switch (e->type()) {
    2479            0 :     case ElementType::NOTE: {
    2480            0 :         if (isGrace()) {
    2481            0 :             ChordRest* prev = Navigation::prevChordRest(this);
    2482            0 :             if (prev) {
    2483            0 :                 if (prev->isChord()) {
    2484            0 :                     return toChord(prev)->notes().back();
    2485              :                 }
    2486            0 :                 return prev;
    2487              :             }
    2488              :         }
    2489              : 
    2490            0 :         GraceNotesGroup& graceNotesBefore = this->graceNotesBefore();
    2491            0 :         if (!graceNotesBefore.empty()) {
    2492            0 :             if (Chord* graceNotesBeforeLastChord = graceNotesBefore.back()) {
    2493            0 :                 if (e == graceNotesBeforeLastChord->notes().back()) {
    2494            0 :                     break;
    2495              :                 }
    2496              : 
    2497            0 :                 Note* prevNote = graceNotesBeforeLastChord->notes().back();
    2498            0 :                 if (prevNote->isPreBendOrDiveStart() || prevNote->isGraceBendStart()) {
    2499            0 :                     return prevNote->bendFor()->frontSegment();
    2500              :                 }
    2501              : 
    2502            0 :                 ChordRest* prev = Navigation::prevChordRest(this);
    2503            0 :                 if (prev) {
    2504            0 :                     if (prev->isChord()) {
    2505            0 :                         return toChord(prev)->notes().back();
    2506              :                     }
    2507            0 :                     return prev;
    2508              :                 }
    2509              :             }
    2510              :         }
    2511              : 
    2512            0 :         if (e == m_notes.back()) {
    2513            0 :             break;
    2514              :         }
    2515            0 :         Note* prevNote = nullptr;
    2516            0 :         for (auto& i : m_notes) {
    2517            0 :             if (i == e) {
    2518            0 :                 prevNote = *(&i + 1);
    2519              :             }
    2520              :         }
    2521            0 :         EngravingItem* next = prevNote->lastElementBeforeSegment();
    2522            0 :         return next;
    2523              :     }
    2524              : 
    2525            0 :     case ElementType::CHORD:
    2526            0 :         return m_notes.front();
    2527              : 
    2528            0 :     case ElementType::TREMOLO_TWOCHORD:
    2529              :     case ElementType::TREMOLO_SINGLECHORD:
    2530            0 :         if (m_arpeggio) {
    2531            0 :             return m_arpeggio;
    2532              :         }
    2533              :     // fall through
    2534              :     case ElementType::ARPEGGIO:
    2535              :     case ElementType::CHORD_BRACKET:
    2536              :     {
    2537            0 :         Note* n = m_notes.front();
    2538            0 :         EngravingItem* elN = n->lastElementBeforeSegment();
    2539            0 :         assert(elN != NULL);
    2540            0 :         return elN;
    2541              :     }
    2542              : 
    2543            0 :     default:
    2544            0 :         break;
    2545              :     }
    2546            0 :     return ChordRest::prevElement();
    2547              : }
    2548              : 
    2549              : //---------------------------------------------------------
    2550              : //   lastElementBeforeSegment
    2551              : //---------------------------------------------------------
    2552              : 
    2553            0 : EngravingItem* Chord::lastElementBeforeSegment()
    2554              : {
    2555            0 :     if (m_tremoloSingleChord) {
    2556            0 :         return m_tremoloSingleChord;
    2557            0 :     } else if (m_tremoloTwoChord) {
    2558            0 :         return m_tremoloTwoChord;
    2559            0 :     } else if (m_arpeggio) {
    2560            0 :         return m_arpeggio;
    2561              :     } else {
    2562            0 :         Note* n = m_notes.front();
    2563            0 :         EngravingItem* elN = n->lastElementBeforeSegment();
    2564            0 :         assert(elN != NULL);
    2565            0 :         return elN;
    2566              :     }
    2567              : }
    2568              : 
    2569              : //---------------------------------------------------------
    2570              : //   nextSegmentElement
    2571              : //---------------------------------------------------------
    2572              : 
    2573            0 : EngravingItem* Chord::nextSegmentElement()
    2574              : {
    2575            0 :     for (track_idx_t v = track() + 1; staffIdx() == v / VOICES; ++v) {
    2576            0 :         EngravingItem* e = segment()->element(v);
    2577            0 :         if (e) {
    2578            0 :             if (e->isChord()) {
    2579            0 :                 return toChord(e)->notes().back();
    2580              :             }
    2581              : 
    2582            0 :             return e;
    2583              :         }
    2584              :     }
    2585              : 
    2586            0 :     return ChordRest::nextSegmentElement();
    2587              : }
    2588              : 
    2589              : //---------------------------------------------------------
    2590              : //   prevSegmentElement
    2591              : //---------------------------------------------------------
    2592              : 
    2593            0 : EngravingItem* Chord::prevSegmentElement()
    2594              : {
    2595            0 :     EngravingItem* el = score()->selection().element();
    2596            0 :     if (!el && !score()->selection().elements().empty()) {
    2597            0 :         el = score()->selection().elements().front();
    2598              :     }
    2599            0 :     EngravingItem* e = segment()->lastInPrevSegments(el->staffIdx());
    2600            0 :     if (e) {
    2601            0 :         if (e->isChord()) {
    2602            0 :             return toChord(e)->notes().front();
    2603              :         }
    2604            0 :         return e;
    2605              :     }
    2606              : 
    2607            0 :     return ChordRest::prevSegmentElement();
    2608              : }
    2609              : 
    2610              : //---------------------------------------------------------
    2611              : //   accessibleExtraInfo
    2612              : //---------------------------------------------------------
    2613              : 
    2614            0 : String Chord::accessibleExtraInfo() const
    2615              : {
    2616            0 :     String rez;
    2617              : 
    2618            0 :     for (const Chord* c : graceNotes()) {
    2619            0 :         if (!score()->selectionFilter().canSelect(c)) {
    2620            0 :             continue;
    2621              :         }
    2622            0 :         for (const Note* n : c->notes()) {
    2623            0 :             rez = String(u"%1 %2").arg(rez, n->screenReaderInfo());
    2624              :         }
    2625              :     }
    2626              : 
    2627            0 :     for (Articulation* a : articulations()) {
    2628            0 :         if (!score()->selectionFilter().canSelect(a)) {
    2629            0 :             continue;
    2630              :         }
    2631            0 :         rez = String(u"%1 %2").arg(rez, a->screenReaderInfo());
    2632              :     }
    2633              : 
    2634            0 :     if (arpeggio() && score()->selectionFilter().canSelect(arpeggio())) {
    2635            0 :         rez = String(u"%1 %2").arg(rez, arpeggio()->screenReaderInfo());
    2636              :     }
    2637              : 
    2638            0 :     if (tremoloTwoChord() && score()->selectionFilter().canSelect(tremoloTwoChord())) {
    2639            0 :         rez = String(u"%1 %2").arg(rez, tremoloTwoChord()->screenReaderInfo());
    2640              :     }
    2641              : 
    2642            0 :     if (tremoloSingleChord() && score()->selectionFilter().canSelect(tremoloSingleChord())) {
    2643            0 :         rez = String(u"%1 %2").arg(rez, tremoloSingleChord()->screenReaderInfo());
    2644              :     }
    2645              : 
    2646            0 :     for (EngravingItem* e : el()) {
    2647            0 :         if (!score()->selectionFilter().canSelect(e)) {
    2648            0 :             continue;
    2649              :         }
    2650            0 :         rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
    2651              :     }
    2652              : 
    2653            0 :     return String(u"%1 %2").arg(rez, ChordRest::accessibleExtraInfo());
    2654            0 : }
    2655              : 
    2656          202 : void Chord::undoChangeProperty(Pid id, const PropertyValue& newValue)
    2657              : {
    2658          202 :     undoChangeProperty(id, newValue, propertyFlags(id));
    2659          202 : }
    2660              : 
    2661              : //---------------------------------------------------------
    2662              : //   undoChangeProperty
    2663              : //---------------------------------------------------------
    2664              : 
    2665          316 : void Chord::undoChangeProperty(Pid id, const PropertyValue& newValue, PropertyFlags ps)
    2666              : {
    2667          316 :     if (id == Pid::VISIBLE) {
    2668            1 :         processSiblings([=](EngravingItem* element) {
    2669            2 :             element->undoChangeProperty(id, newValue, ps);
    2670            2 :         }, false);
    2671              :     }
    2672              : 
    2673          316 :     ChordRest::undoChangeProperty(id, newValue, ps);
    2674          316 : }
    2675              : 
    2676           24 : std::set<SymId> Chord::articulationSymbolIds() const
    2677              : {
    2678           24 :     std::set<SymId> result;
    2679           24 :     for (const Articulation* artic: m_articulations) {
    2680            0 :         result.insert(artic->symId());
    2681              :     }
    2682              : 
    2683           24 :     return result;
    2684            0 : }
    2685              : 
    2686              : //---------------------------------------------------------
    2687              : //   getNoteEventLists
    2688              : //    Get contents of all NoteEventLists for all notes in
    2689              : //    the chord.
    2690              : //---------------------------------------------------------
    2691              : 
    2692            0 : std::vector<NoteEventList> Chord::getNoteEventLists()
    2693              : {
    2694            0 :     std::vector<NoteEventList> ell;
    2695            0 :     if (notes().empty()) {
    2696            0 :         return ell;
    2697              :     }
    2698            0 :     ell.reserve(notes().size());
    2699            0 :     for (size_t i = 0; i < notes().size(); ++i) {
    2700            0 :         ell.push_back(NoteEventList(notes()[i]->playEvents()));
    2701              :     }
    2702            0 :     return ell;
    2703            0 : }
    2704              : 
    2705              : //---------------------------------------------------------
    2706              : //   setNoteEventLists
    2707              : //    Set contents of all NoteEventLists for all notes in
    2708              : //    the chord.
    2709              : //---------------------------------------------------------
    2710              : 
    2711          341 : void Chord::setNoteEventLists(std::vector<NoteEventList>& ell)
    2712              : {
    2713          341 :     if (notes().empty()) {
    2714            0 :         return;
    2715              :     }
    2716          341 :     IF_ASSERT_FAILED(ell.size() == notes().size()) {
    2717            0 :         return;
    2718              :     }
    2719          704 :     for (size_t i = 0; i < ell.size(); i++) {
    2720          363 :         notes()[i]->setPlayEvents(ell[i]);
    2721              :     }
    2722              : }
    2723              : 
    2724              : //---------------------------------------------------------
    2725              : //   styleChanged
    2726              : //---------------------------------------------------------
    2727          141 : void Chord::styleChanged()
    2728              : {
    2729          295 :     auto updateElementsStyle = [](EngravingItem* e) {
    2730          295 :         e->styleChanged();
    2731          295 :     };
    2732          141 :     scanElements(updateElementsStyle);
    2733          141 : }
    2734              : 
    2735        51681 : void Chord::computeKerningExceptions()
    2736              : {
    2737        51681 :     m_allowKerningAbove = true;
    2738        51681 :     m_allowKerningBelow = true;
    2739        53434 :     for (Articulation* art : m_articulations) {
    2740         1753 :         if (art->up()) {
    2741         1234 :             m_allowKerningAbove = false;
    2742              :         } else {
    2743          519 :             m_allowKerningBelow = false;
    2744              :         }
    2745              :     }
    2746        51681 :     if ((m_startEndSlurs.startUp || m_startEndSlurs.endUp) && !ldata()->up) {
    2747          565 :         m_allowKerningAbove = false;
    2748              :     }
    2749        51681 :     if ((m_startEndSlurs.startDown || m_startEndSlurs.endDown) && ldata()->up) {
    2750          727 :         m_allowKerningBelow = false;
    2751              :     }
    2752        51681 : }
    2753              : 
    2754       251149 : Ornament* Chord::findOrnament(bool forPlayback) const
    2755              : {
    2756       258216 :     for (Articulation* art : m_articulations) {
    2757         8617 :         if (art->isOrnament()) {
    2758         1550 :             return toOrnament(art);
    2759              :         }
    2760              :     }
    2761       259311 :     for (Spanner* spanner : m_startingSpanners) {
    2762        10123 :         if (spanner->isTrill()) {
    2763          411 :             return toTrill(spanner)->ornament();
    2764              :         }
    2765              :     }
    2766       249188 :     if (forPlayback) {
    2767              :         // TODO: cleanup.
    2768              :         // We shouldn't do this kind of special cases, and the DOM shouldn't know anything about playback.
    2769              :         // This should be in a different function that returns the ornament from the Trill ending on this chord. [MS]
    2770            2 :         for (Spanner* spanner : m_endingSpanners) {
    2771            2 :             if (spanner->isTrill()) {
    2772            2 :                 return toTrill(spanner)->ornament();
    2773              :             }
    2774              :         }
    2775              :     }
    2776       249186 :     return nullptr;
    2777              : }
    2778              : 
    2779              : //---------------------------------
    2780              : // firstGraceOrNote
    2781              : //---------------------------------
    2782          213 : Note* Chord::firstGraceOrNote()
    2783              : {
    2784          213 :     GraceNotesGroup& graceNotesBefore = this->graceNotesBefore();
    2785          213 :     if (!graceNotesBefore.empty()) {
    2786           31 :         if (Chord* graceNotesBeforeFirstChord = graceNotesBefore.front()) {
    2787           31 :             return graceNotesBeforeFirstChord->notes().front();
    2788              :         }
    2789              :     }
    2790              : 
    2791          182 :     return this->notes().back();
    2792              : }
    2793              : 
    2794              : //---------------------------------
    2795              : // GRACE NOTES
    2796              : //---------------------------------
    2797              : 
    2798        67806 : GraceNotesGroup::GraceNotesGroup(DummyParentOr<Chord> c)
    2799        67806 :     : EngravingItem(ElementType::GRACE_NOTES_GROUP, c), _parent(c.as<Chord>()) {}
    2800              : 
    2801          995 : void GraceNotesGroup::setPos(double x, double y)
    2802              : {
    2803          995 :     EngravingItem::setPos(x, y);
    2804         2322 :     for (unsigned i = 0; i < this->size(); ++i) {
    2805         1327 :         Chord* chord = this->at(i);
    2806         1327 :         chord->mutldata()->move(PointF(x, y));
    2807              :     }
    2808          995 : }
    2809              : 
    2810         2150 : void GraceNotesGroup::addToShape()
    2811              : {
    2812         5085 :     for (Chord* grace : *this) {
    2813         2935 :         const PointF yOffset = grace->staffOffset();
    2814         2935 :         staff_idx_t staffIdx = grace->staffIdx();
    2815         2935 :         staff_idx_t vStaffIdx = grace->vStaffIdx();
    2816         2935 :         Shape& s = _appendedSegment->staffShape(staffIdx);
    2817         2935 :         s.add(grace->shape(LD_ACCESS::PASS).translate(grace->pos() + yOffset));
    2818         2935 :         if (vStaffIdx != staffIdx) {
    2819              :             // Cross-staff grace notes add their shape to both the origin and the destination staff
    2820            0 :             Shape& s2 = _appendedSegment->staffShape(vStaffIdx);
    2821            0 :             s2.add(grace->shape().translate(grace->pos() + yOffset));
    2822              :         }
    2823              :     }
    2824         2150 : }
    2825              : }
        

Generated by: LCOV version 2.0-1