LCOV - code coverage report
Current view: top level - src/engraving/dom - note.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 55.5 % 2191 1216
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              : /**
      24              :  \file
      25              :  Implementation of classes Note and ShadowNote.
      26              : */
      27              : 
      28              : #include "note.h"
      29              : 
      30              : #include <cassert>
      31              : 
      32              : #include "translation.h"
      33              : 
      34              : #include "iengravingconfiguration.h" // IWYU pragma: keep
      35              : #include "iengravingfont.h"
      36              : 
      37              : #include "../editing/addremoveelement.h"
      38              : #include "../editing/editchord.h"
      39              : #include "../editing/editnote.h"
      40              : #include "../editing/editparentheses.h"
      41              : #include "../editing/noteinput.h"
      42              : #include "../editing/transaction/transaction.h"
      43              : #include "../editing/transpose.h"
      44              : #include "types/typesconv.h"
      45              : 
      46              : #include "rendering/score/horizontalspacing.h"
      47              : 
      48              : #include "accidental.h"
      49              : #include "actionicon.h"
      50              : #include "articulation.h"
      51              : #include "bagpembell.h"
      52              : #include "barline.h"
      53              : #include "beam.h"
      54              : #include "chord.h"
      55              : #include "chordline.h"
      56              : #include "drumset.h"
      57              : #include "factory.h"
      58              : #include "fingering.h"
      59              : #include "glissando.h"
      60              : #include "guitarbend.h"
      61              : #include "laissezvib.h"
      62              : #include "linkedobjects.h"
      63              : #include "measure.h"
      64              : #include "notedot.h"
      65              : #include "noteline.h"
      66              : #include "parenthesis.h"
      67              : #include "part.h"
      68              : #include "partialtie.h"
      69              : #include "pitchspelling.h"
      70              : #include "score.h"
      71              : #include "segment.h"
      72              : #include "spanner.h"
      73              : #include "staff.h"
      74              : #include "stafftype.h"
      75              : #include "stringdata.h"
      76              : #include "tie.h"
      77              : #include "utils.h"
      78              : #include "volta.h"
      79              : 
      80              : #include "log.h"
      81              : 
      82              : using namespace mu;
      83              : using namespace muse::draw;
      84              : using namespace mu::engraving;
      85              : using namespace mu::engraving::rendering::score;
      86              : 
      87              : namespace mu::engraving {
      88              : //---------------------------------------------------------
      89              : //   noteHeads
      90              : //    notehead groups
      91              : //---------------------------------------------------------
      92              : 
      93              : //int(NoteHeadGroup::HEAD_GROUPS) - 1: "-1" is needed to prevent building CUSTOM_GROUP noteheads set, since it is built by users and keep a specific set of existing noteheads
      94              : static const SymId noteHeads[2][int(NoteHeadGroup::HEAD_GROUPS) - 1][int(NoteHeadType::HEAD_TYPES)] = {
      95              :     {    // down stem
      96              :         { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,
      97              :           SymId::noteheadDoubleWhole },
      98              :         { SymId::noteheadXWhole,              SymId::noteheadXHalf,               SymId::noteheadXBlack,
      99              :           SymId::noteheadXDoubleWhole },
     100              :         { SymId::noteheadPlusWhole,           SymId::noteheadPlusHalf,            SymId::noteheadPlusBlack,
     101              :           SymId::noteheadPlusDoubleWhole },
     102              :         { SymId::noteheadCircleXWhole,        SymId::noteheadCircleXHalf,         SymId::noteheadCircleX,
     103              :           SymId::noteheadCircleXDoubleWhole },
     104              :         { SymId::noteheadWholeWithX,          SymId::noteheadHalfWithX,           SymId::noteheadVoidWithX,
     105              :           SymId::noteheadDoubleWholeWithX },
     106              :         { SymId::noteheadTriangleUpWhole,     SymId::noteheadTriangleUpHalf,      SymId::noteheadTriangleUpBlack,
     107              :           SymId::noteheadTriangleUpDoubleWhole },
     108              :         { SymId::noteheadTriangleDownWhole,   SymId::noteheadTriangleDownHalf,    SymId::noteheadTriangleDownBlack,
     109              :           SymId::noteheadTriangleDownDoubleWhole },
     110              :         { SymId::noteheadSlashedWhole1,       SymId::noteheadSlashedHalf1,        SymId::noteheadSlashedBlack1,
     111              :           SymId::noteheadSlashedDoubleWhole1 },
     112              :         { SymId::noteheadSlashedWhole2,       SymId::noteheadSlashedHalf2,        SymId::noteheadSlashedBlack2,
     113              :           SymId::noteheadSlashedDoubleWhole2 },
     114              :         { SymId::noteheadDiamondWhole,        SymId::noteheadDiamondHalf,         SymId::noteheadDiamondBlack,
     115              :           SymId::noteheadDiamondDoubleWhole },
     116              :         { SymId::noteheadDiamondWholeOld,     SymId::noteheadDiamondHalfOld,      SymId::noteheadDiamondBlackOld,
     117              :           SymId::noteheadDiamondDoubleWholeOld },
     118              :         { SymId::noteheadCircledWhole,        SymId::noteheadCircledHalf,         SymId::noteheadCircledBlack,
     119              :           SymId::noteheadCircledDoubleWhole },
     120              :         { SymId::noteheadCircledWholeLarge,   SymId::noteheadCircledHalfLarge,    SymId::noteheadCircledBlackLarge,
     121              :           SymId::noteheadCircledDoubleWholeLarge },
     122              :         { SymId::noteheadLargeArrowUpWhole,   SymId::noteheadLargeArrowUpHalf,    SymId::noteheadLargeArrowUpBlack,
     123              :           SymId::noteheadLargeArrowUpDoubleWhole },
     124              :         { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,
     125              :           SymId::noteheadDoubleWholeSquare },
     126              : 
     127              :         { SymId::noteheadSlashWhiteWhole,     SymId::noteheadSlashWhiteHalf,      SymId::noteheadSlashHorizontalEnds,
     128              :           SymId::noteheadSlashWhiteWhole },
     129              :         { SymId::noteheadSlashDiamondWhite,   SymId::noteheadSlashDiamondWhite,   SymId::noteheadSlashHorizontalEnds,
     130              :           SymId::noteheadSlashWhiteWhole },
     131              : 
     132              :         { SymId::noteShapeRoundWhite,         SymId::noteShapeRoundWhite,         SymId::noteShapeRoundBlack,
     133              :           SymId::noteShapeRoundDoubleWhole },
     134              :         { SymId::noteShapeSquareWhite,        SymId::noteShapeSquareWhite,        SymId::noteShapeSquareBlack,
     135              :           SymId::noteShapeSquareDoubleWhole },
     136              :         { SymId::noteShapeTriangleRightWhite, SymId::noteShapeTriangleRightWhite, SymId::noteShapeTriangleRightBlack,
     137              :           SymId::noteShapeTriangleRightDoubleWhole },
     138              :         { SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondBlack,
     139              :           SymId::noteShapeDiamondDoubleWhole },
     140              :         { SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpBlack,
     141              :           SymId::noteShapeTriangleUpDoubleWhole },
     142              :         { SymId::noteShapeMoonWhite,          SymId::noteShapeMoonWhite,          SymId::noteShapeMoonBlack,
     143              :           SymId::noteShapeMoonDoubleWhole },
     144              :         { SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundBlack,
     145              :           SymId::noteShapeTriangleRoundDoubleWhole },
     146              : 
     147              :         { SymId::noteheadHeavyX,              SymId::noteheadHeavyX,              SymId::noteheadHeavyX,
     148              :           SymId::noteheadHeavyX },
     149              :         { SymId::noteheadHeavyXHat,           SymId::noteheadHeavyXHat,           SymId::noteheadHeavyXHat,
     150              :           SymId::noteheadHeavyXHat },
     151              : 
     152              :         { SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneBlack,
     153              :           SymId::noteShapeKeystoneDoubleWhole },
     154              :         { SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonBlack,
     155              :           SymId::noteShapeQuarterMoonDoubleWhole },
     156              :         { SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleBlack,
     157              :           SymId::noteShapeIsoscelesTriangleDoubleWhole },
     158              :         { SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftBlack,
     159              :           SymId::noteShapeMoonLeftDoubleWhole },
     160              :         { SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftBlack,
     161              :           SymId::noteShapeArrowheadLeftDoubleWhole },
     162              :         { SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftBlack,
     163              :           SymId::noteShapeTriangleRoundLeftDoubleWhole },
     164              : 
     165              :         { SymId::noteDoWhole,  SymId::noteDoHalf,  SymId::noteDoBlack,  SymId::noSym },
     166              :         { SymId::noteDiWhole,  SymId::noteDiHalf,  SymId::noteDiBlack,  SymId::noSym },
     167              :         { SymId::noteRaWhole,  SymId::noteRaHalf,  SymId::noteRaBlack,  SymId::noSym },
     168              :         { SymId::noteReWhole,  SymId::noteReHalf,  SymId::noteReBlack,  SymId::noSym },
     169              :         { SymId::noteRiWhole,  SymId::noteRiHalf,  SymId::noteRiBlack,  SymId::noSym },
     170              :         { SymId::noteMeWhole,  SymId::noteMeHalf,  SymId::noteMeBlack,  SymId::noSym },
     171              :         { SymId::noteMiWhole,  SymId::noteMiHalf,  SymId::noteMiBlack,  SymId::noSym },
     172              :         { SymId::noteFaWhole,  SymId::noteFaHalf,  SymId::noteFaBlack,  SymId::noSym },
     173              :         { SymId::noteFiWhole,  SymId::noteFiHalf,  SymId::noteFiBlack,  SymId::noSym },
     174              :         { SymId::noteSeWhole,  SymId::noteSeHalf,  SymId::noteSeBlack,  SymId::noSym },
     175              :         { SymId::noteSoWhole,  SymId::noteSoHalf,  SymId::noteSoBlack,  SymId::noSym },
     176              :         { SymId::noteLeWhole,  SymId::noteLeHalf,  SymId::noteLeBlack,  SymId::noSym },
     177              :         { SymId::noteLaWhole,  SymId::noteLaHalf,  SymId::noteLaBlack,  SymId::noSym },
     178              :         { SymId::noteLiWhole,  SymId::noteLiHalf,  SymId::noteLiBlack,  SymId::noSym },
     179              :         { SymId::noteTeWhole,  SymId::noteTeHalf,  SymId::noteTeBlack,  SymId::noSym },
     180              :         { SymId::noteTiWhole,  SymId::noteTiHalf,  SymId::noteTiBlack,  SymId::noSym },
     181              :         { SymId::noteSiWhole,  SymId::noteSiHalf,  SymId::noteSiBlack,  SymId::noSym },
     182              : 
     183              :         { SymId::noteASharpWhole,  SymId::noteASharpHalf,  SymId::noteASharpBlack,  SymId::noSym },
     184              :         { SymId::noteAWhole,       SymId::noteAHalf,       SymId::noteABlack,       SymId::noSym },
     185              :         { SymId::noteAFlatWhole,   SymId::noteAFlatHalf,   SymId::noteAFlatBlack,   SymId::noSym },
     186              :         { SymId::noteBSharpWhole,  SymId::noteBSharpHalf,  SymId::noteBSharpBlack,  SymId::noSym },
     187              :         { SymId::noteBWhole,       SymId::noteBHalf,       SymId::noteBBlack,       SymId::noSym },
     188              :         { SymId::noteBFlatWhole,   SymId::noteBFlatHalf,   SymId::noteBFlatBlack,   SymId::noSym },
     189              :         { SymId::noteCSharpWhole,  SymId::noteCSharpHalf,  SymId::noteCSharpBlack,  SymId::noSym },
     190              :         { SymId::noteCWhole,       SymId::noteCHalf,       SymId::noteCBlack,       SymId::noSym },
     191              :         { SymId::noteCFlatWhole,   SymId::noteCFlatHalf,   SymId::noteCFlatBlack,   SymId::noSym },
     192              :         { SymId::noteDSharpWhole,  SymId::noteDSharpHalf,  SymId::noteDSharpBlack,  SymId::noSym },
     193              :         { SymId::noteDWhole,       SymId::noteDHalf,       SymId::noteDBlack,       SymId::noSym },
     194              :         { SymId::noteDFlatWhole,   SymId::noteDFlatHalf,   SymId::noteDFlatBlack,   SymId::noSym },
     195              :         { SymId::noteESharpWhole,  SymId::noteESharpHalf,  SymId::noteESharpBlack,  SymId::noSym },
     196              :         { SymId::noteEWhole,       SymId::noteEHalf,       SymId::noteEBlack,       SymId::noSym },
     197              :         { SymId::noteEFlatWhole,   SymId::noteEFlatHalf,   SymId::noteEFlatBlack,   SymId::noSym },
     198              :         { SymId::noteFSharpWhole,  SymId::noteFSharpHalf,  SymId::noteFSharpBlack,  SymId::noSym },
     199              :         { SymId::noteFWhole,       SymId::noteFHalf,       SymId::noteFBlack,       SymId::noSym },
     200              :         { SymId::noteFFlatWhole,   SymId::noteFFlatHalf,   SymId::noteFFlatBlack,   SymId::noSym },
     201              :         { SymId::noteGSharpWhole,  SymId::noteGSharpHalf,  SymId::noteGSharpBlack,  SymId::noSym },
     202              :         { SymId::noteGWhole,       SymId::noteGHalf,       SymId::noteGBlack,       SymId::noSym },
     203              :         { SymId::noteGFlatWhole,   SymId::noteGFlatHalf,   SymId::noteGFlatBlack,   SymId::noSym },
     204              :         { SymId::noteHWhole,       SymId::noteHHalf,       SymId::noteHBlack,       SymId::noSym },
     205              :         { SymId::noteHSharpWhole,  SymId::noteHSharpHalf,  SymId::noteHSharpBlack,  SymId::noSym },
     206              : 
     207              :         { SymId::noSym, SymId::swissRudimentsNoteheadHalfFlam,   SymId::swissRudimentsNoteheadBlackFlam,   SymId::noSym },
     208              :         { SymId::noSym, SymId::swissRudimentsNoteheadHalfDouble, SymId::swissRudimentsNoteheadBlackDouble, SymId::noSym }
     209              :     },
     210              :     {    // up stem
     211              :         { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,
     212              :           SymId::noteheadDoubleWhole },
     213              :         { SymId::noteheadXWhole,              SymId::noteheadXHalf,               SymId::noteheadXBlack,
     214              :           SymId::noteheadXDoubleWhole },
     215              :         { SymId::noteheadPlusWhole,           SymId::noteheadPlusHalf,            SymId::noteheadPlusBlack,
     216              :           SymId::noteheadPlusDoubleWhole },
     217              :         { SymId::noteheadCircleXWhole,        SymId::noteheadCircleXHalf,         SymId::noteheadCircleX,
     218              :           SymId::noteheadCircleXDoubleWhole },
     219              :         { SymId::noteheadWholeWithX,          SymId::noteheadHalfWithX,           SymId::noteheadVoidWithX,
     220              :           SymId::noteheadDoubleWholeWithX },
     221              :         { SymId::noteheadTriangleUpWhole,     SymId::noteheadTriangleUpHalf,      SymId::noteheadTriangleUpBlack,
     222              :           SymId::noteheadTriangleUpDoubleWhole },
     223              :         { SymId::noteheadTriangleDownWhole,   SymId::noteheadTriangleDownHalf,    SymId::noteheadTriangleDownBlack,
     224              :           SymId::noteheadTriangleDownDoubleWhole },
     225              :         { SymId::noteheadSlashedWhole1,       SymId::noteheadSlashedHalf1,        SymId::noteheadSlashedBlack1,
     226              :           SymId::noteheadSlashedDoubleWhole1 },
     227              :         { SymId::noteheadSlashedWhole2,       SymId::noteheadSlashedHalf2,        SymId::noteheadSlashedBlack2,
     228              :           SymId::noteheadSlashedDoubleWhole2 },
     229              :         { SymId::noteheadDiamondWhole,        SymId::noteheadDiamondHalf,         SymId::noteheadDiamondBlack,
     230              :           SymId::noteheadDiamondDoubleWhole },
     231              :         { SymId::noteheadDiamondWholeOld,     SymId::noteheadDiamondHalfOld,      SymId::noteheadDiamondBlackOld,
     232              :           SymId::noteheadDiamondDoubleWholeOld },
     233              :         { SymId::noteheadCircledWhole,        SymId::noteheadCircledHalf,         SymId::noteheadCircledBlack,
     234              :           SymId::noteheadCircledDoubleWhole },
     235              :         { SymId::noteheadCircledWholeLarge,   SymId::noteheadCircledHalfLarge,    SymId::noteheadCircledBlackLarge,
     236              :           SymId::noteheadCircledDoubleWholeLarge },
     237              :         // different from down, find source?
     238              :         { SymId::noteheadLargeArrowDownWhole, SymId::noteheadLargeArrowDownHalf,  SymId::noteheadLargeArrowDownBlack,
     239              :           SymId::noteheadLargeArrowDownDoubleWhole },
     240              :         { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,
     241              :           SymId::noteheadDoubleWholeSquare },
     242              : 
     243              :         { SymId::noteheadSlashWhiteWhole,     SymId::noteheadSlashWhiteHalf,      SymId::noteheadSlashHorizontalEnds,
     244              :           SymId::noteheadSlashWhiteDoubleWhole },
     245              :         { SymId::noteheadSlashDiamondWhite,   SymId::noteheadSlashDiamondWhite,   SymId::noteheadSlashHorizontalEnds,
     246              :           SymId::noteheadSlashWhiteDoubleWhole },
     247              : 
     248              :         { SymId::noteShapeRoundWhite,         SymId::noteShapeRoundWhite,         SymId::noteShapeRoundBlack,
     249              :           SymId::noteShapeRoundDoubleWhole },
     250              :         { SymId::noteShapeSquareWhite,        SymId::noteShapeSquareWhite,        SymId::noteShapeSquareBlack,
     251              :           SymId::noteShapeSquareDoubleWhole },
     252              :         // different from down
     253              :         { SymId::noteShapeTriangleLeftWhite,  SymId::noteShapeTriangleLeftWhite,  SymId::noteShapeTriangleLeftBlack,
     254              :           SymId::noteShapeTriangleLeftDoubleWhole },
     255              :         { SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondBlack,
     256              :           SymId::noteShapeDiamondDoubleWhole },
     257              :         { SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpBlack,
     258              :           SymId::noteShapeTriangleUpDoubleWhole },
     259              :         { SymId::noteShapeMoonWhite,          SymId::noteShapeMoonWhite,          SymId::noteShapeMoonBlack,
     260              :           SymId::noteShapeMoonDoubleWhole },
     261              :         { SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundBlack,
     262              :           SymId::noteShapeTriangleRoundDoubleWhole },
     263              : 
     264              :         { SymId::noteheadHeavyX,              SymId::noteheadHeavyX,              SymId::noteheadHeavyX,
     265              :           SymId::noteheadHeavyX },
     266              :         { SymId::noteheadHeavyXHat,           SymId::noteheadHeavyXHat,           SymId::noteheadHeavyXHat,
     267              :           SymId::noteheadHeavyXHat },
     268              : 
     269              :         { SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneBlack,
     270              :           SymId::noteShapeKeystoneDoubleWhole },
     271              :         { SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonBlack,
     272              :           SymId::noteShapeQuarterMoonDoubleWhole },
     273              :         { SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleBlack,
     274              :           SymId::noteShapeIsoscelesTriangleDoubleWhole },
     275              :         { SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftBlack,
     276              :           SymId::noteShapeMoonLeftDoubleWhole },
     277              :         { SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftBlack,
     278              :           SymId::noteShapeArrowheadLeftDoubleWhole },
     279              :         { SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftBlack,
     280              :           SymId::noteShapeTriangleRoundLeftDoubleWhole },
     281              : 
     282              :         { SymId::noteDoWhole,  SymId::noteDoHalf,  SymId::noteDoBlack,  SymId::noSym },
     283              :         { SymId::noteDiWhole,  SymId::noteDiHalf,  SymId::noteDiBlack,  SymId::noSym },
     284              :         { SymId::noteRaWhole,  SymId::noteRaHalf,  SymId::noteRaBlack,  SymId::noSym },
     285              :         { SymId::noteReWhole,  SymId::noteReHalf,  SymId::noteReBlack,  SymId::noSym },
     286              :         { SymId::noteRiWhole,  SymId::noteRiHalf,  SymId::noteRiBlack,  SymId::noSym },
     287              :         { SymId::noteMeWhole,  SymId::noteMeHalf,  SymId::noteMeBlack,  SymId::noSym },
     288              :         { SymId::noteMiWhole,  SymId::noteMiHalf,  SymId::noteMiBlack,  SymId::noSym },
     289              :         { SymId::noteFaWhole,  SymId::noteFaHalf,  SymId::noteFaBlack,  SymId::noSym },
     290              :         { SymId::noteFiWhole,  SymId::noteFiHalf,  SymId::noteFiBlack,  SymId::noSym },
     291              :         { SymId::noteSeWhole,  SymId::noteSeHalf,  SymId::noteSeBlack,  SymId::noSym },
     292              :         { SymId::noteSoWhole,  SymId::noteSoHalf,  SymId::noteSoBlack,  SymId::noSym },
     293              :         { SymId::noteLeWhole,  SymId::noteLeHalf,  SymId::noteLeBlack,  SymId::noSym },
     294              :         { SymId::noteLaWhole,  SymId::noteLaHalf,  SymId::noteLaBlack,  SymId::noSym },
     295              :         { SymId::noteLiWhole,  SymId::noteLiHalf,  SymId::noteLiBlack,  SymId::noSym },
     296              :         { SymId::noteTeWhole,  SymId::noteTeHalf,  SymId::noteTeBlack,  SymId::noSym },
     297              :         { SymId::noteTiWhole,  SymId::noteTiHalf,  SymId::noteTiBlack,  SymId::noSym },
     298              :         { SymId::noteSiWhole,  SymId::noteSiHalf,  SymId::noteSiBlack,  SymId::noSym },
     299              : 
     300              :         { SymId::noteASharpWhole,  SymId::noteASharpHalf,  SymId::noteASharpBlack,  SymId::noSym },
     301              :         { SymId::noteAWhole,       SymId::noteAHalf,       SymId::noteABlack,       SymId::noSym },
     302              :         { SymId::noteAFlatWhole,   SymId::noteAFlatHalf,   SymId::noteAFlatBlack,   SymId::noSym },
     303              :         { SymId::noteBSharpWhole,  SymId::noteBSharpHalf,  SymId::noteBSharpBlack,  SymId::noSym },
     304              :         { SymId::noteBWhole,       SymId::noteBHalf,       SymId::noteBBlack,       SymId::noSym },
     305              :         { SymId::noteBFlatWhole,   SymId::noteBFlatHalf,   SymId::noteBFlatBlack,   SymId::noSym },
     306              :         { SymId::noteCSharpWhole,  SymId::noteCSharpHalf,  SymId::noteCSharpBlack,  SymId::noSym },
     307              :         { SymId::noteCWhole,       SymId::noteCHalf,       SymId::noteCBlack,       SymId::noSym },
     308              :         { SymId::noteCFlatWhole,   SymId::noteCFlatHalf,   SymId::noteCFlatBlack,   SymId::noSym },
     309              :         { SymId::noteDSharpWhole,  SymId::noteDSharpHalf,  SymId::noteDSharpBlack,  SymId::noSym },
     310              :         { SymId::noteDWhole,       SymId::noteDHalf,       SymId::noteDBlack,       SymId::noSym },
     311              :         { SymId::noteDFlatWhole,   SymId::noteDFlatHalf,   SymId::noteDFlatBlack,   SymId::noSym },
     312              :         { SymId::noteESharpWhole,  SymId::noteESharpHalf,  SymId::noteESharpBlack,  SymId::noSym },
     313              :         { SymId::noteEWhole,       SymId::noteEHalf,       SymId::noteEBlack,       SymId::noSym },
     314              :         { SymId::noteEFlatWhole,   SymId::noteEFlatHalf,   SymId::noteEFlatBlack,   SymId::noSym },
     315              :         { SymId::noteFSharpWhole,  SymId::noteFSharpHalf,  SymId::noteFSharpBlack,  SymId::noSym },
     316              :         { SymId::noteFWhole,       SymId::noteFHalf,       SymId::noteFBlack,       SymId::noSym },
     317              :         { SymId::noteFFlatWhole,   SymId::noteFFlatHalf,   SymId::noteFFlatBlack,   SymId::noSym },
     318              :         { SymId::noteGSharpWhole,  SymId::noteGSharpHalf,  SymId::noteGSharpBlack,  SymId::noSym },
     319              :         { SymId::noteGWhole,       SymId::noteGHalf,       SymId::noteGBlack,       SymId::noSym },
     320              :         { SymId::noteGFlatWhole,   SymId::noteGFlatHalf,   SymId::noteGFlatBlack,   SymId::noSym },
     321              :         { SymId::noteHWhole,       SymId::noteHHalf,       SymId::noteHBlack,       SymId::noSym },
     322              :         { SymId::noteHSharpWhole,  SymId::noteHSharpHalf,  SymId::noteHSharpBlack,  SymId::noSym },
     323              : 
     324              :         { SymId::noSym, SymId::swissRudimentsNoteheadHalfFlam,   SymId::swissRudimentsNoteheadBlackFlam,   SymId::noSym },
     325              :         { SymId::noSym, SymId::swissRudimentsNoteheadHalfDouble, SymId::swissRudimentsNoteheadBlackDouble, SymId::noSym }
     326              :     }
     327              : };
     328              : 
     329              : //---------------------------------------------------------
     330              : //   noteHead
     331              : //---------------------------------------------------------
     332              : 
     333            2 : SymId Note::noteHead(int direction, NoteHeadGroup group, NoteHeadType t)
     334              : {
     335            2 :     return noteHeads[direction][int(group)][int(t)];
     336              : }
     337              : 
     338      1436498 : SymId Note::noteHead(int direction, NoteHeadGroup group, NoteHeadType t, int tpc, Key key, NoteHeadScheme scheme)
     339              : {
     340              :     // shortcut
     341      1436498 :     if (scheme == NoteHeadScheme::HEAD_NORMAL) {
     342      1434057 :         return noteHeads[direction][int(group)][int(t)];
     343              :     }
     344              :     // other schemes
     345         2441 :     if (scheme == NoteHeadScheme::HEAD_PITCHNAME || scheme == NoteHeadScheme::HEAD_PITCHNAME_GERMAN
     346          656 :         || scheme == NoteHeadScheme::HEAD_PITCHNAME_NO_ACCIDENTALS
     347          656 :         || scheme == NoteHeadScheme::HEAD_PITCHNAME_GERMAN_NO_ACCIDENTALS) {
     348         1785 :         const bool no_accidentals = scheme == NoteHeadScheme::HEAD_PITCHNAME_NO_ACCIDENTALS
     349         1785 :                                     || scheme == NoteHeadScheme::HEAD_PITCHNAME_GERMAN_NO_ACCIDENTALS;
     350         1785 :         const bool german = scheme == NoteHeadScheme::HEAD_PITCHNAME_GERMAN
     351         1785 :                             || scheme == NoteHeadScheme::HEAD_PITCHNAME_GERMAN_NO_ACCIDENTALS;
     352              : 
     353         1785 :         if (tpc == Tpc::TPC_A) {
     354          201 :             group = NoteHeadGroup::HEAD_A;
     355         1584 :         } else if (tpc == Tpc::TPC_B) {
     356          137 :             if (german) {
     357           27 :                 group = NoteHeadGroup::HEAD_H;
     358              :             } else {
     359          110 :                 group = NoteHeadGroup::HEAD_B;
     360              :             }
     361         1447 :         } else if (tpc == Tpc::TPC_C) {
     362          175 :             group = NoteHeadGroup::HEAD_C;
     363         1272 :         } else if (tpc == Tpc::TPC_D) {
     364          280 :             group = NoteHeadGroup::HEAD_D;
     365          992 :         } else if (tpc == Tpc::TPC_E) {
     366          254 :             group = NoteHeadGroup::HEAD_E;
     367          738 :         } else if (tpc == Tpc::TPC_F) {
     368          129 :             group = NoteHeadGroup::HEAD_F;
     369          609 :         } else if (tpc == Tpc::TPC_G) {
     370          197 :             group = NoteHeadGroup::HEAD_G;
     371          412 :         } else if (tpc == Tpc::TPC_A_S) {
     372            0 :             if (no_accidentals) {
     373            0 :                 group = NoteHeadGroup::HEAD_A;
     374              :             } else {
     375            0 :                 group = NoteHeadGroup::HEAD_A_SHARP;
     376              :             }
     377          412 :         } else if (tpc == Tpc::TPC_B_S) {
     378            0 :             if (no_accidentals) {
     379            0 :                 if (german) {
     380            0 :                     group = NoteHeadGroup::HEAD_H;
     381              :                 } else {
     382            0 :                     group = NoteHeadGroup::HEAD_B;
     383              :                 }
     384              :             } else {
     385            0 :                 if (german) {
     386            0 :                     group = NoteHeadGroup::HEAD_H_SHARP;
     387              :                 } else {
     388            0 :                     group = NoteHeadGroup::HEAD_B_SHARP;
     389              :                 }
     390              :             }
     391          412 :         } else if (tpc == Tpc::TPC_C_S) {
     392           84 :             if (no_accidentals) {
     393            0 :                 group = NoteHeadGroup::HEAD_C;
     394              :             } else {
     395           84 :                 group = NoteHeadGroup::HEAD_C_SHARP;
     396              :             }
     397          328 :         } else if (tpc == Tpc::TPC_D_S) {
     398           28 :             if (no_accidentals) {
     399            0 :                 group = NoteHeadGroup::HEAD_D;
     400              :             } else {
     401           28 :                 group = NoteHeadGroup::HEAD_D_SHARP;
     402              :             }
     403          300 :         } else if (tpc == Tpc::TPC_E_S) {
     404            0 :             if (no_accidentals) {
     405            0 :                 group = NoteHeadGroup::HEAD_E;
     406              :             } else {
     407            0 :                 group = NoteHeadGroup::HEAD_E_SHARP;
     408              :             }
     409          300 :         } else if (tpc == Tpc::TPC_F_S) {
     410          112 :             if (no_accidentals) {
     411            0 :                 group = NoteHeadGroup::HEAD_F;
     412              :             } else {
     413          112 :                 group = NoteHeadGroup::HEAD_F_SHARP;
     414              :             }
     415          188 :         } else if (tpc == Tpc::TPC_G_S) {
     416           44 :             if (no_accidentals) {
     417            0 :                 group = NoteHeadGroup::HEAD_G;
     418              :             } else {
     419           44 :                 group = NoteHeadGroup::HEAD_G_SHARP;
     420              :             }
     421          144 :         } else if (tpc == Tpc::TPC_A_B) {
     422           44 :             if (no_accidentals) {
     423            0 :                 group = NoteHeadGroup::HEAD_A;
     424              :             } else {
     425           44 :                 group = NoteHeadGroup::HEAD_A_FLAT;
     426              :             }
     427          100 :         } else if (tpc == Tpc::TPC_B_B) {
     428           28 :             if (no_accidentals) {
     429            0 :                 group = NoteHeadGroup::HEAD_B;
     430              :             } else {
     431           28 :                 if (german) {
     432           28 :                     group = NoteHeadGroup::HEAD_B;
     433              :                 } else {
     434            0 :                     group = NoteHeadGroup::HEAD_B_FLAT;
     435              :                 }
     436              :             }
     437           72 :         } else if (tpc == Tpc::TPC_C_B) {
     438            0 :             if (no_accidentals) {
     439            0 :                 group = NoteHeadGroup::HEAD_C;
     440              :             } else {
     441            0 :                 group = NoteHeadGroup::HEAD_C_FLAT;
     442              :             }
     443           72 :         } else if (tpc == Tpc::TPC_D_B) {
     444            0 :             if (no_accidentals) {
     445            0 :                 group = NoteHeadGroup::HEAD_D;
     446              :             } else {
     447            0 :                 group = NoteHeadGroup::HEAD_D_FLAT;
     448              :             }
     449           72 :         } else if (tpc == Tpc::TPC_E_B) {
     450           72 :             if (no_accidentals) {
     451            0 :                 group = NoteHeadGroup::HEAD_E;
     452              :             } else {
     453           72 :                 group = NoteHeadGroup::HEAD_E_FLAT;
     454              :             }
     455            0 :         } else if (tpc == Tpc::TPC_F_B) {
     456            0 :             if (no_accidentals) {
     457            0 :                 group = NoteHeadGroup::HEAD_F;
     458              :             } else {
     459            0 :                 group = NoteHeadGroup::HEAD_F_FLAT;
     460              :             }
     461            0 :         } else if (tpc == Tpc::TPC_G_B) {
     462            0 :             if (no_accidentals) {
     463            0 :                 group = NoteHeadGroup::HEAD_G;
     464              :             } else {
     465            0 :                 group = NoteHeadGroup::HEAD_G_FLAT;
     466              :             }
     467            0 :         } else if (no_accidentals) {
     468              :             // for TPCs that don't have their own heads (i.e. with 2 or 3 accidentals),
     469              :             // fall back to using the corresponding ones without accidentals
     470              :             // rather than using the (smaller!) normal noteheads
     471            0 :             if (tpc == Tpc::TPC_A_SS || tpc == Tpc::TPC_A_SSS) {
     472            0 :                 group = NoteHeadGroup::HEAD_A;
     473            0 :             } else if (tpc == Tpc::TPC_B_SS || tpc == Tpc::TPC_B_SSS) {
     474            0 :                 if (german) {
     475            0 :                     group = NoteHeadGroup::HEAD_H;
     476              :                 } else {
     477            0 :                     group = NoteHeadGroup::HEAD_B;
     478              :                 }
     479            0 :             } else if (tpc == Tpc::TPC_C_SS || tpc == Tpc::TPC_C_SSS) {
     480            0 :                 group = NoteHeadGroup::HEAD_C;
     481            0 :             } else if (tpc == Tpc::TPC_D_SS || tpc == Tpc::TPC_D_SSS) {
     482            0 :                 group = NoteHeadGroup::HEAD_D;
     483            0 :             } else if (tpc == Tpc::TPC_E_SS || tpc == Tpc::TPC_E_SSS) {
     484            0 :                 group = NoteHeadGroup::HEAD_E;
     485            0 :             } else if (tpc == Tpc::TPC_F_SS || tpc == Tpc::TPC_F_SSS) {
     486            0 :                 group = NoteHeadGroup::HEAD_F;
     487            0 :             } else if (tpc == Tpc::TPC_G_SS || tpc == Tpc::TPC_G_SSS) {
     488            0 :                 group = NoteHeadGroup::HEAD_G;
     489            0 :             } else if (tpc == Tpc::TPC_A_BB || tpc == Tpc::TPC_A_BBB) {
     490            0 :                 group = NoteHeadGroup::HEAD_A;
     491            0 :             } else if (tpc == Tpc::TPC_B_BB || tpc == Tpc::TPC_B_BBB) {
     492            0 :                 if (german) {
     493            0 :                     group = NoteHeadGroup::HEAD_H;
     494              :                 } else {
     495            0 :                     group = NoteHeadGroup::HEAD_B;
     496              :                 }
     497            0 :             } else if (tpc == Tpc::TPC_C_BB || tpc == Tpc::TPC_C_BBB) {
     498            0 :                 group = NoteHeadGroup::HEAD_C;
     499            0 :             } else if (tpc == Tpc::TPC_D_BB || tpc == Tpc::TPC_D_BBB) {
     500            0 :                 group = NoteHeadGroup::HEAD_D;
     501            0 :             } else if (tpc == Tpc::TPC_E_BB || tpc == Tpc::TPC_E_BBB) {
     502            0 :                 group = NoteHeadGroup::HEAD_E;
     503            0 :             } else if (tpc == Tpc::TPC_F_BB || tpc == Tpc::TPC_F_BBB) {
     504            0 :                 group = NoteHeadGroup::HEAD_F;
     505            0 :             } else if (tpc == Tpc::TPC_G_BB || tpc == Tpc::TPC_G_BBB) {
     506            0 :                 group = NoteHeadGroup::HEAD_G;
     507              :             }
     508              :         }
     509         2441 :     } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_4) {
     510            0 :         int degree = tpc2degree(tpc, key);
     511            0 :         switch (degree) {
     512            0 :         case 0:
     513              :         case 3:
     514            0 :             group = NoteHeadGroup::HEAD_FA;
     515            0 :             break;
     516            0 :         case 1:
     517              :         case 4:
     518            0 :             group = NoteHeadGroup::HEAD_SOL;
     519            0 :             break;
     520            0 :         case 2:
     521              :         case 5:
     522            0 :             group = NoteHeadGroup::HEAD_LA;
     523            0 :             break;
     524            0 :         case 6:
     525            0 :             group = NoteHeadGroup::HEAD_MI;
     526            0 :             break;
     527              :         }
     528          656 :     } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_AIKIN
     529          656 :                || scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_FUNK
     530          656 :                || scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_WALKER) {
     531            0 :         int degree = tpc2degree(tpc, key);
     532            0 :         switch (degree) {
     533            0 :         case 0:
     534            0 :             if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_AIKIN) {
     535            0 :                 group = NoteHeadGroup::HEAD_DO;
     536            0 :             } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_FUNK) {
     537            0 :                 group = NoteHeadGroup::HEAD_DO_FUNK;
     538            0 :             } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_WALKER) {
     539            0 :                 group = NoteHeadGroup::HEAD_DO_WALKER;
     540              :             }
     541            0 :             break;
     542            0 :         case 1:
     543            0 :             if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_AIKIN) {
     544            0 :                 group = NoteHeadGroup::HEAD_RE;
     545            0 :             } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_FUNK) {
     546            0 :                 group = NoteHeadGroup::HEAD_RE_FUNK;
     547            0 :             } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_WALKER) {
     548            0 :                 group = NoteHeadGroup::HEAD_RE_WALKER;
     549              :             }
     550            0 :             break;
     551            0 :         case 2:
     552            0 :             group = NoteHeadGroup::HEAD_MI;
     553            0 :             break;
     554            0 :         case 3:
     555            0 :             group = NoteHeadGroup::HEAD_FA;
     556            0 :             break;
     557            0 :         case 4:
     558            0 :             group = NoteHeadGroup::HEAD_SOL;
     559            0 :             break;
     560            0 :         case 5:
     561            0 :             group = NoteHeadGroup::HEAD_LA;
     562            0 :             break;
     563            0 :         case 6:
     564            0 :             if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_AIKIN) {
     565            0 :                 group = NoteHeadGroup::HEAD_TI;
     566            0 :             } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_FUNK) {
     567            0 :                 group = NoteHeadGroup::HEAD_TI_FUNK;
     568            0 :             } else if (scheme == NoteHeadScheme::HEAD_SHAPE_NOTE_7_WALKER) {
     569            0 :                 group = NoteHeadGroup::HEAD_TI_WALKER;
     570              :             }
     571            0 :             break;
     572              :         }
     573          656 :     } else if (scheme == NoteHeadScheme::HEAD_SOLFEGE) {
     574          383 :         int degree = tpc2degree(tpc, key);
     575          383 :         int alteration = tpc2alterByKey(tpc, key);
     576          383 :         if (degree == 0 && alteration == 0) {
     577            0 :             group = NoteHeadGroup::HEAD_DO_NAME;
     578          383 :         } else if (degree == 0 && alteration == 1) {
     579           48 :             group = NoteHeadGroup::HEAD_DI_NAME;
     580          335 :         } else if (degree == 1 && alteration == -1) {
     581           44 :             group = NoteHeadGroup::HEAD_RA_NAME;
     582          291 :         } else if (degree == 1 && alteration == 0) {
     583            0 :             group = NoteHeadGroup::HEAD_RE_NAME;
     584          291 :         } else if (degree == 1 && alteration == 1) {
     585           44 :             group = NoteHeadGroup::HEAD_RI_NAME;
     586          247 :         } else if (degree == 2 && alteration == -1) {
     587           44 :             group = NoteHeadGroup::HEAD_ME_NAME;
     588          203 :         } else if (degree == 2 && alteration == 0) {
     589            0 :             group = NoteHeadGroup::HEAD_MI_NAME;
     590          203 :         } else if (degree == 3 && alteration == 0) {
     591            0 :             group = NoteHeadGroup::HEAD_FA_NAME;
     592          203 :         } else if (degree == 3 && alteration == 1) {
     593           44 :             group = NoteHeadGroup::HEAD_FI_NAME;
     594          159 :         } else if (degree == 4 && alteration == -1) {
     595           44 :             group = NoteHeadGroup::HEAD_SE_NAME;
     596          115 :         } else if (degree == 4 && alteration == 0) {
     597           43 :             group = NoteHeadGroup::HEAD_SOL_NAME;
     598           72 :         } else if (degree == 4 && alteration == 1) {
     599            0 :             group = NoteHeadGroup::HEAD_SI_NAME;
     600           72 :         } else if (degree == 5 && alteration == -1) {
     601            0 :             group = NoteHeadGroup::HEAD_LE_NAME;
     602           72 :         } else if (degree == 5 && alteration == 0) {
     603            0 :             group = NoteHeadGroup::HEAD_LA_NAME;
     604           72 :         } else if (degree == 5 && alteration == 1) {
     605           44 :             group = NoteHeadGroup::HEAD_LI_NAME;
     606           28 :         } else if (degree == 6 && alteration == -1) {
     607           28 :             group = NoteHeadGroup::HEAD_TE_NAME;
     608            0 :         } else if (degree == 6 && alteration == 0) {
     609            0 :             group = NoteHeadGroup::HEAD_TI_NAME;
     610              :         }
     611          273 :     } else if (scheme == NoteHeadScheme::HEAD_SOLFEGE_FIXED) {
     612          273 :         Char stepName = tpc2stepName(tpc);
     613          273 :         if (stepName == u'C') {
     614           74 :             group = NoteHeadGroup::HEAD_DO_NAME;
     615          199 :         } else if (stepName == u'D') {
     616           43 :             group = NoteHeadGroup::HEAD_RE_NAME;
     617          156 :         } else if (stepName == u'E') {
     618           43 :             group = NoteHeadGroup::HEAD_MI_NAME;
     619          113 :         } else if (stepName == u'F') {
     620           43 :             group = NoteHeadGroup::HEAD_FA_NAME;
     621           70 :         } else if (stepName == u'G') {
     622            0 :             group = NoteHeadGroup::HEAD_SOL_NAME;
     623           70 :         } else if (stepName == u'A') {
     624           43 :             group = NoteHeadGroup::HEAD_LA_NAME;
     625           27 :         } else if (stepName == u'B') {
     626           27 :             group = NoteHeadGroup::HEAD_SI_NAME;
     627              :         }
     628              :     }
     629         2441 :     return noteHeads[direction][int(group)][int(t)];
     630              : }
     631              : 
     632            0 : NoteHead::NoteHead(DummyParentOr<Note> parent)
     633            0 :     : Symbol(ElementType::NOTEHEAD, parent) {}
     634              : 
     635              : //---------------------------------------------------------
     636              : //   headGroup
     637              : //   used only when dropping a notehead from the palette
     638              : //   they are either half note, either double whole
     639              : //---------------------------------------------------------
     640              : 
     641            0 : NoteHeadGroup NoteHead::headGroup() const
     642              : {
     643            0 :     NoteHeadGroup group = NoteHeadGroup::HEAD_INVALID;
     644            0 :     for (int i = 0; i < int(NoteHeadGroup::HEAD_DO_WALKER); ++i) {
     645            0 :         if (noteHeads[0][i][1] == m_sym || noteHeads[0][i][3] == m_sym) {
     646            0 :             group = (NoteHeadGroup)i;
     647            0 :             break;
     648              :         }
     649              :     }
     650            0 :     return group;
     651              : }
     652              : 
     653              : //---------------------------------------------------------
     654              : //   Note
     655              : //---------------------------------------------------------
     656              : 
     657        35940 : Note::Note(DummyParentOr<Chord> ch)
     658        35940 :     : EngravingItem(ElementType::NOTE, ch, ElementFlag::MOVABLE)
     659              : {
     660        35940 :     m_playEvents.push_back(NoteEvent());      // add default play event
     661        35940 : }
     662              : 
     663        73806 : Note::~Note()
     664              : {
     665        36903 :     delete m_accidental;
     666        36903 :     muse::DeleteAll(m_el);
     667              : 
     668        36903 :     if (m_tieFor && m_tieFor->parent() == this) {
     669          783 :         delete m_tieFor;
     670              :     }
     671              : 
     672        36903 :     muse::DeleteAll(m_dots);
     673        73806 : }
     674              : 
     675         7436 : std::vector<Note*> Note::compoundNotes() const
     676              : {
     677         7436 :     std::vector<Note*> elements;
     678         7436 :     if (Note* note = firstTiedNote()) {
     679         7436 :         elements.push_back(note);
     680              :     }
     681              : 
     682         7436 :     if (Note* note = lastTiedNote()) {
     683         7436 :         elements.push_back(note);
     684              :     }
     685              : 
     686         7437 :     for (Spanner* e : m_spannerFor) {
     687            1 :         elements.push_back(toNote(e->endElement()));
     688              :     }
     689         7437 :     for (Spanner* e : m_spannerBack) {
     690            1 :         elements.push_back(toNote(e->startElement()));
     691              :     }
     692              : 
     693         7436 :     Beam* beam = chord()->beam();
     694         7436 :     if (beam) {
     695         2796 :         for (EngravingItem* e : beam->elements()) {
     696         2167 :             if (e && e->isNote() && e != this) {
     697            0 :                 elements.push_back(toNote(e));
     698              :             }
     699              :         }
     700              :     }
     701              : 
     702         7436 :     return elements;
     703            0 : }
     704              : 
     705         5838 : Note::Note(const Note& n, bool link)
     706         5838 :     : EngravingItem(n, link)
     707              : {
     708         5838 :     if (link) {
     709         1078 :         score()->undo(new Link(this, const_cast<Note*>(&n)));
     710              :     }
     711         5838 :     m_subchannel        = n.m_subchannel;
     712         5838 :     m_line              = n.m_line;
     713         5838 :     m_fret              = n.m_fret;
     714         5838 :     m_harmonicFret     = n.m_harmonicFret;
     715         5838 :     m_displayFret      = n.m_displayFret;
     716         5838 :     m_string            = n.m_string;
     717         5838 :     m_fretConflict      = n.m_fretConflict;
     718         5838 :     m_ghost             = n.m_ghost;
     719         5838 :     m_deadNote          = n.m_deadNote;
     720         5838 :     m_pitch             = n.m_pitch;
     721         5838 :     m_centOffset        = n.m_centOffset;
     722         5838 :     m_tpc[0]            = n.m_tpc[0];
     723         5838 :     m_tpc[1]            = n.m_tpc[1];
     724         5838 :     m_dotsHidden        = n.m_dotsHidden;
     725         5838 :     m_hidden            = n.m_hidden;
     726         5838 :     m_play              = n.m_play;
     727         5838 :     m_tuning            = n.m_tuning;
     728         5838 :     m_veloType          = n.m_veloType;
     729         5838 :     m_userVelocity      = n.m_userVelocity;
     730         5838 :     m_headScheme        = n.m_headScheme;
     731         5838 :     m_headGroup         = n.m_headGroup;
     732         5838 :     m_headType          = n.m_headType;
     733         5838 :     m_userMirror        = n.m_userMirror;
     734         5838 :     m_isSmall          = n.m_isSmall;
     735         5838 :     m_userDotPosition   = n.m_userDotPosition;
     736         5838 :     m_fixed             = n.m_fixed;
     737         5838 :     m_fixedLine         = n.m_fixedLine;
     738         5838 :     m_harmonic          = n.m_harmonic;
     739         5838 :     m_hasParens         = n.m_hasParens;
     740         5838 :     m_hideGeneratedParens = n.m_hideGeneratedParens;
     741              : 
     742         5838 :     if (n.m_accidental) {
     743           30 :         add(new Accidental(*(n.m_accidental)));
     744              :     }
     745              : 
     746              :     // types in _el: SYMBOL, IMAGE, FINGERING, TEXT, BEND
     747         5838 :     const Staff* stf = staff();
     748         5838 :     bool tabFingering = stf ? stf->staffTypeForElement(this)->showTabFingering() : false;
     749         5863 :     for (EngravingItem* e : n.m_el) {
     750           25 :         if (e->isFingering() && staff()->isTabStaff(tick()) && !tabFingering) {      // tablature has no fingering
     751            0 :             continue;
     752              :         }
     753           25 :         EngravingItem* ce = e->clone();
     754           25 :         add(ce);
     755           25 :         if (link) {
     756           25 :             score()->undo(new Link(ce, const_cast<EngravingItem*>(e)));
     757              :         }
     758              :     }
     759              : 
     760         5838 :     m_playEvents = n.m_playEvents;
     761              : 
     762         5838 :     if (n.laissezVib()) {
     763            0 :         m_tieFor = Factory::copyLaissezVib(*toLaissezVib(n.m_tieFor));
     764            0 :         m_tieFor->setOwnershipParent(this);
     765            0 :         m_tieFor->setStartNote(this);
     766            0 :         m_tieFor->setTick(tick());
     767            0 :         if (link) {
     768            0 :             score()->undo(new Link(m_tieFor, n.m_tieFor));
     769              :         }
     770         5838 :     } else if (n.outgoingPartialTie()) {
     771            0 :         setTieFor(Factory::copyPartialTie(*toPartialTie(n.m_tieFor)));
     772            0 :         m_tieFor->setOwnershipParent(this);
     773            0 :         m_tieFor->setStartNote(this);
     774            0 :         m_tieFor->setTick(tick());
     775            0 :         if (link) {
     776            0 :             score()->undo(new Link(m_tieFor, n.m_tieFor));
     777              :         }
     778         5838 :     } else if (n.m_tieFor) {
     779          425 :         m_tieFor = Factory::copyTie(*n.m_tieFor);
     780          425 :         m_tieFor->setStartNote(this);
     781          425 :         m_tieFor->setTick(tick());
     782          425 :         m_tieFor->setEndNote(0);
     783              :     }
     784              : 
     785         5838 :     if (n.incomingPartialTie()) {
     786            0 :         setTieBack(Factory::copyPartialTie(*toPartialTie(n.m_tieBack)));
     787            0 :         m_tieBack->setOwnershipParent(this);
     788            0 :         m_tieBack->setEndNote(this);
     789            0 :         m_tieBack->setTick(tick());
     790            0 :         if (link) {
     791            0 :             score()->undo(new Link(m_tieBack, n.m_tieBack));
     792              :         }
     793              :     }
     794              : 
     795         5872 :     for (NoteDot* dot : n.m_dots) {
     796           34 :         add(Factory::copyNoteDot(*dot));
     797              :     }
     798         5838 :     m_mark      = n.m_mark;
     799              : 
     800         5838 :     setDropTarget(false);
     801         5838 : }
     802              : 
     803          338 : void Note::setOwnershipParent(DummyParentOr<Chord> ch)
     804              : {
     805          338 :     EngravingItem::setOwnershipParent(ch);
     806          338 : }
     807              : 
     808              : //---------------------------------------------------------
     809              : //   concertPitchIdx
     810              : //---------------------------------------------------------
     811              : 
     812      1773487 : inline int Note::concertPitchIdx() const
     813              : {
     814      1773487 :     return concertPitch() ? 0 : 1;
     815              : }
     816              : 
     817              : //---------------------------------------------------------
     818              : //   setPitch
     819              : //---------------------------------------------------------
     820              : 
     821        39470 : void Note::setPitch(int val, bool notifyAboutChanged)
     822              : {
     823        39470 :     assert(pitchIsValid(val));
     824        39470 :     if (m_pitch != val) {
     825        37429 :         m_pitch = val;
     826              : 
     827        37429 :         if (notifyAboutChanged) {
     828              : #ifndef ENGRAVING_NO_ACCESSIBILITY
     829        19810 :             notifyAboutNameChanged();
     830              : #endif
     831              :         }
     832              :     }
     833        39470 : }
     834              : 
     835         7787 : void Note::setPitch(int pitch, int tpc1, int tpc2)
     836              : {
     837         7787 :     assert(tpcIsValid(tpc1));
     838         7787 :     assert(tpcIsValid(tpc2));
     839         7787 :     m_tpc[0] = tpc1;
     840         7787 :     m_tpc[1] = tpc2;
     841         7787 :     setPitch(pitch);
     842         7787 : }
     843              : 
     844              : //---------------------------------------------------------
     845              : //   tpc1default
     846              : //---------------------------------------------------------
     847              : 
     848            0 : int Note::tpc1default(int p) const
     849              : {
     850            0 :     Key key = Key::C;
     851            0 :     if (staff() && chord()) {
     852            0 :         Fraction tick = chord()->tick();
     853            0 :         key = staff()->concertKey(tick);
     854              :     }
     855            0 :     return pitch2tpc(p, key, Prefer::NEAREST);
     856              : }
     857              : 
     858              : //---------------------------------------------------------
     859              : //   tpc2default
     860              : //---------------------------------------------------------
     861              : 
     862            0 : int Note::tpc2default(int p) const
     863              : {
     864            0 :     Key key = Key::C;
     865            0 :     if (staff() && chord()) {
     866            0 :         Fraction tick = chord()->tick();
     867            0 :         key = staff()->key(tick);
     868            0 :         if (concertPitch()) {
     869            0 :             Interval interval = originPart()->instrument(tick)->transpose();
     870            0 :             if (!interval.isZero()) {
     871            0 :                 interval.flip();
     872            0 :                 key = Transpose::transposeKey(key, interval);
     873              :             }
     874              :         }
     875              :     }
     876            0 :     return pitch2tpc(p - transposition(), key, Prefer::NEAREST);
     877              : }
     878              : 
     879              : //---------------------------------------------------------
     880              : //   setTpcFromPitch
     881              : //---------------------------------------------------------
     882              : 
     883         5229 : void Note::setTpcFromPitch(Prefer prefer /* = Prefer::NEAREST */)
     884              : {
     885              :     // works best if note is already added to score, otherwise we can't determine transposition or key
     886         5229 :     Fraction tick = chord() ? chord()->tick() : Fraction(-1, 1);
     887         5229 :     Interval v = staff() ? staff()->transpose(tick) : Interval();
     888         5229 :     Key cKey = (staff() && chord()) ? staff()->concertKey(chord()->tick()) : Key::C;
     889              :     // set concert pitch tpc
     890         5229 :     m_tpc[0] = pitch2tpc(m_pitch, cKey, prefer);
     891              :     // set transposed tpc
     892         5229 :     if (v.isZero()) {
     893         3085 :         m_tpc[1] = m_tpc[0];
     894              :     } else {
     895         2144 :         v.flip();
     896         2144 :         m_tpc[1] = Transpose::transposeTpc(m_tpc[0], v, true);
     897              :     }
     898         5229 :     assert(tpcIsValid(m_tpc[0]));
     899         5229 :     assert(tpcIsValid(m_tpc[1]));
     900         5229 : }
     901              : 
     902              : //---------------------------------------------------------
     903              : //   setTpc
     904              : //---------------------------------------------------------
     905              : 
     906            6 : void Note::setTpc(int v)
     907              : {
     908            6 :     IF_ASSERT_FAILED(tpcIsValid(v)) {
     909            0 :         return;
     910              :     }
     911            6 :     m_tpc[concertPitchIdx()] = v;
     912              : }
     913              : 
     914              : //---------------------------------------------------------
     915              : //   undoSetTpc
     916              : //    change the current tpc
     917              : //---------------------------------------------------------
     918              : 
     919          130 : void Note::undoSetTpc(int v)
     920              : {
     921          130 :     if (concertPitch()) {
     922            0 :         if (v != tpc1()) {
     923            0 :             undoChangeProperty(Pid::TPC1, v);
     924              :         }
     925              :     } else {
     926          130 :         if (v != tpc2()) {
     927          130 :             undoChangeProperty(Pid::TPC2, v);
     928              :         }
     929              :     }
     930          130 : }
     931              : 
     932              : //---------------------------------------------------------
     933              : //   tpc
     934              : //---------------------------------------------------------
     935              : 
     936      1773481 : int Note::tpc() const
     937              : {
     938      1773481 :     return m_tpc[concertPitchIdx()];
     939              : }
     940              : 
     941              : //---------------------------------------------------------
     942              : //   tpcUserName
     943              : //---------------------------------------------------------
     944              : 
     945            0 : String Note::tpcUserName(const bool explicitAccidental, bool full) const
     946              : {
     947            0 :     String pitchName = engraving::tpcUserName(tpc(), epitch() + ottaveCapoFret(), explicitAccidental, full);
     948              : 
     949            0 :     pitchName = muse::mtrc("global/pitchName", pitchName);
     950              : 
     951            0 :     if (fixed() && headGroup() == NoteHeadGroup::HEAD_SLASH) {
     952              :         // see Note::accessibleInfo(), but we return what we have
     953            0 :         return pitchName;
     954              :     }
     955            0 :     if (staff()->isDrumStaff(tick()) && originPart()->instrument(tick())->drumset()) {
     956              :         // see Note::accessibleInfo(), but we return what we have
     957            0 :         return pitchName;
     958              :     }
     959            0 :     if (staff()->isTabStaff(tick())) {
     960              :         // no further translation
     961            0 :         return pitchName;
     962              :     }
     963              : 
     964            0 :     String pitchOffset;
     965            0 :     if (tuning() != 0) {
     966              :         static constexpr size_t bufferSize = 50;
     967              :         char buffer[bufferSize];
     968            0 :         snprintf(buffer, bufferSize, "%+.3f", tuning());
     969            0 :         pitchOffset = String::fromAscii(buffer);
     970              :     }
     971              : 
     972            0 :     if (!concertPitch() && transposition()) {
     973            0 :         String soundingPitch = engraving::tpcUserName(tpc1(), ppitch(), explicitAccidental);
     974            0 :         soundingPitch = muse::mtrc("global/pitchName", soundingPitch);
     975            0 :         return muse::mtrc("engraving", "%1 (sounding as %2%3)").arg(pitchName, soundingPitch, pitchOffset);
     976            0 :     }
     977            0 :     return pitchName + pitchOffset;
     978            0 : }
     979              : 
     980              : //---------------------------------------------------------
     981              : //   transposeTpc
     982              : //    return transposed tpc
     983              : //    If in concertPitch mode return tpc for transposed view
     984              : //    else return tpc for concert pitch view.
     985              : //---------------------------------------------------------
     986              : 
     987          308 : int Note::transposeTpc(int tpc) const
     988              : {
     989          308 :     Fraction tick = chord() ? chord()->tick() : Fraction(-1, 1);
     990          308 :     Interval v = staff()->transpose(tick);
     991          308 :     if (v.isZero()) {
     992           35 :         return tpc;
     993              :     }
     994          273 :     if (concertPitch()) {
     995            0 :         v.flip();
     996            0 :         return Transpose::transposeTpc(tpc, v, true);
     997              :     } else {
     998          273 :         return Transpose::transposeTpc(tpc, v, true);
     999              :     }
    1000              : }
    1001              : 
    1002         1574 : int Note::playingTpc() const
    1003              : {
    1004         1574 :     int result = tpc();
    1005              : 
    1006         1574 :     if (!concertPitch() && transposition()) {
    1007           88 :         int tpc1 = this->tpc1();
    1008           88 :         if (tpc1 == Tpc::TPC_INVALID) {
    1009            0 :             result = transposeTpc(result);
    1010              :         } else {
    1011           88 :             result = tpc1;
    1012              :         }
    1013              :     }
    1014              : 
    1015         1574 :     int steps = ottaveCapoFret();
    1016         1574 :     if (steps != 0) {
    1017            0 :         result = Transpose::transposeTpc(result, Interval(steps), true);
    1018              :     }
    1019              : 
    1020         1574 :     return result;
    1021              : }
    1022              : 
    1023              : //---------------------------------------------------------
    1024              : //   noteHead
    1025              : //---------------------------------------------------------
    1026              : 
    1027      1436498 : SymId Note::noteHead() const
    1028              : {
    1029              :     int up;
    1030              :     NoteHeadType ht;
    1031      1436498 :     if (chord()) {
    1032      1436498 :         up = chord()->up();
    1033      1436498 :         ht = chord()->durationType().headType();
    1034              :     } else {
    1035            0 :         up = 1;
    1036            0 :         ht = NoteHeadType::HEAD_QUARTER;
    1037              :     }
    1038      1436498 :     if (m_headType != NoteHeadType::HEAD_AUTO) {
    1039         1500 :         ht = m_headType;
    1040              :     }
    1041              : 
    1042      1436498 :     const Staff* st = chord() ? chord()->staff() : nullptr;
    1043              : 
    1044      1436498 :     NoteHeadGroup headGroup = m_headGroup;
    1045      1436498 :     if (m_headGroup == NoteHeadGroup::HEAD_CUSTOM) {
    1046            0 :         if (st) {
    1047            0 :             if (st->staffTypeForElement(chord())->isDrumStaff()) {
    1048            0 :                 Fraction t = chord()->tick();
    1049            0 :                 Instrument* inst = originPart()->instrument(t);
    1050            0 :                 Drumset* d = inst->drumset();
    1051            0 :                 if (d) {
    1052            0 :                     return d->noteHeads(m_pitch, ht);
    1053              :                 } else {
    1054            0 :                     LOGD("no drumset");
    1055            0 :                     return noteHead(up, NoteHeadGroup::HEAD_NORMAL, ht);
    1056              :                 }
    1057              :             } else {
    1058            0 :                 headGroup = NoteHeadGroup::HEAD_NORMAL;
    1059              :             }
    1060              :         } else {
    1061            0 :             return ldata()->cachedNoteheadSym.value();
    1062              :         }
    1063              :     }
    1064              : 
    1065      1436498 :     Key key = Key::C;
    1066      1436498 :     NoteHeadScheme scheme = m_headScheme;
    1067      1436498 :     if (st) {
    1068      1436498 :         Fraction tick = chord()->tick();
    1069      1436498 :         if (tick >= Fraction(0, 1)) {
    1070      1436498 :             key    = st->key(tick);
    1071      1436498 :             if (scheme == NoteHeadScheme::HEAD_AUTO) {
    1072      1434057 :                 scheme = st->staffTypeForElement(chord())->noteHeadScheme();
    1073              :             }
    1074              :         }
    1075              :     }
    1076      1436498 :     if (scheme == NoteHeadScheme::HEAD_AUTO) {
    1077            0 :         scheme = NoteHeadScheme::HEAD_NORMAL;
    1078              :     }
    1079      1436498 :     SymId t = noteHead(up, headGroup, ht, tpc(), key, scheme);
    1080      1436498 :     if (t == SymId::noSym) {
    1081            0 :         LOGD("invalid notehead %d/%d", int(headGroup), int(ht));
    1082            0 :         t = noteHead(up, NoteHeadGroup::HEAD_NORMAL, ht);
    1083              :     }
    1084      1436498 :     return t;
    1085              : }
    1086              : 
    1087              : //---------------------------------------------------------
    1088              : //   headWidth
    1089              : //
    1090              : //    returns the x of the symbol bbox. It is different from headWidth() because zero point could be different from leftmost bbox position.
    1091              : //---------------------------------------------------------
    1092        59861 : double Note::bboxRightPos() const
    1093              : {
    1094        59861 :     const auto& bbox = score()->engravingFont()->bbox(noteHead(), magS());
    1095       119722 :     return bbox.right();
    1096              : }
    1097              : 
    1098              : //---------------------------------------------------------
    1099              : //   headBodyWidth
    1100              : //
    1101              : //    returns the width of the notehead "body". It is actual for slashed noteheads like -O-, where O is body.
    1102              : //---------------------------------------------------------
    1103       254205 : double Note::headBodyWidth() const
    1104              : {
    1105       254205 :     const StaffType* st = staffType();
    1106       254205 :     if (st && st->isTabStaff()) {
    1107          333 :         return tabHeadWidth(st);
    1108              :     }
    1109       253872 :     return headWidth() + 2 * bboxXShift();
    1110              : }
    1111              : 
    1112              : //---------------------------------------------------------
    1113              : //   outsideTieAttachX
    1114              : //
    1115              : //    returns the X-position for tie attachment for this particular notehead
    1116              : //---------------------------------------------------------
    1117            0 : double Note::outsideTieAttachX(bool up) const
    1118              : {
    1119            0 :     double xo = 0;
    1120              : 
    1121              :     // tab staff notes just use center of bounding box
    1122            0 :     if (staffType()->isTabStaff()) {
    1123            0 :         return x() + ((width() / 2) * mag());
    1124              :     }
    1125              :     // special cases:
    1126            0 :     if (m_headGroup == NoteHeadGroup::HEAD_SLASH) {
    1127            0 :         xo = (up ? headWidth() * 0.75 : headWidth() * 0.25);
    1128            0 :         if (chord()->durationType().hasStem()) {
    1129              :             // for quarters and halves, we can safely move a little bit outwards
    1130            0 :             xo += spatium() * 0.13 * (chord()->up() ? -mag() : mag());
    1131              :         }
    1132            0 :         return x() + xo;
    1133              :     }
    1134            0 :     if (m_headGroup == NoteHeadGroup::HEAD_SLASHED1 || m_headGroup == NoteHeadGroup::HEAD_SLASHED2) {
    1135              :         // just use the very center of the notehead
    1136            0 :         return x() + ((headBodyWidth() / 2) * mag());
    1137              :     }
    1138              :     /* Noteheads do not have optical centers at this time, but here's the code
    1139              :        to future-proof
    1140              :     xo = symSmuflAnchor(noteHead(), SmuflAnchorId::opticalCenter).x() * mag();
    1141              :     if (xo > 0) {
    1142              :         return x() + xo;
    1143              :     }
    1144              :     */
    1145              :     // try for average of cutouts
    1146            0 :     if (up) {
    1147            0 :         double xNE = symSmuflAnchor(noteHead(), SmuflAnchorId::cutOutNE).x();
    1148            0 :         double xNW = symSmuflAnchor(noteHead(), SmuflAnchorId::cutOutNW).x();
    1149            0 :         xo = ((xNE + xNW) / 2);
    1150            0 :         if (xNE < xNW) {
    1151              :             // musejazz is busted
    1152            0 :             xo = 0;
    1153              :         }
    1154              :     } else {
    1155            0 :         double xSE = symSmuflAnchor(noteHead(), SmuflAnchorId::cutOutSE).x();
    1156            0 :         double xSW = symSmuflAnchor(noteHead(), SmuflAnchorId::cutOutSW).x();
    1157            0 :         xo = ((xSE + xSW) / 2);
    1158            0 :         if (xSE < xSW) {
    1159            0 :             xo = 0;
    1160              :         }
    1161              :     }
    1162            0 :     if (xo > 0) {
    1163            0 :         return x() + xo;
    1164              :     }
    1165              :     // no cutout, not a slash head, default to middle of notehead
    1166            0 :     return x() + (headWidth() / 2);
    1167              : }
    1168              : 
    1169            0 : void Note::updateHeadGroup(const NoteHeadGroup headGroup)
    1170              : {
    1171            0 :     NoteHeadGroup group = headGroup;
    1172              : 
    1173            0 :     if (group == NoteHeadGroup::HEAD_INVALID) {
    1174            0 :         LOGD("unknown notehead");
    1175            0 :         group = NoteHeadGroup::HEAD_NORMAL;
    1176              :     }
    1177              : 
    1178            0 :     if (group == m_headGroup) {
    1179            0 :         return;
    1180              :     }
    1181              : 
    1182            0 :     if (links()) {
    1183            0 :         for (EngravingObject* scoreElement : *links()) {
    1184            0 :             scoreElement->undoChangeProperty(Pid::HEAD_GROUP, group);
    1185            0 :             Note* note = toNote(scoreElement);
    1186              : 
    1187            0 :             if (note->staff() && !note->staff()->isDrumStaff(chord()->tick()) && group == NoteHeadGroup::HEAD_CROSS) {
    1188            0 :                 scoreElement->undoChangeProperty(Pid::DEAD, true);
    1189              :             }
    1190              :         }
    1191              :     } else {
    1192            0 :         undoChangeProperty(Pid::HEAD_GROUP, group);
    1193              :     }
    1194              : }
    1195              : 
    1196              : //---------------------------------------------------------
    1197              : //   headWidth
    1198              : //
    1199              : //    returns the width of the symbol bbox
    1200              : //    or the width of the string representation of the fret mark
    1201              : //---------------------------------------------------------
    1202              : 
    1203       327083 : double Note::headWidth() const
    1204              : {
    1205       327083 :     return symWidth(noteHead());
    1206              : }
    1207              : 
    1208              : //---------------------------------------------------------
    1209              : //   bboxXShift
    1210              : //
    1211              : //    returns the x shift of the notehead bounding box
    1212              : //---------------------------------------------------------
    1213       274867 : double Note::bboxXShift() const
    1214              : {
    1215       274867 :     const auto& bbox = score()->engravingFont()->bbox(noteHead(), magS());
    1216       274867 :     return bbox.bottomLeft().x();
    1217              : }
    1218              : 
    1219              : //---------------------------------------------------------
    1220              : //   noteheadCenterX
    1221              : //
    1222              : //    returns the x coordinate of the notehead center related to the basepoint of the notehead bbox
    1223              : //---------------------------------------------------------
    1224         9099 : double Note::noteheadCenterX() const
    1225              : {
    1226         9099 :     return score()->engravingFont()->width(noteHead(), magS()) / 2 + bboxXShift();
    1227              : }
    1228              : 
    1229              : //---------------------------------------------------------
    1230              : //   tabHeadWidth
    1231              : //---------------------------------------------------------
    1232              : 
    1233         3859 : double Note::tabHeadWidth(const StaffType* tab) const
    1234              : {
    1235              :     double val;
    1236         3859 :     if (tab && tab->isTabStaff() && m_fret != INVALID_FRET_INDEX && m_string != INVALID_STRING_INDEX) {
    1237         2036 :         Font f = tab->fretFont();
    1238         2036 :         f.setPointSizeF(tab->fretFontSize());
    1239         2036 :         val = FontMetrics::width(f, m_fretString) * magS();
    1240         2036 :     } else {
    1241         1823 :         val = headWidth();
    1242              :     }
    1243         3859 :     return val;
    1244              : }
    1245              : 
    1246              : //---------------------------------------------------------
    1247              : //   headHeight
    1248              : //
    1249              : //    returns the height of the notehead symbol
    1250              : //    or the height of the string representation of the fret mark
    1251              : //---------------------------------------------------------
    1252              : 
    1253         8170 : double Note::headHeight() const
    1254              : {
    1255         8170 :     return symHeight(noteHead());
    1256              : }
    1257              : 
    1258              : //---------------------------------------------------------
    1259              : //   tabHeadHeight
    1260              : //---------------------------------------------------------
    1261              : 
    1262            0 : double Note::tabHeadHeight(const StaffType* tab) const
    1263              : {
    1264            0 :     if (tab && m_fret != INVALID_FRET_INDEX && m_string != INVALID_STRING_INDEX) {
    1265            0 :         return tab->fretBoxH() * magS();
    1266              :     }
    1267            0 :     return headHeight();
    1268              : }
    1269              : 
    1270              : //---------------------------------------------------------
    1271              : //   stemDownNW
    1272              : //---------------------------------------------------------
    1273              : 
    1274       331475 : PointF Note::stemDownNW() const
    1275              : {
    1276       331475 :     return symSmuflAnchor(noteHead(), SmuflAnchorId::stemDownNW);
    1277              : }
    1278              : 
    1279              : //---------------------------------------------------------
    1280              : //   stemUpSE
    1281              : //---------------------------------------------------------
    1282              : 
    1283       362662 : PointF Note::stemUpSE() const
    1284              : {
    1285       362662 :     return symSmuflAnchor(noteHead(), SmuflAnchorId::stemUpSE);
    1286              : }
    1287              : 
    1288              : //---------------------------------------------------------
    1289              : //   playTicks
    1290              : ///   Return total tick len of tied notes
    1291              : //---------------------------------------------------------
    1292              : 
    1293          722 : int Note::playTicks() const
    1294              : {
    1295          722 :     return playTicksFraction().ticks();
    1296              : }
    1297              : 
    1298              : //---------------------------------------------------------
    1299              : //   playTicksFraction
    1300              : ///   Return total tick len of tied notes
    1301              : //---------------------------------------------------------
    1302              : 
    1303          722 : Fraction Note::playTicksFraction() const
    1304              : {
    1305          722 :     if (!m_tieBack && !m_tieFor && chord()) {
    1306          670 :         return chord()->actualTicks();
    1307              :     }
    1308           52 :     return lastTiedNote()->chord()->endTick() - firstTiedNote()->chord()->tick();
    1309              : }
    1310              : 
    1311              : //---------------------------------------------------------
    1312              : //   addSpanner
    1313              : //---------------------------------------------------------
    1314              : 
    1315          391 : void Note::addSpanner(Spanner* l)
    1316              : {
    1317          391 :     EngravingItem* e = l->endElement();
    1318          391 :     if (e && e->isNote()) {
    1319          372 :         Note* note = toNote(e);
    1320          372 :         note->addSpannerBack(l);
    1321          372 :         bool isNoteAnchoredTextLine = l->isNoteLine() && toNoteLine(l)->enforceMinLength();
    1322          372 :         if (l->isGlissando() || l->isGuitarBend() || isNoteAnchoredTextLine) {
    1323          372 :             note->chord()->setEndsNoteAnchoredLine(true);
    1324              :         }
    1325              :     }
    1326          391 :     addSpannerFor(l);
    1327          391 : }
    1328              : 
    1329              : //---------------------------------------------------------
    1330              : //   removeSpanner
    1331              : //---------------------------------------------------------
    1332              : 
    1333            0 : void Note::removeSpanner(Spanner* l)
    1334              : {
    1335            0 :     Note* e = toNote(l->endElement());
    1336            0 :     if (e && e->isNote()) {
    1337            0 :         if (!e->removeSpannerBack(l)) {
    1338            0 :             LOGD("Note::removeSpanner(%p): cannot remove spannerBack %s %p", this, l->typeName(), l);
    1339              :             // abort();
    1340              :         }
    1341            0 :         if (l->isGlissando()) {
    1342            0 :             e->chord()->updateEndsNoteAnchoredLine();
    1343              :         }
    1344              :     }
    1345            0 :     if (!removeSpannerFor(l)) {
    1346            0 :         LOGD("Note(%p): cannot remove spannerFor %s %p", this, l->typeName(), l);
    1347              :         // abort();
    1348              :     }
    1349            0 : }
    1350              : 
    1351              : //---------------------------------------------------------
    1352              : //   add
    1353              : //---------------------------------------------------------
    1354              : 
    1355         7123 : void Note::add(EngravingItem* e)
    1356              : {
    1357         7123 :     if (e->ownershipParent() != this) {
    1358          349 :         e->setOwnershipParent(this);
    1359              :     }
    1360         7123 :     e->setTrack(track());
    1361              : 
    1362         7123 :     switch (e->type()) {
    1363          711 :     case ElementType::NOTEDOT:
    1364          711 :         m_dots.push_back(toNoteDot(e));
    1365          711 :         break;
    1366          338 :     case ElementType::BEND:
    1367              :     case ElementType::FINGERING:
    1368              :     case ElementType::IMAGE:
    1369              :     case ElementType::TEXT:
    1370          338 :         m_el.push_back(e);
    1371          338 :         break;
    1372           32 :     case ElementType::SYMBOL: {
    1373           32 :         m_el.push_back(e);
    1374           32 :     } break;
    1375           19 :     case ElementType::LAISSEZ_VIB: {
    1376           19 :         LaissezVib* lv = toLaissezVib(e);
    1377           19 :         lv->setStartNote(this);
    1378           19 :         lv->setTick(lv->startNote()->tick());
    1379           19 :         setTieFor(lv);
    1380           19 :         break;
    1381              :     }
    1382           75 :     case ElementType::PARTIAL_TIE: {
    1383           75 :         PartialTie* pt = toPartialTie(e);
    1384           75 :         pt->setTick(tick());
    1385           75 :         if (pt->isOutgoing()) {
    1386           24 :             pt->setStartNote(this);
    1387           24 :             setTieFor(pt);
    1388              :         } else {
    1389           51 :             pt->setEndNote(this);
    1390           51 :             setTieBack(pt);
    1391              :         }
    1392           75 :         break;
    1393              :     }
    1394          491 :     case ElementType::TIE: {
    1395          491 :         Tie* tie = toTie(e);
    1396          491 :         tie->setStartNote(this);
    1397          491 :         tie->setTick(tie->startNote()->tick());
    1398          491 :         setTieFor(tie);
    1399          491 :         if (tie->endNote()) {
    1400          375 :             tie->endNote()->setTieBack(tie);
    1401              :         }
    1402              :     }
    1403          491 :     break;
    1404         5066 :     case ElementType::ACCIDENTAL:
    1405         5066 :         m_accidental = toAccidental(e);
    1406         5066 :         m_centOffset = Accidental::subtype2centOffset(toAccidental(e)->accidentalType());
    1407         5066 :         break;
    1408          391 :     case ElementType::TEXTLINE:
    1409              :     case ElementType::NOTELINE:
    1410              :     case ElementType::GLISSANDO:
    1411              :     case ElementType::GUITAR_BEND:
    1412          391 :         addSpanner(toSpanner(e));
    1413          391 :         break;
    1414            0 :     default:
    1415            0 :         EngravingItem::add(e);
    1416            0 :         break;
    1417              :     }
    1418         7123 :     triggerLayout();
    1419              : 
    1420         7123 :     e->added();
    1421         7123 : }
    1422              : 
    1423              : //---------------------------------------------------------
    1424              : //   remove
    1425              : //---------------------------------------------------------
    1426              : 
    1427         2874 : void Note::remove(EngravingItem* e)
    1428              : {
    1429         2874 :     switch (e->type()) {
    1430           12 :     case ElementType::NOTEDOT:
    1431           12 :         m_dots.pop_back();
    1432           12 :         break;
    1433              : 
    1434           24 :     case ElementType::BEND:
    1435              :     case ElementType::TEXT:
    1436              :     case ElementType::IMAGE:
    1437              :     case ElementType::FINGERING:
    1438           24 :         if (!m_el.remove(e)) {
    1439            0 :             LOGD("Note::remove(): cannot find %s", e->typeName());
    1440              :         }
    1441           24 :         break;
    1442           12 :     case ElementType::SYMBOL:
    1443           12 :         if (!m_el.remove(e)) {
    1444            0 :             LOGD("Note::remove(): cannot find %s", e->typeName());
    1445              :         }
    1446           12 :         break;
    1447           39 :     case ElementType::PARTIAL_TIE: {
    1448           39 :         PartialTie* pt = toPartialTie(e);
    1449           39 :         assert((pt->isOutgoing() ? pt->startNote() : pt->endNote()) == this);
    1450           39 :         if (pt->isOutgoing()) {
    1451           10 :             setTieFor(nullptr);
    1452              :         } else {
    1453           29 :             setTieBack(nullptr);
    1454           29 :             pt->setJumpPoint(nullptr);
    1455              :         }
    1456           39 :         break;
    1457              :     }
    1458         1006 :     case ElementType::LAISSEZ_VIB:
    1459              :     case ElementType::TIE: {
    1460         1006 :         Tie* tie = toTie(e);
    1461         1006 :         assert(tie->startNote() == this);
    1462         1006 :         setTieFor(nullptr);
    1463         1006 :         tie->setJumpPoint(nullptr);
    1464         1006 :         if (tie->endNote()) {
    1465          991 :             tie->endNote()->setTieBack(0);
    1466              :         }
    1467              :     }
    1468         1006 :     break;
    1469              : 
    1470         1781 :     case ElementType::ACCIDENTAL:
    1471         1781 :         m_accidental = 0;
    1472         1781 :         m_centOffset = 0;
    1473         1781 :         break;
    1474              : 
    1475            0 :     case ElementType::TEXTLINE:
    1476              :     case ElementType::NOTELINE:
    1477              :     case ElementType::GLISSANDO:
    1478              :     case ElementType::GUITAR_BEND:
    1479            0 :         removeSpanner(toSpanner(e));
    1480            0 :         break;
    1481              : 
    1482            0 :     default:
    1483            0 :         EngravingItem::remove(e);
    1484            0 :         break;
    1485              :     }
    1486         2874 :     triggerLayout();
    1487         2874 :     e->removed();
    1488         2874 : }
    1489              : 
    1490              : //---------------------------------------------------------
    1491              : //   isNoteName
    1492              : //---------------------------------------------------------
    1493              : 
    1494        58698 : bool Note::isNoteName() const
    1495              : {
    1496        58698 :     if (chord() && chord()->staff()) {
    1497        58698 :         const Staff* st = staff();
    1498        58698 :         NoteHeadScheme s = m_headScheme;
    1499        58698 :         if (s == NoteHeadScheme::HEAD_AUTO) {
    1500        58561 :             s = st->staffTypeForElement(this)->noteHeadScheme();
    1501              :         }
    1502        58606 :         return s == NoteHeadScheme::HEAD_PITCHNAME || s == NoteHeadScheme::HEAD_PITCHNAME_GERMAN
    1503        58593 :                || s == NoteHeadScheme::HEAD_PITCHNAME_NO_ACCIDENTALS || s == NoteHeadScheme::HEAD_PITCHNAME_GERMAN_NO_ACCIDENTALS
    1504       117304 :                || s == NoteHeadScheme::HEAD_SOLFEGE || s == NoteHeadScheme::HEAD_SOLFEGE_FIXED;
    1505              :     }
    1506            0 :     return false;
    1507              : }
    1508              : 
    1509         1028 : void Note::updateFrettingForTiesAndBends()
    1510              : {
    1511         1028 :     Note* prevNote = nullptr;
    1512         1028 :     if (m_tieBack) {
    1513           37 :         prevNote = m_tieBack->startNote();
    1514              :     } else {
    1515          991 :         GuitarBend* bend = bendBack();
    1516          991 :         if (bend) {
    1517           25 :             prevNote = bend->startNote();
    1518              :         }
    1519              :     }
    1520              : 
    1521         1028 :     if (!prevNote) {
    1522          966 :         return;
    1523              :     }
    1524              : 
    1525           62 :     setString(prevNote->string());
    1526           62 :     setFret(prevNote->fret());
    1527              : }
    1528              : 
    1529        26548 : bool Note::shouldHideFret() const
    1530              : {
    1531        26548 :     if (!tieBack() || shouldForceShowFret() || !staffType()->isTabStaff()) {
    1532        26229 :         return false;
    1533              :     }
    1534              : 
    1535          319 :     if (isContinuationOfBend() && !rtick().isZero()) {
    1536           10 :         return true;
    1537              :     }
    1538              : 
    1539          309 :     ShowTiedFret showTiedFret = style().value(Sid::tabShowTiedFret).value<ShowTiedFret>();
    1540          309 :     if (showTiedFret == ShowTiedFret::TIE_AND_FRET) {
    1541          309 :         return false;
    1542              :     }
    1543              : 
    1544            0 :     ParenthesizeTiedFret parenthTiedFret = style().value(Sid::tabParenthesizeTiedFret).value<ParenthesizeTiedFret>();
    1545            0 :     if (parenthTiedFret == ParenthesizeTiedFret::NEVER || !rtick().isZero()) {
    1546            0 :         return true;
    1547              :     }
    1548              : 
    1549            0 :     if (parenthTiedFret == ParenthesizeTiedFret::START_OF_MEASURE) {
    1550            0 :         return false;
    1551              :     }
    1552              : 
    1553            0 :     const Measure* measure = findMeasure();
    1554            0 :     bool isStartOfSystem = measure && measure->system() && measure->isFirstInSystem();
    1555              : 
    1556            0 :     return !isStartOfSystem;
    1557              : }
    1558              : 
    1559        13005 : bool Note::shouldForceShowFret() const
    1560              : {
    1561        13005 :     if (!style().styleB(Sid::parenthesizeTiedFretIfArticulation)) {
    1562            0 :         return false;
    1563              :     }
    1564              : 
    1565        13005 :     Chord* ch = chord();
    1566        13005 :     if (!ch) {
    1567            0 :         return false;
    1568              :     }
    1569              : 
    1570        12933 :     auto hasTremoloBar = [&] () {
    1571        13325 :         for (EngravingItem* item : ch->segment()->annotations()) {
    1572          392 :             if (item && item->isTremoloBar() && item->track() == track()) {
    1573            0 :                 return true;
    1574              :             }
    1575              :         }
    1576        12933 :         return false;
    1577        13005 :     };
    1578              : 
    1579        12933 :     auto hasVibratoLine = [&] () {
    1580        12933 :         auto spanners = score()->spannerMap().findOverlapping(tick().ticks(), ch->endTick().ticks());
    1581        15548 :         for (auto interval : spanners) {
    1582         2623 :             Spanner* sp = interval.value;
    1583         2623 :             if (sp->isVibrato() && sp->startElement() == ch) {
    1584            8 :                 return true;
    1585              :             }
    1586              :         }
    1587        12925 :         return false;
    1588        12933 :     };
    1589              : 
    1590        13005 :     const GuitarBend* bendF = bendFor();
    1591        13005 :     bool startUnconnectedBend = bendF && !bendF->findPrecedingBend();
    1592        13005 :     bool startsNonBendSpanner = !spannerFor().empty() && !bendF;
    1593              : 
    1594        13005 :     bool chordHasDip = false;
    1595        31842 :     for (Note* note : chord()->notes()) {
    1596        18955 :         for (Spanner* sp : note->spannerFor()) {
    1597          118 :             if (sp->isGuitarBend() && toGuitarBend(sp)->bendType() == GuitarBendType::DIP) {
    1598            8 :                 chordHasDip = true;
    1599            8 :                 break;
    1600              :             }
    1601              :         }
    1602        18845 :         if (chordHasDip) {
    1603            8 :             break;
    1604              :         }
    1605              :     }
    1606              : 
    1607        25998 :     return !ch->articulations().empty() || ch->chordLine() || startsNonBendSpanner || startUnconnectedBend || hasTremoloBar()
    1608        25998 :            || hasVibratoLine() || chordHasDip;
    1609              : }
    1610              : 
    1611         5292 : void Note::setVisible(bool v)
    1612              : {
    1613         5292 :     EngravingItem::setVisible(v);
    1614         5292 :     if (!chord() || chord()->noteParentheses().empty()) {
    1615         5280 :         return;
    1616              :     }
    1617              : 
    1618           12 :     const NoteParenthesisInfo* noteParenInfo = chord()->findNoteParenthesisInfo(this);
    1619              : 
    1620           12 :     if (!noteParenInfo) {
    1621            0 :         return;
    1622              :     }
    1623              : 
    1624           12 :     const std::vector<Note*>& notes = noteParenInfo->notes();
    1625           12 :     bool visible = false;
    1626           22 :     for (const Note* note : notes) {
    1627           12 :         if (note->visible()) {
    1628            2 :             visible = true;
    1629            2 :             break;
    1630              :         }
    1631              :     }
    1632              : 
    1633           12 :     if (noteParenInfo->leftParen()) {
    1634           12 :         noteParenInfo->leftParen()->setVisible(visible);
    1635              :     }
    1636           12 :     if (noteParenInfo->rightParen()) {
    1637           12 :         noteParenInfo->rightParen()->setVisible(visible);
    1638              :     }
    1639              : }
    1640              : 
    1641          174 : bool Note::isExactUnison(Note* other)
    1642              : {
    1643          174 :     return other->pitch() == m_pitch && other->tpc() == tpc();
    1644              : }
    1645              : 
    1646        17619 : void Note::setupAfterRead(const Fraction& ctxTick, bool pasteMode)
    1647              : {
    1648              :     // ensure sane values:
    1649        17619 :     m_pitch = std::clamp(m_pitch, 0, 127);
    1650              : 
    1651        17619 :     if (!tpcIsValid(m_tpc[0]) && !tpcIsValid(m_tpc[1])) {
    1652            0 :         Key key = (staff() && chord()) ? staff()->key(chord()->tick()) : Key::C;
    1653            0 :         int tpc = pitch2tpc(m_pitch, key, Prefer::NEAREST);
    1654            0 :         if (concertPitch()) {
    1655            0 :             m_tpc[0] = tpc;
    1656              :         } else {
    1657            0 :             m_tpc[1] = tpc;
    1658              :         }
    1659              :     }
    1660        17619 :     if (!(tpcIsValid(m_tpc[0]) && tpcIsValid(m_tpc[1]))) {
    1661            0 :         Fraction tick = chord() ? chord()->tick() : Fraction(-1, 1);
    1662            0 :         Interval v = staff() ? staff()->transpose(tick) : Interval();
    1663            0 :         if (tpcIsValid(m_tpc[0])) {
    1664            0 :             v.flip();
    1665            0 :             if (v.isZero()) {
    1666            0 :                 m_tpc[1] = m_tpc[0];
    1667              :             } else {
    1668            0 :                 m_tpc[1] = Transpose::transposeTpc(m_tpc[0], v, true);
    1669              :             }
    1670              :         } else {
    1671            0 :             if (v.isZero()) {
    1672            0 :                 m_tpc[0] = m_tpc[1];
    1673              :             } else {
    1674            0 :                 m_tpc[0] = Transpose::transposeTpc(m_tpc[1], v, true);
    1675              :             }
    1676              :         }
    1677              :     }
    1678              : 
    1679              :     // check consistency of pitch, tpc1, tpc2, and transposition
    1680              :     // see note in InstrumentChange::read() about a known case of tpc corruption produced in 2.0.x
    1681              :     // but since there are other causes of tpc corruption (eg, https://musescore.org/en/node/74746)
    1682              :     // including perhaps some we don't know about yet,
    1683              :     // we will attempt to fix some problems here regardless of version
    1684              : 
    1685        17619 :     if (staff() && !staff()->isDrumStaff(ctxTick) && !pasteMode && !MScore::testMode) {
    1686            0 :         int tpc1Pitch = (tpc2pitch(m_tpc[0]) + 12) % 12;
    1687            0 :         int tpc2Pitch = (tpc2pitch(m_tpc[1]) + 12) % 12;
    1688            0 :         int soundingPitch = m_pitch % 12;
    1689            0 :         if (tpc1Pitch != soundingPitch) {
    1690            0 :             LOGD("bad tpc1 - soundingPitch = %d, tpc1 = %d", soundingPitch, tpc1Pitch);
    1691            0 :             m_pitch += tpc1Pitch - soundingPitch;
    1692              :         }
    1693            0 :         if (staff()) {
    1694            0 :             Interval v = staff()->transpose(ctxTick);
    1695            0 :             int writtenPitch = (m_pitch - v.chromatic) % 12;
    1696            0 :             if (tpc2Pitch != writtenPitch) {
    1697            0 :                 LOGD("bad tpc2 - writtenPitch = %d, tpc2 = %d", writtenPitch, tpc2Pitch);
    1698            0 :                 if (concertPitch()) {
    1699              :                     // assume we want to keep sounding pitch
    1700              :                     // so fix written pitch (tpc only)
    1701            0 :                     v.flip();
    1702            0 :                     m_tpc[1] = Transpose::transposeTpc(m_tpc[0], v, true);
    1703              :                 } else {
    1704              :                     // assume we want to keep written pitch
    1705              :                     // so fix sounding pitch (both tpc and pitch)
    1706            0 :                     m_tpc[0] = Transpose::transposeTpc(m_tpc[1], v, true);
    1707            0 :                     m_pitch += tpc2Pitch - writtenPitch;
    1708              :                 }
    1709              :             }
    1710              :         }
    1711              :     }
    1712              : 
    1713        17619 :     const StaffType* st = staffType();
    1714        17619 :     if (st && st->isTabStaff() && st->fretUseTextStyle() && color() == configuration()->defaultColor()) {
    1715           49 :         setColor(propertyDefault(Pid::COLOR).value<Color>());
    1716              :     }
    1717        17619 : }
    1718              : 
    1719              : //---------------------------------------------------------
    1720              : //   transposition
    1721              : //---------------------------------------------------------
    1722              : 
    1723       212207 : int Note::transposition() const
    1724              : {
    1725       212207 :     Fraction tick = chord() ? chord()->tick() : Fraction(-1, 1);
    1726       212207 :     Part* origin = originPart();
    1727       424414 :     return origin ? origin->instrument(tick)->transpose().chromatic : 0;
    1728              : }
    1729              : 
    1730              : //---------------------------------------------------------
    1731              : //   NoteEditData
    1732              : //---------------------------------------------------------
    1733              : 
    1734              : class NoteEditData : public ElementEditData
    1735              : {
    1736            0 :     OBJECT_ALLOCATOR(engraving, NoteEditData)
    1737              : public:
    1738              :     enum EditMode : unsigned char {
    1739              :         EditMode_ChangePitch = 0,
    1740              :         EditMode_AddSpacing,
    1741              :         EditMode_Undefined,
    1742              :     };
    1743              : 
    1744              :     int line = 0;
    1745              :     int string = 0;
    1746              :     EditMode mode = EditMode_Undefined;
    1747              :     PointF delta;
    1748              : 
    1749            0 :     virtual EditDataType type() override { return EditDataType::NoteEditData; }
    1750              : 
    1751              :     static constexpr double MODE_TRANSITION_LIMIT_DEGREES = 15.0;
    1752              : 
    1753            0 :     static inline EditMode editModeByDragDirection(const double& deltaX, const double& deltaY)
    1754              :     {
    1755            0 :         double x = std::abs(deltaX);
    1756            0 :         double y = std::abs(deltaY);
    1757              : 
    1758            0 :         PointF normalizedVector(x, y);
    1759              : 
    1760            0 :         normalizedVector.normalize();
    1761              : 
    1762            0 :         float radians = PointF::dotProduct(normalizedVector, PointF(1, 0));
    1763              : 
    1764            0 :         double degrees = (std::acos(radians) * 180.0) / M_PI;
    1765              : 
    1766            0 :         LOGD() << "NOTE DRAG DEGREES " << degrees;
    1767              : 
    1768            0 :         if (degrees >= MODE_TRANSITION_LIMIT_DEGREES) {
    1769            0 :             return NoteEditData::EditMode_ChangePitch;
    1770              :         } else {
    1771            0 :             return NoteEditData::EditMode_AddSpacing;
    1772              :         }
    1773              :     }
    1774              : };
    1775              : 
    1776              : //---------------------------------------------------------
    1777              : //   acceptDrop
    1778              : //---------------------------------------------------------
    1779              : 
    1780           18 : bool Note::acceptDrop(EditData& data) const
    1781              : {
    1782           18 :     EngravingItem* e = data.dropElement;
    1783           18 :     switch (e->type()) {
    1784            0 :     case ElementType::GLISSANDO:
    1785              :     case ElementType::GUITAR_BEND:
    1786            0 :         for (auto ee : m_spannerFor) {
    1787            0 :             if (ee->isGlissando() || ee->isGuitarBend()) {
    1788            0 :                 return false;
    1789              :             }
    1790              :         }
    1791            0 :         return true;
    1792            0 :     case ElementType::FINGERING:
    1793            0 :         return staff()->isTabStaff(tick()) ? staffType()->showTabFingering() : true;
    1794           10 :     case ElementType::ARTICULATION:
    1795              :     case ElementType::ORNAMENT:
    1796              :     case ElementType::TAPPING:
    1797              :     case ElementType::CHORDLINE:
    1798              :     case ElementType::TEXT:
    1799              :     case ElementType::ACCIDENTAL:
    1800              :     case ElementType::ARPEGGIO:
    1801              :     case ElementType::CHORD_BRACKET:
    1802              :     case ElementType::NOTEHEAD:
    1803              :     case ElementType::NOTE:
    1804              :     case ElementType::TREMOLO_SINGLECHORD:
    1805              :     case ElementType::TREMOLO_TWOCHORD:
    1806              :     case ElementType::IMAGE:
    1807              :     case ElementType::CHORD:
    1808              :     case ElementType::SYMBOL:
    1809              :     case ElementType::BAR_LINE:
    1810              :     case ElementType::STICKING:
    1811              :     case ElementType::BEND:
    1812              :     case ElementType::FIGURED_BASS:
    1813              :     case ElementType::LYRICS:
    1814           10 :         return true;
    1815            0 :     case ElementType::BAGPIPE_EMBELLISHMENT:
    1816            0 :         return noteType() == NoteType::NORMAL;
    1817            0 :     case ElementType::ACTION_ICON: {
    1818            0 :         switch (toActionIcon(e)->actionType()) {
    1819            0 :         case ActionIconType::ACCIACCATURA:
    1820              :         case ActionIconType::APPOGGIATURA:
    1821              :         case ActionIconType::GRACE4:
    1822              :         case ActionIconType::GRACE16:
    1823              :         case ActionIconType::GRACE32:
    1824              :         case ActionIconType::GRACE8_AFTER:
    1825              :         case ActionIconType::GRACE16_AFTER:
    1826              :         case ActionIconType::GRACE32_AFTER:
    1827              :         case ActionIconType::PARENTHESES:
    1828              :         case ActionIconType::STANDARD_BEND:
    1829              :         case ActionIconType::PRE_BEND:
    1830              :         case ActionIconType::GRACE_NOTE_BEND:
    1831              :         case ActionIconType::SLIGHT_BEND:
    1832              :         case ActionIconType::DIVE:
    1833              :         case ActionIconType::PRE_DIVE:
    1834              :         case ActionIconType::DIP:
    1835              :         case ActionIconType::SCOOP:
    1836              :         case ActionIconType::NOTE_ANCHORED_LINE:
    1837            0 :             return true;
    1838            0 :         default: break;
    1839              :         }
    1840            0 :         break;
    1841              :     }
    1842            8 :     default:
    1843            8 :         if (e->isSpanner()) {
    1844            0 :             return e->type() != ElementType::TIE && e->type() != ElementType::PARTIAL_TIE;
    1845              :         }
    1846            8 :         break;
    1847              :     }
    1848            8 :     return toChordRest(chord())->acceptDrop(data);
    1849              : }
    1850              : 
    1851              : //---------------------------------------------------------
    1852              : //   drop
    1853              : //---------------------------------------------------------
    1854              : 
    1855           48 : EngravingItem* Note::drop(Transaction& tx, EditData& data)
    1856              : {
    1857           48 :     EngravingItem* e = data.dropElement;
    1858              : 
    1859           48 :     const Staff* st = staff();
    1860           48 :     bool isTablature = st->isTabStaff(tick());
    1861           48 :     bool tabFingering = st->staffTypeForElement(this)->showTabFingering();
    1862           48 :     Chord* ch = chord();
    1863              : 
    1864           48 :     switch (e->type()) {
    1865            6 :     case ElementType::SYMBOL:
    1866              :     case ElementType::IMAGE:
    1867            6 :         e->setOwnershipParent(this);
    1868            6 :         score()->undoAddElement(e);
    1869            6 :         return e;
    1870              : 
    1871            3 :     case ElementType::FINGERING:
    1872            3 :         if (!isTablature || tabFingering) {
    1873            3 :             e->setOwnershipParent(this);
    1874            3 :             score()->undoAddElement(e);
    1875            3 :             return e;
    1876              :         } else {
    1877            0 :             delete e;
    1878              :         }
    1879            0 :         return 0;
    1880              : 
    1881            0 :     case ElementType::LYRICS:
    1882            0 :         e->setOwnershipParent(ch);
    1883            0 :         e->setTrack(track());
    1884            0 :         score()->undoAddElement(e);
    1885            0 :         return e;
    1886              : 
    1887            0 :     case ElementType::ACCIDENTAL:
    1888            0 :         EditNote::changeAccidental(score(), this, toAccidental(e)->accidentalType());
    1889            0 :         break;
    1890              : 
    1891            0 :     case ElementType::BEND:
    1892            0 :         e->setOwnershipParent(this);
    1893            0 :         e->setTrack(track());
    1894            0 :         score()->undoAddElement(e);
    1895            0 :         return e;
    1896              : 
    1897            0 :     case ElementType::NOTEHEAD:
    1898              :     {
    1899            0 :         NoteHead* s = toNoteHead(e);
    1900            0 :         NoteHeadGroup group = s->headGroup();
    1901            0 :         if (group == NoteHeadGroup::HEAD_INVALID) {
    1902            0 :             LOGD("unknown notehead");
    1903            0 :             group = NoteHeadGroup::HEAD_NORMAL;
    1904              :         }
    1905            0 :         delete s;
    1906              : 
    1907            0 :         if (group != m_headGroup) {
    1908            0 :             if (links()) {
    1909            0 :                 for (EngravingObject* se : *links()) {
    1910            0 :                     se->undoChangeProperty(Pid::HEAD_GROUP, group);
    1911            0 :                     Note* note = toNote(se);
    1912            0 :                     if (note->staff() && !note->staff()->isDrumStaff(ch->tick())) {
    1913            0 :                         se->undoChangeProperty(Pid::DEAD, group == NoteHeadGroup::HEAD_CROSS);
    1914              :                     }
    1915              :                 }
    1916              :             } else {
    1917            0 :                 undoChangeProperty(Pid::HEAD_GROUP, group);
    1918            0 :                 if (!staff()->isDrumStaff(ch->tick())) {
    1919            0 :                     undoChangeProperty(Pid::DEAD, group == NoteHeadGroup::HEAD_CROSS);
    1920              :                 }
    1921              :             }
    1922              :         }
    1923              :     }
    1924            0 :     break;
    1925              : 
    1926            0 :     case ElementType::ACTION_ICON:
    1927              :     {
    1928            0 :         switch (toActionIcon(e)->actionType()) {
    1929            0 :         case ActionIconType::ACCIACCATURA:
    1930              :         {
    1931            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::ACCIACCATURA, Constants::DIVISION / 2);
    1932            0 :             score()->select(note, SelectType::SINGLE, 0);
    1933            0 :             break;
    1934              :         }
    1935            0 :         case ActionIconType::APPOGGIATURA:
    1936              :         {
    1937            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::APPOGGIATURA, Constants::DIVISION / 2);
    1938            0 :             score()->select(note, SelectType::SINGLE, 0);
    1939            0 :             break;
    1940              :         }
    1941            0 :         case ActionIconType::GRACE4:
    1942              :         {
    1943            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::GRACE4, Constants::DIVISION);
    1944            0 :             score()->select(note, SelectType::SINGLE, 0);
    1945            0 :             break;
    1946              :         }
    1947            0 :         case ActionIconType::GRACE16:
    1948              :         {
    1949            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::GRACE16,  Constants::DIVISION / 4);
    1950            0 :             score()->select(note, SelectType::SINGLE, 0);
    1951            0 :             break;
    1952              :         }
    1953            0 :         case ActionIconType::GRACE32:
    1954              :         {
    1955            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::GRACE32, Constants::DIVISION / 8);
    1956            0 :             score()->select(note, SelectType::SINGLE, 0);
    1957            0 :             break;
    1958              :         }
    1959            0 :         case ActionIconType::GRACE8_AFTER:
    1960              :         {
    1961            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::GRACE8_AFTER, Constants::DIVISION / 2);
    1962            0 :             score()->select(note, SelectType::SINGLE, 0);
    1963            0 :             break;
    1964              :         }
    1965            0 :         case ActionIconType::GRACE16_AFTER:
    1966              :         {
    1967            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::GRACE16_AFTER, Constants::DIVISION / 4);
    1968            0 :             score()->select(note, SelectType::SINGLE, 0);
    1969            0 :             break;
    1970              :         }
    1971            0 :         case ActionIconType::GRACE32_AFTER:
    1972              :         {
    1973            0 :             Note* note = score()->setGraceNote(ch, pitch(), NoteType::GRACE32_AFTER, Constants::DIVISION / 8);
    1974            0 :             score()->select(note, SelectType::SINGLE, 0);
    1975            0 :             break;
    1976              :         }
    1977              : 
    1978            0 :         case ActionIconType::PARENTHESES: {
    1979            0 :             EditParentheses::addParenthesesToNotes(tx, { this });
    1980            0 :             break;
    1981              :         }
    1982            0 :         case ActionIconType::STANDARD_BEND:
    1983              :         case ActionIconType::SLIGHT_BEND:
    1984              :         case ActionIconType::DIVE:
    1985              :         case ActionIconType::DIP:
    1986              :         case ActionIconType::SCOOP:
    1987            0 :             score()->addGuitarBend(GuitarBend::bendTypeFromActionIcon(toActionIcon(e)->actionType()), this);
    1988            0 :             break;
    1989            0 :         case ActionIconType::PRE_BEND:
    1990              :         case ActionIconType::GRACE_NOTE_BEND:
    1991              :         case ActionIconType::PRE_DIVE:
    1992              :         {
    1993            0 :             GuitarBendType type = GuitarBend::bendTypeFromActionIcon(toActionIcon(e)->actionType());
    1994            0 :             GuitarBend* guitarBend = score()->addGuitarBend(type, this);
    1995            0 :             if (!guitarBend) {
    1996            0 :                 break;
    1997              :             }
    1998            0 :             Note* note = guitarBend->startNote();
    1999            0 :             IF_ASSERT_FAILED(note) {
    2000            0 :                 LOGE() << "not valid start note of the bend";
    2001            0 :                 break;
    2002              :             }
    2003              : 
    2004            0 :             score()->select(note, SelectType::SINGLE, 0);
    2005            0 :             break;
    2006              :         }
    2007            0 :         case mu::engraving::ActionIconType::NOTE_ANCHORED_LINE:
    2008            0 :             score()->addNoteLine();
    2009            0 :         default:
    2010            0 :             break;
    2011              :         }
    2012            0 :         return ch->drop(tx, data);
    2013              :     }
    2014              : 
    2015            0 :     case ElementType::GUITAR_BEND:
    2016              :     {
    2017            0 :         GuitarBend* newGuitarBend = score()->addGuitarBend(toGuitarBend(e)->bendType(), this);
    2018            0 :         delete e;
    2019            0 :         return newGuitarBend;
    2020              :     }
    2021              : 
    2022            0 :     case ElementType::BAGPIPE_EMBELLISHMENT:
    2023              :     {
    2024            0 :         BagpipeEmbellishment* b = toBagpipeEmbellishment(e);
    2025            0 :         BagpipeNoteList nl = b->resolveNoteList();
    2026              :         // add grace notes in reverse order, as setGraceNote adds a grace note
    2027              :         // before the current note
    2028            0 :         for (int i = static_cast<int>(nl.size()) - 1; i >= 0; --i) {
    2029            0 :             int p = BagpipeEmbellishment::BAGPIPE_NOTEINFO_LIST[nl.at(i)].pitch;
    2030            0 :             score()->setGraceNote(ch, p, NoteType::GRACE32, Constants::DIVISION / 8);
    2031              :         }
    2032            0 :     }
    2033            0 :         delete e;
    2034            0 :         break;
    2035              : 
    2036           14 :     case ElementType::NOTE:
    2037              :     {
    2038              :         // calculate correct transposed tpc
    2039           14 :         Note* n = toNote(e);
    2040           14 :         const Segment* segment = ch->segment();
    2041           14 :         Interval v = staff()->transpose(ch->tick());
    2042           14 :         v.flip();
    2043           14 :         n->setTpc2(Transpose::transposeTpc(n->tpc1(), v, true));
    2044              :         // replace this note with new note
    2045           14 :         n->setOwnershipParent(ch);
    2046           14 :         if (this->tieBack()) {
    2047            4 :             n->setTieBack(this->tieBack());
    2048            4 :             n->tieBack()->setEndNote(n);
    2049            4 :             this->setTieBack(nullptr);
    2050              :         }
    2051              :         // Set correct stem direction for drum staves
    2052           14 :         const StaffGroup staffGroup = st->staffType(segment->tick())->group();
    2053           14 :         DirectionV stemDirection = DirectionV::AUTO;
    2054           14 :         if (staffGroup == StaffGroup::PERCUSSION) {
    2055            2 :             const Drumset* ds = originPart()->instrument(segment->tick())->drumset();
    2056            2 :             DO_ASSERT(ds);
    2057              : 
    2058            2 :             if (ds) {
    2059            2 :                 stemDirection = ds->stemDirection(n->noteVal().pitch);
    2060              :             }
    2061              :         }
    2062           14 :         ch->setStemDirection(stemDirection);
    2063              : 
    2064           14 :         score()->undoRemoveElement(this);
    2065           14 :         score()->undoAddElement(n);
    2066           14 :         return n;
    2067              :     }
    2068              :     break;
    2069              : 
    2070           11 :     case ElementType::GLISSANDO:
    2071              :     {
    2072           11 :         for (auto ee : m_spannerFor) {
    2073            0 :             if (ee->isGlissando()) {
    2074            0 :                 LOGD("there is already a glissando");
    2075            0 :                 delete e;
    2076            0 :                 return 0;
    2077              :             }
    2078              :         }
    2079              : 
    2080           11 :         Glissando* gliss = toGlissando(e);
    2081           11 :         EngravingItem* endEl = gliss->endElement();
    2082           11 :         Note* finalNote = endEl && endEl->isNote() ? toNote(endEl) : SLine::guessFinalNote(this);
    2083           11 :         if (finalNote) {
    2084              :             // init glissando data
    2085           11 :             gliss->setStartElement(this);
    2086           11 :             gliss->setEndElement(finalNote);
    2087           11 :             gliss->setTick(ch->tick());
    2088           11 :             gliss->setTick2(finalNote->chord()->tick());
    2089           11 :             gliss->setTrack(track());
    2090           11 :             gliss->setTrack2(finalNote->track());
    2091              :             // in TAB, use straight line with no text
    2092           11 :             if (staff()->isTabStaff(finalNote->chord()->tick())) {
    2093            0 :                 gliss->setGlissandoType(GlissandoType::STRAIGHT);
    2094            0 :                 gliss->setShowText(false);
    2095              :             }
    2096           11 :             gliss->setOwnershipParent(this);
    2097              : 
    2098           11 :             const Sid styleId = gliss->getPropertyStyle(Pid::GLISS_STYLE);
    2099           11 :             if (gliss->isStyled(Pid::GLISS_STYLE) && score()->style().isDefault(styleId)) {
    2100           11 :                 const GlissandoStyle instrumentStyle = originPart()->instrument(gliss->tick())->glissandoStyle();
    2101           11 :                 if (instrumentStyle != gliss->glissandoStyle()) {
    2102            0 :                     gliss->setGlissandoStyle(instrumentStyle);
    2103            0 :                     gliss->setPropertyFlags(Pid::GLISS_STYLE, PropertyFlags::UNSTYLED);
    2104              :                 }
    2105              :             }
    2106              : 
    2107           11 :             score()->undoAddElement(e);
    2108              :         } else {
    2109            0 :             LOGD("no segment for second note of glissando found");
    2110            0 :             delete e;
    2111            0 :             return 0;
    2112              :         }
    2113              :     }
    2114           11 :     break;
    2115              : 
    2116            0 :     case ElementType::CHORD:
    2117              :     {
    2118            0 :         Chord* c      = toChord(e);
    2119            0 :         Note* n       = c->upNote();
    2120            0 :         DirectionV dir = c->stemDirection();
    2121            0 :         track_idx_t t = track(); // (staff2track(staffIdx()) + n->voice());
    2122            0 :         score()->select(0, SelectType::SINGLE, 0);
    2123            0 :         NoteVal nval;
    2124            0 :         nval.pitch = n->pitch();
    2125            0 :         nval.headGroup = n->headGroup();
    2126            0 :         const ChordRest* cr = nullptr;
    2127            0 :         if (data.modifiers & ShiftModifier) {
    2128              :             // add note to chord
    2129            0 :             NoteInput::addNote(tx, score(), ch, nval);
    2130              :         } else {
    2131              :             // replace current chord
    2132            0 :             Segment* seg = score()->setNoteRest(ch->segment(), t, nval,
    2133            0 :                                                 score()->inputState().duration().fraction(), dir);
    2134            0 :             cr = seg ? toChordRest(seg->element(t)) : nullptr;
    2135              :         }
    2136            0 :         if (cr) {
    2137            0 :             NoteInput::nextInputPos(tx, score(), cr, false);
    2138              :         }
    2139            0 :         delete e;
    2140              :     }
    2141            0 :     break;
    2142              : 
    2143            3 :     case ElementType::CHORDLINE:
    2144            3 :         toChordLine(e)->setNote(this);
    2145            3 :         return ch->drop(tx, data);
    2146              : 
    2147           11 :     default:
    2148              :         Spanner* spanner;
    2149           11 :         if (e->isSpanner() && (spanner = toSpanner(e))->anchor() == Spanner::Anchor::NOTE) {
    2150            0 :             spanner->setOwnershipParent(this);
    2151            0 :             spanner->setStartElement(this);
    2152            0 :             spanner->setTick(tick());
    2153            0 :             spanner->setTrack(track());
    2154            0 :             spanner->setTrack2(track());
    2155            0 :             spanner->computeEndElement();
    2156            0 :             score()->undoAddElement(spanner);
    2157            0 :             return e;
    2158              :         }
    2159           11 :         return ch->drop(tx, data);
    2160              :     }
    2161           11 :     return 0;
    2162              : }
    2163              : 
    2164              : //---------------------------------------------------------
    2165              : //   dotIsUp
    2166              : //---------------------------------------------------------
    2167              : 
    2168            0 : bool Note::dotIsUp() const
    2169              : {
    2170            0 :     if (m_dots.empty()) {
    2171            0 :         return true;
    2172              :     }
    2173            0 :     if (m_userDotPosition == DirectionV::AUTO) {
    2174            0 :         return m_dots[0]->y() < spatium() * .1;
    2175              :     } else {
    2176            0 :         return m_userDotPosition == DirectionV::UP;
    2177              :     }
    2178              : }
    2179              : 
    2180        52491 : static bool hasAlteredUnison(Note* note)
    2181              : {
    2182        52491 :     const auto& chordNotes = note->chord()->notes();
    2183        52491 :     AccidentalVal accVal = tpc2alter(note->tpc());
    2184        52491 :     int absLine = absStep(note->tpc(), note->epitch());
    2185        52491 :     return std::find_if(chordNotes.begin(), chordNotes.end(), [note, accVal, absLine](Note* n) {
    2186        89303 :         return n != note && !n->hidden() && absStep(n->tpc(), n->epitch()) == absLine && tpc2alter(n->tpc()) != accVal;
    2187       104982 :     }) != chordNotes.end();
    2188              : }
    2189              : 
    2190              : //---------------------------------------------------------
    2191              : //   updateAccidental
    2192              : //    set _accidental and _line depending on tpc
    2193              : //---------------------------------------------------------
    2194              : 
    2195        56332 : void Note::updateAccidental(AccidentalState* as)
    2196              : {
    2197        56332 :     if (deadNote() && configuration()->keepDeadNotesUnchangedOnTranspose()) {
    2198            0 :         if (m_accidental) {
    2199            0 :             score()->undoRemoveElement(m_accidental);
    2200              :         }
    2201            0 :         int eAbsLine = absStep(tpc(), epitch());
    2202            0 :         as->setAccidentalVal(eAbsLine, tpc2alter(tpc()), false);
    2203            0 :         updateRelLine(eAbsLine, true);
    2204            0 :         return;
    2205              :     }
    2206              : 
    2207        56332 :     int absLine = absStep(tpc(), epitch());
    2208              : 
    2209              :     // Ensure m_centOffset and microtonal accidental match (they can mismatch when switching from TAB)
    2210        56332 :     if (muse::RealIsNull(m_centOffset)) {
    2211        56249 :         if (m_accidental && !muse::RealIsNull(Accidental::subtype2centOffset(m_accidental->accidentalType()))) {
    2212            0 :             score()->undoRemoveElement(m_accidental);
    2213              :         }
    2214              :     } else {
    2215           83 :         if (m_accidental) {
    2216           83 :             bool correct = muse::RealIsEqual(Accidental::subtype2centOffset(m_accidental->accidentalType()), m_centOffset);
    2217           83 :             if (!correct) {
    2218            0 :                 m_accidental->undoChangeProperty(Pid::ACCIDENTAL_TYPE, static_cast<int>(Accidental::centOffset2Subtype(m_centOffset)));
    2219              :             }
    2220              :         } else {
    2221            0 :             AccidentalType accType = Accidental::value2MicrotonalSubtype(tpc2alter(tpc()), quarterToneOffset());
    2222            0 :             updateLine();
    2223            0 :             EditNote::changeAccidental(score(), this, accType);
    2224              :         }
    2225              :     }
    2226              : 
    2227              :     // don't touch accidentals that don't concern tpc such as
    2228              :     // quarter tones
    2229        56332 :     if (!(m_accidental && Accidental::isMicrotonal(m_accidental->accidentalType()))) {
    2230              :         // calculate accidental
    2231        56246 :         AccidentalType acci = AccidentalType::NONE;
    2232              : 
    2233        56246 :         AccidentalVal accVal = tpc2alter(tpc());
    2234        56246 :         bool error = false;
    2235        56246 :         int eAbsLine = absStep(tpc(), epitch());
    2236        56246 :         AccidentalVal absLineAccVal = as->accidentalVal(eAbsLine, error);
    2237        56246 :         if (error) {
    2238            0 :             LOGD("error accidentalVal()");
    2239            0 :             return;
    2240              :         }
    2241        56246 :         if ((accVal != absLineAccVal) || hidden() || as->tieContext(eAbsLine) || as->forceRestateAccidental(eAbsLine)) {
    2242         3755 :             as->setAccidentalVal(eAbsLine, accVal, m_tieBack != 0 && m_accidental == 0);
    2243         3755 :             acci = Accidental::value2subtype(accVal);
    2244              :             // if previous tied note has same tpc, don't show accidental
    2245         3755 :             if (tieBackNonPartial() && m_tieBack->startNote()->tpc1() == tpc1()) {
    2246           45 :                 acci = AccidentalType::NONE;
    2247         3710 :             } else if (acci == AccidentalType::NONE) {
    2248          585 :                 acci = AccidentalType::NATURAL;
    2249              :             }
    2250        52491 :         } else if (hasAlteredUnison(this)) {
    2251            3 :             if ((acci = Accidental::value2subtype(accVal)) == AccidentalType::NONE) {
    2252            3 :                 acci = AccidentalType::NATURAL;
    2253              :             }
    2254              :         }
    2255        56246 :         if (acci != AccidentalType::NONE && !m_hidden) {
    2256         3713 :             if (m_accidental == 0) {
    2257         1908 :                 Accidental* a = Factory::createAccidental(this);
    2258         1908 :                 a->setAccidentalType(acci);
    2259         1908 :                 a->setVisible(visible());
    2260         1908 :                 score()->undoAddElement(a);
    2261         1805 :             } else if (m_accidental->accidentalType() != acci) {
    2262          100 :                 Accidental* a = m_accidental->clone();
    2263          100 :                 a->setOwnershipParent(this);
    2264          100 :                 a->setAccidentalType(acci);
    2265          100 :                 score()->undoChangeElement(m_accidental, a);
    2266              :             }
    2267         3713 :         } else {
    2268        52533 :             if (m_accidental) {
    2269              :                 // remove this if it was AUTO:
    2270         1804 :                 if (m_accidental->role() == AccidentalRole::AUTO) {
    2271         1621 :                     score()->undoRemoveElement(m_accidental);
    2272              :                 } else {
    2273              :                     // keep it, but update type if needed
    2274          183 :                     acci = Accidental::value2subtype(accVal);
    2275          183 :                     if (acci == AccidentalType::NONE) {
    2276          142 :                         acci = AccidentalType::NATURAL;
    2277              :                     }
    2278          183 :                     if (m_accidental->accidentalType() != acci) {
    2279           15 :                         Accidental* a = m_accidental->clone();
    2280           15 :                         a->setOwnershipParent(this);
    2281           15 :                         a->setAccidentalType(acci);
    2282           15 :                         score()->undoChangeElement(m_accidental, a);
    2283              :                     }
    2284              :                 }
    2285              :             }
    2286              :         }
    2287              :     } else {
    2288              :         // microtonal accidentals playback as naturals
    2289              :         // in 1.X, they had no effect on accidental state of measure
    2290              :         // ultimately, they should probably get their own state
    2291              :         // for now, at least change state to natural, so subsequent notes playback as might be expected
    2292              :         // this is an incompatible change, but better to break it for 2.0 than wait until later
    2293           86 :         AccidentalVal accVal = Accidental::subtype2value(m_accidental->accidentalType());
    2294           86 :         as->setAccidentalVal(absLine, accVal, m_tieBack != 0 && m_accidental == 0);
    2295              :     }
    2296              : 
    2297        56332 :     as->setForceRestateAccidental(absLine, false);
    2298        56332 :     updateRelLine(absLine, true);
    2299              : }
    2300              : 
    2301              : //---------------------------------------------------------
    2302              : //   noteType
    2303              : //---------------------------------------------------------
    2304              : 
    2305      1458026 : NoteType Note::noteType() const
    2306              : {
    2307      1458026 :     return chord()->noteType();
    2308              : }
    2309              : 
    2310              : //---------------------------------------------------------
    2311              : //   noteTypeUserName
    2312              : //---------------------------------------------------------
    2313              : 
    2314            0 : String Note::noteTypeUserName() const
    2315              : {
    2316            0 :     switch (noteType()) {
    2317            0 :     case NoteType::ACCIACCATURA:
    2318            0 :         return muse::mtrc("engraving", "Acciaccatura");
    2319            0 :     case NoteType::APPOGGIATURA:
    2320            0 :         return muse::mtrc("engraving", "Appoggiatura");
    2321            0 :     case NoteType::GRACE8_AFTER:
    2322              :     case NoteType::GRACE16_AFTER:
    2323              :     case NoteType::GRACE32_AFTER:
    2324            0 :         return muse::mtrc("engraving", "Grace note after");
    2325            0 :     case NoteType::GRACE4:
    2326              :     case NoteType::GRACE16:
    2327              :     case NoteType::GRACE32:
    2328            0 :         return muse::mtrc("engraving", "Grace note before");
    2329            0 :     default:
    2330            0 :         return muse::mtrc("engraving", "Note");
    2331              :     }
    2332              : }
    2333              : 
    2334              : //---------------------------------------------------------
    2335              : //   scanElements
    2336              : //---------------------------------------------------------
    2337              : 
    2338        18716 : void Note::scanElements(std::function<void(EngravingItem*)> func)
    2339              : {
    2340        18716 :     func(this);
    2341              : 
    2342        18826 :     for (EngravingItem* e : m_el) {
    2343          110 :         e->scanElements(func);
    2344              :     }
    2345        18793 :     for (Spanner* sp : m_spannerFor) {
    2346           77 :         sp->scanElements(func);
    2347              :     }
    2348              : 
    2349        18716 :     if (m_accidental) {
    2350          791 :         func(m_accidental);
    2351              :     }
    2352        19009 :     for (NoteDot* dot : m_dots) {
    2353          293 :         func(dot);
    2354              :     }
    2355        18716 : }
    2356              : 
    2357              : //---------------------------------------------------------
    2358              : //   setTrack
    2359              : //---------------------------------------------------------
    2360              : 
    2361        79899 : void Note::setTrack(track_idx_t val)
    2362              : {
    2363        79899 :     EngravingItem::setTrack(val);
    2364        79899 :     if (tieForNonPartial()) {
    2365          526 :         m_tieFor->setTrack(val);
    2366         1020 :         for (SpannerSegment* seg : m_tieFor->spannerSegments()) {
    2367          494 :             seg->setTrack(val);
    2368              :         }
    2369              :     }
    2370        79899 :     if (tieBackNonPartial()) {
    2371          220 :         m_tieBack->setTrack2(val);
    2372              :     }
    2373        79899 :     if (laissezVib() || outgoingPartialTie()) {
    2374           27 :         m_tieFor->setTrack(val);
    2375           27 :         m_tieFor->setTrack2(val);
    2376           31 :         for (SpannerSegment* seg : m_tieFor->spannerSegments()) {
    2377            4 :             seg->setTrack(val);
    2378              :         }
    2379              :     }
    2380        79899 :     if (incomingPartialTie()) {
    2381           31 :         m_tieBack->setTrack(val);
    2382           31 :         m_tieBack->setTrack2(val);
    2383           33 :         for (SpannerSegment* seg : m_tieBack->spannerSegments()) {
    2384            2 :             seg->setTrack(val);
    2385              :         }
    2386              :     }
    2387        80051 :     for (Spanner* s : m_spannerFor) {
    2388          152 :         s->setTrack(val);
    2389              :     }
    2390        80090 :     for (Spanner* s : m_spannerBack) {
    2391          191 :         s->setTrack2(val);
    2392              :     }
    2393        80129 :     for (EngravingItem* e : m_el) {
    2394          230 :         e->setTrack(val);
    2395              :     }
    2396        79899 :     if (m_accidental) {
    2397         4878 :         m_accidental->setTrack(val);
    2398              :     }
    2399        79899 :     if (!chord()) {     // if note is dragged with shift+ctrl
    2400           30 :         return;
    2401              :     }
    2402        79952 :     for (NoteDot* dot : m_dots) {
    2403           83 :         dot->setTrack(val);
    2404              :     }
    2405              : }
    2406              : 
    2407              : //---------------------------------------------------------
    2408              : //    reset
    2409              : //---------------------------------------------------------
    2410              : 
    2411            0 : void Note::reset()
    2412              : {
    2413            0 :     undoChangeProperty(Pid::OFFSET, PointF());
    2414            0 :     undoResetProperty(Pid::LEADING_SPACE);
    2415            0 :     chord()->undoChangeProperty(Pid::OFFSET, PropertyValue::fromValue(PointF()));
    2416            0 :     chord()->undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::AUTO));
    2417            0 :     setOverrideBendVisibilityRules(false);
    2418            0 :     setHideGeneratedParens(false);
    2419            0 : }
    2420              : 
    2421         1558 : float Note::userVelocityFraction() const
    2422              : {
    2423         1558 :     return m_userVelocity / 127.f;
    2424              : }
    2425              : 
    2426              : //---------------------------------------------------------
    2427              : //   mag
    2428              : //---------------------------------------------------------
    2429              : 
    2430      3620060 : double Note::mag() const
    2431              : {
    2432      3620060 :     double m = chord() ? chord()->mag() : 1.0;
    2433      3620060 :     if (m_isSmall) {
    2434         2861 :         m *= style().styleD(Sid::smallNoteMag);
    2435              :     }
    2436      3620060 :     return m;
    2437              : }
    2438              : 
    2439              : //---------------------------------------------------------
    2440              : //   elementBase
    2441              : //---------------------------------------------------------
    2442            0 : EngravingItem* Note::elementBase() const
    2443              : {
    2444            0 :     return chord();
    2445              : }
    2446              : 
    2447              : //---------------------------------------------------------
    2448              : //   setSmall
    2449              : //---------------------------------------------------------
    2450              : 
    2451         5327 : void Note::setSmall(bool val)
    2452              : {
    2453         5327 :     m_isSmall = val;
    2454         5327 : }
    2455              : 
    2456        36589 : GuitarBend* Note::bendFor() const
    2457              : {
    2458              :     /// Returns bend or dive going forward from this note. In the edge case of having both, returns the bend.
    2459        36589 :     GuitarBend* diveFor = nullptr;
    2460              : 
    2461        39708 :     for (Spanner* sp : m_spannerFor) {
    2462         5325 :         if (!sp->isGuitarBend()) {
    2463          189 :             continue;
    2464              :         }
    2465              : 
    2466         5136 :         GuitarBend* bend = toGuitarBend(sp);
    2467         5136 :         if (bend->bendType() == GuitarBendType::SCOOP) {
    2468            6 :             continue;
    2469              :         }
    2470              : 
    2471         5130 :         if (!bend->isDive()) {
    2472         2206 :             return bend;
    2473              :         } else {
    2474         2924 :             diveFor = bend;
    2475              :         }
    2476              :     }
    2477              : 
    2478        34383 :     return diveFor;
    2479              : }
    2480              : 
    2481        28065 : GuitarBend* Note::bendBack() const
    2482              : {
    2483              :     /// Returns bend or dive going back from this note. In the edge case of having both, returns the bend.
    2484        28065 :     GuitarBend* diveBack = nullptr;
    2485              : 
    2486        30272 :     for (Spanner* sp : m_spannerBack) {
    2487         4875 :         if (!sp->isGuitarBend()) {
    2488          181 :             continue;
    2489              :         }
    2490              : 
    2491         4694 :         GuitarBend* bend = toGuitarBend(sp);
    2492         4694 :         if (bend->bendType() == GuitarBendType::SLIGHT_BEND || bend->bendType() == GuitarBendType::DIP) {
    2493          223 :             continue;
    2494              :         }
    2495              : 
    2496         4471 :         if (!bend->isDive()) {
    2497         2668 :             return bend;
    2498              :         } else {
    2499         1803 :             diveBack = bend;
    2500              :         }
    2501              :     }
    2502              : 
    2503        25397 :     return diveBack;
    2504              : }
    2505              : 
    2506         1176 : GuitarBend* Note::diveFor() const
    2507              : {
    2508         2306 :     for (Spanner* sp : m_spannerFor) {
    2509         1130 :         if (sp->isGuitarBend() && toGuitarBend(sp)->isDive() && toGuitarBend(sp)->bendType() != GuitarBendType::SCOOP) {
    2510            0 :             return toGuitarBend(sp);
    2511              :         }
    2512              :     }
    2513              : 
    2514         1176 :     return nullptr;
    2515              : }
    2516              : 
    2517         6167 : GuitarBend* Note::diveBack() const
    2518              : {
    2519         7890 :     for (Spanner* sp : m_spannerBack) {
    2520         2844 :         if (sp->isGuitarBend() && toGuitarBend(sp)->isDive() && toGuitarBend(sp)->bendType() != GuitarBendType::DIP) {
    2521         1121 :             return toGuitarBend(sp);
    2522              :         }
    2523              :     }
    2524              : 
    2525         5046 :     return nullptr;
    2526              : }
    2527              : 
    2528        86229 : Tie* Note::tieForNonPartial() const
    2529              : {
    2530        86229 :     if (!m_tieFor || m_tieFor->type() != ElementType::TIE) {
    2531        85515 :         return nullptr;
    2532              :     }
    2533              : 
    2534          714 :     return m_tieFor;
    2535              : }
    2536              : 
    2537       166710 : Tie* Note::tieBackNonPartial() const
    2538              : {
    2539       166710 :     if (!m_tieBack || m_tieBack->type() != ElementType::TIE) {
    2540       163613 :         return nullptr;
    2541              :     }
    2542              : 
    2543         3097 :     return m_tieBack;
    2544              : }
    2545              : 
    2546       566578 : LaissezVib* Note::laissezVib() const
    2547              : {
    2548       566578 :     if (!m_tieFor || !m_tieFor->isLaissezVib()) {
    2549       566253 :         return nullptr;
    2550              :     }
    2551              : 
    2552          325 :     return toLaissezVib(m_tieFor);
    2553              : }
    2554              : 
    2555       144751 : PartialTie* Note::incomingPartialTie() const
    2556              : {
    2557       144751 :     if (!m_tieBack || !m_tieBack->isPartialTie()) {
    2558       144335 :         return nullptr;
    2559              :     }
    2560              : 
    2561          416 :     return toPartialTie(m_tieBack);
    2562              : }
    2563              : 
    2564       120343 : PartialTie* Note::outgoingPartialTie() const
    2565              : {
    2566       120343 :     if (!m_tieFor || !m_tieFor->isPartialTie()) {
    2567       120272 :         return nullptr;
    2568              :     }
    2569              : 
    2570           71 :     return toPartialTie(m_tieFor);
    2571              : }
    2572              : 
    2573         3519 : void Note::setTieFor(Tie* t)
    2574              : {
    2575         3519 :     if (!t) {
    2576         1365 :         m_jumpPoints.clear();
    2577              :     }
    2578         3519 :     m_tieFor = t;
    2579         3519 :     if (m_tieFor && !m_tieFor->isLaissezVib()) {
    2580         2133 :         m_tieFor->updatePossibleJumpPoints();
    2581              :     }
    2582         3519 : }
    2583              : 
    2584         3201 : void Note::setTieBack(Tie* t)
    2585              : {
    2586         3201 :     if (m_tieBack && t && m_tieBack->jumpPoint()) {
    2587            0 :         t->setJumpPoint(m_tieBack->jumpPoint());
    2588            0 :         m_tieBack->setJumpPoint(nullptr);
    2589              :     }
    2590         3201 :     m_tieBack = t;
    2591         3201 : }
    2592              : 
    2593              : //---------------------------------------------------------
    2594              : //   line
    2595              : //---------------------------------------------------------
    2596              : 
    2597      1250292 : int Note::line() const
    2598              : {
    2599      1250292 :     return fixed() ? m_fixedLine : m_line;
    2600              : }
    2601              : 
    2602              : //---------------------------------------------------------
    2603              : //   setHeadScheme
    2604              : //---------------------------------------------------------
    2605              : 
    2606           70 : void Note::setHeadScheme(NoteHeadScheme val)
    2607              : {
    2608           70 :     IF_ASSERT_FAILED(int(val) >= -1 && int(val) < int(NoteHeadScheme::HEAD_SCHEMES)) {
    2609            0 :         val = NoteHeadScheme::HEAD_AUTO;
    2610              :     }
    2611           70 :     m_headScheme = val;
    2612           70 : }
    2613              : 
    2614              : //---------------------------------------------------------
    2615              : //   setHeadGroup
    2616              : //---------------------------------------------------------
    2617              : 
    2618         8108 : void Note::setHeadGroup(NoteHeadGroup val)
    2619              : {
    2620         8108 :     assert(int(val) >= 0 && int(val) < int(NoteHeadGroup::HEAD_GROUPS));
    2621         8108 :     m_headGroup = val;
    2622         8108 : }
    2623              : 
    2624              : //---------------------------------------------------------
    2625              : //   ottaveCapoFret
    2626              : //    offset added by Ottava's and Capo Fret.
    2627              : //---------------------------------------------------------
    2628              : 
    2629        13002 : int Note::ottaveCapoFret() const
    2630              : {
    2631        13002 :     const Chord* ch = chord();
    2632        13002 :     Fraction segmentTick = ch->segment()->tick();
    2633        13002 :     const Staff* staff = this->staff();
    2634              : 
    2635        13002 :     const CapoParams& capo = staff->capo(segmentTick);
    2636        13002 :     int capoFret = 0;
    2637              : 
    2638              :     using MODE = CapoParams::TransposeMode;
    2639        13002 :     if (capo.active && MODE::PLAYBACK_ONLY == capo.transposeMode) {
    2640            0 :         if (capo.ignoredStrings.empty() || !muse::contains(capo.ignoredStrings, static_cast<string_idx_t>(m_string))) {
    2641            0 :             capoFret = capo.fretPosition;
    2642              :         }
    2643              :     }
    2644              : 
    2645        26004 :     return staff->pitchOffset(segmentTick) + capoFret;
    2646              : }
    2647              : 
    2648              : //---------------------------------------------------------
    2649              : //   ppitch
    2650              : //    playback pitch
    2651              : //---------------------------------------------------------
    2652              : 
    2653        10186 : int Note::ppitch() const
    2654              : {
    2655        10186 :     const Chord* ch = chord();
    2656              : 
    2657              :     // if staff is drum
    2658              :     // match tremolo and articulation between variants and chord
    2659        10186 :     if (m_play && ch) {
    2660        10127 :         const Staff* staff = ch->staff();
    2661        10127 :         Fraction tick = ch->tick();
    2662              : 
    2663        10127 :         if (staff && staff->isDrumStaff(tick)) {
    2664          105 :             const Drumset* ds = originPart()->instrument(tick)->drumset();
    2665          105 :             if (ds) {
    2666          105 :                 DrumInstrumentVariant div = ds->findVariant(m_pitch, ch->articulations(), ch->tremoloType());
    2667          105 :                 if (div.pitch != INVALID_PITCH) {
    2668            0 :                     return div.pitch;
    2669              :                 }
    2670          105 :             }
    2671              :         }
    2672              :     }
    2673              : 
    2674        10186 :     return m_pitch + ottaveCapoFret() + linkedOttavaPitchOffset();
    2675              : }
    2676              : 
    2677              : //---------------------------------------------------------
    2678              : //   epitch
    2679              : //    effective pitch, i.e. a pitch which is visible in the
    2680              : //    currently used written notation.
    2681              : //    honours transposing instruments
    2682              : //---------------------------------------------------------
    2683              : 
    2684       211529 : int Note::epitch() const
    2685              : {
    2686       211529 :     return m_pitch - (concertPitch() ? 0 : transposition()) + linkedOttavaPitchOffset();
    2687              : }
    2688              : 
    2689              : //---------------------------------------------------------
    2690              : //   linkedOttavaPitchOffset
    2691              : //    if an ottava exists in another part but has been excluded
    2692              : //    from this one, this returns the corresponding pitch offset
    2693              : //---------------------------------------------------------
    2694              : 
    2695       221715 : int Note::linkedOttavaPitchOffset() const
    2696              : {
    2697       221715 :     int linkedOttavaPitchOffset = 0;
    2698       221715 :     if (links() && staff()->pitchOffset(tick()) == 0) {
    2699        36095 :         for (EngravingObject* link : *links()) {
    2700        24188 :             int offset = toNote(link)->staff()->pitchOffset(tick());
    2701        24188 :             if (offset != 0) {
    2702            0 :                 linkedOttavaPitchOffset = offset;
    2703            0 :                 break;
    2704              :             }
    2705              :         }
    2706              :     }
    2707       221715 :     return linkedOttavaPitchOffset;
    2708              : }
    2709              : 
    2710              : //---------------------------------------------------------
    2711              : //   octave
    2712              : //    compute octave number from note information
    2713              : //---------------------------------------------------------
    2714              : 
    2715         1242 : int Note::octave() const
    2716              : {
    2717         1242 :     return ((epitch() + ottaveCapoFret() - static_cast<int>(tpc2alter(tpc()))) / 12) - 1;
    2718              : }
    2719              : 
    2720         1574 : int Note::playingOctave() const
    2721              : {
    2722         1574 :     return mu::engraving::playingOctave(ppitch(), tpc1());
    2723              : }
    2724              : 
    2725         1558 : double Note::playingTuning() const
    2726              : {
    2727         1558 :     return m_tuning + m_centOffset;
    2728              : }
    2729              : 
    2730              : //---------------------------------------------------------
    2731              : //   customizeVelocity
    2732              : //    Input is the global velocity determined by dynamic
    2733              : //    signs and crescendo/diminuendo etc.
    2734              : //    Returns the actual play velocity for this note
    2735              : //    modified by veloOffset
    2736              : //---------------------------------------------------------
    2737              : 
    2738            0 : int Note::customizeVelocity(int velo) const
    2739              : {
    2740            0 :     if (m_veloType == VeloType::OFFSET_VAL) {
    2741            0 :         velo = velo + (velo * userVelocity()) / 100;
    2742            0 :     } else if (m_veloType == VeloType::USER_VAL) {
    2743            0 :         velo = userVelocity();
    2744              :     }
    2745            0 :     return std::clamp(velo, 1, 127);
    2746              : }
    2747              : 
    2748              : //---------------------------------------------------------
    2749              : //   startDrag
    2750              : //---------------------------------------------------------
    2751              : 
    2752            0 : void Note::startDrag(EditData& ed)
    2753              : {
    2754            0 :     std::shared_ptr<NoteEditData> ned = std::make_shared<NoteEditData>();
    2755            0 :     ned->e      = this;
    2756            0 :     ned->line   = m_line;
    2757            0 :     ned->string = m_string;
    2758            0 :     ned->pushProperty(Pid::PITCH);
    2759            0 :     ned->pushProperty(Pid::TPC1);
    2760            0 :     ned->pushProperty(Pid::TPC2);
    2761            0 :     ned->pushProperty(Pid::FRET);
    2762            0 :     ned->pushProperty(Pid::STRING);
    2763              : 
    2764            0 :     ed.addData(ned);
    2765            0 : }
    2766              : 
    2767              : //---------------------------------------------------------
    2768              : //   drag
    2769              : //---------------------------------------------------------
    2770              : 
    2771            0 : RectF Note::drag(EditData& ed)
    2772              : {
    2773            0 :     NoteEditData* noteEditData = static_cast<NoteEditData*>(ed.getData(this).get());
    2774            0 :     IF_ASSERT_FAILED(noteEditData) {
    2775            0 :         return RectF();
    2776              :     }
    2777              : 
    2778            0 :     if (ed.isEditMode) {
    2779            0 :         dragInEditMode(ed);
    2780            0 :         return RectF();
    2781              :     }
    2782              : 
    2783            0 :     PointF delta = ed.evtDelta;
    2784            0 :     noteEditData->delta = delta;
    2785              : 
    2786            0 :     if (noteEditData->mode == NoteEditData::EditMode_Undefined) {
    2787            0 :         noteEditData->mode = NoteEditData::editModeByDragDirection(delta.x(), delta.y());
    2788              :     }
    2789              : 
    2790            0 :     bool isSingleNoteSelection = score()->getSelectedElement() == this;
    2791            0 :     if (noteEditData->mode == NoteEditData::EditMode_AddSpacing && isSingleNoteSelection && !(ed.modifiers & ControlModifier)) {
    2792            0 :         horizontalDrag(ed);
    2793            0 :     } else if (noteEditData->mode == NoteEditData::EditMode_ChangePitch) {
    2794            0 :         verticalDrag(ed);
    2795              :     }
    2796              : 
    2797            0 :     return RectF();
    2798              : }
    2799              : 
    2800              : //---------------------------------------------------------
    2801              : //   endDrag
    2802              : //---------------------------------------------------------
    2803              : 
    2804            0 : void Note::endDrag(EditData& ed)
    2805              : {
    2806            0 :     NoteEditData* ned = static_cast<NoteEditData*>(ed.getData(this).get());
    2807            0 :     IF_ASSERT_FAILED(ned) {
    2808            0 :         return;
    2809              :     }
    2810            0 :     for (Note* nn : tiedNotes()) {
    2811            0 :         for (const auto& [id, data, flags] : ned->propertyData) {
    2812            0 :             setPropertyFlags(id, flags); // reset initial property flags state
    2813            0 :             score()->undoPropertyChanged(nn, id, data);
    2814              :         }
    2815            0 :     }
    2816              : }
    2817              : 
    2818              : //---------------------------------------------------------
    2819              : //   dragInEditMode
    2820              : //---------------------------------------------------------
    2821              : 
    2822            0 : void Note::dragInEditMode(EditData& editData)
    2823              : {
    2824            0 :     Chord* ch = chord();
    2825            0 :     Segment* seg = ch->segment();
    2826              : 
    2827            0 :     if (editData.modifiers & ShiftModifier) {
    2828            0 :         const Spatium deltaSp = Spatium(editData.delta.x() / spatium());
    2829            0 :         seg->undoChangeProperty(Pid::LEADING_SPACE, seg->extraLeadingSpace() + deltaSp);
    2830            0 :     } else if (ch->notes().size() == 1) {
    2831              :         // if the chord contains only this note, then move the whole chord
    2832              :         // including stem, flag etc.
    2833            0 :         ch->undoChangeProperty(Pid::OFFSET, PropertyValue::fromValue(ch->offset() + offset() + editData.evtDelta));
    2834            0 :         setOffset(PointF());
    2835              :     } else {
    2836            0 :         setOffset(offset() + editData.evtDelta);
    2837              :     }
    2838              : 
    2839            0 :     triggerLayout();
    2840            0 : }
    2841              : 
    2842              : //---------------------------------------------------------
    2843              : //   verticalDrag
    2844              : //---------------------------------------------------------
    2845              : 
    2846            0 : void Note::verticalDrag(EditData& ed)
    2847              : {
    2848            0 :     Fraction _tick = chord()->tick();
    2849            0 :     if (originPart()->instrument(_tick)->useDrumset()) {
    2850            0 :         return;
    2851              :     }
    2852              : 
    2853            0 :     NoteEditData* ned   = static_cast<NoteEditData*>(ed.getData(this).get());
    2854              : 
    2855            0 :     const bool tab = staffType()->isTabStaff();
    2856            0 :     double step    = spatium() * staffType()->lineDistance().val() * (tab ? 1.0 : 0.5);
    2857            0 :     int lineOffset = lrint(ed.moveDelta.y() / step);
    2858              : 
    2859            0 :     if (tab) {
    2860            0 :         const StringData* strData = originPart()->stringData(_tick, staffIdx());
    2861            0 :         const int pitchOffset = staff()->pitchOffset(_tick);
    2862            0 :         int nString = ned->string + (staffType()->upsideDown() ? -lineOffset : lineOffset);
    2863            0 :         int nFret   = strData->fret(m_pitch + pitchOffset, nString, staff(), tick());
    2864              : 
    2865            0 :         if (nFret >= 0) {                        // no fret?
    2866            0 :             if (fret() != nFret || string() != nString) {
    2867            0 :                 for (Note* nn : tiedNotes()) {
    2868            0 :                     nn->setFret(nFret);
    2869            0 :                     nn->setString(nString);
    2870            0 :                     strData->fretChords(nn->chord());
    2871            0 :                     nn->triggerLayout();
    2872            0 :                 }
    2873              :             }
    2874              :         }
    2875              :     } else {
    2876            0 :         staff_idx_t idx = chord()->vStaffIdx();
    2877            0 :         bool error = false;
    2878            0 :         AccidentalVal accOffs = firstTiedNote()->chord()->measure()->findAccidental(
    2879            0 :             firstTiedNote()->chord()->segment(), idx, ned->line + lineOffset, error);
    2880            0 :         if (error) {
    2881            0 :             accOffs = Accidental::subtype2value(AccidentalType::NONE);
    2882              :         }
    2883            0 :         int nStep = absStep(ned->line + lineOffset, score()->staff(idx)->clef(_tick));
    2884            0 :         nStep = std::max(0, nStep);
    2885            0 :         int octave = nStep / STEP_DELTA_OCTAVE;
    2886            0 :         int newPitch = step2pitch(nStep) + octave * PITCH_DELTA_OCTAVE + int(accOffs);
    2887              : 
    2888            0 :         int newTpc1 = step2tpc(nStep % STEP_DELTA_OCTAVE, accOffs);
    2889            0 :         int newTpc2 = newTpc1;
    2890            0 :         if (concertPitch()) {
    2891            0 :             newTpc2 = transposeTpc(newTpc1);
    2892              :         } else {
    2893            0 :             newPitch += staff()->transpose(_tick).chromatic;
    2894            0 :             newTpc1 = transposeTpc(newTpc2);
    2895              :         }
    2896              : 
    2897            0 :         int clampedPitch = clampPitch(newPitch);
    2898            0 :         if (clampedPitch != newPitch) {
    2899              :             // newTpc1/newTpc2 were derived from a step/accidental that no longer
    2900              :             // matches the clamped pitch; respell them so tpc and pitch stay in sync
    2901            0 :             Key key = score()->staff(idx)->key(_tick);
    2902            0 :             if (concertPitch()) {
    2903            0 :                 newTpc1 = pitch2tpc(clampedPitch, key, Prefer::NEAREST);
    2904            0 :                 newTpc2 = transposeTpc(newTpc1);
    2905              :             } else {
    2906            0 :                 newTpc2 = pitch2tpc(clampedPitch - staff()->transpose(_tick).chromatic, key, Prefer::NEAREST);
    2907            0 :                 newTpc1 = transposeTpc(newTpc2);
    2908              :             }
    2909            0 :             newPitch = clampedPitch;
    2910              :         }
    2911              : 
    2912            0 :         for (Note* nn : tiedNotes()) {
    2913            0 :             nn->setAccidentalType(AccidentalType::NONE);
    2914            0 :             nn->setPitch(newPitch, newTpc1, newTpc2);
    2915            0 :             nn->triggerLayout();
    2916            0 :         }
    2917              :     }
    2918            0 :     score()->inputState().setAccidentalType(AccidentalType::NONE);
    2919              : }
    2920              : 
    2921              : //---------------------------------------------------------
    2922              : //   normalizeLeftDragDelta
    2923              : //---------------------------------------------------------
    2924              : 
    2925            0 : void Note::normalizeLeftDragDelta(Segment* seg, EditData& ed, NoteEditData* ned)
    2926              : {
    2927            0 :     Segment* previous = seg->prev();
    2928              : 
    2929            0 :     if (previous) {
    2930            0 :         double minDist = HorizontalSpacing::minHorizontalDistance(previous, seg, 1.0);
    2931              : 
    2932            0 :         double diff = (ed.pos.x()) - (previous->pageX() + minDist);
    2933              : 
    2934            0 :         double distanceBetweenSegments = (previous->pageX() + minDist) - seg->pageX();
    2935              : 
    2936            0 :         if (diff < 0) {
    2937            0 :             ned->delta.setX(distanceBetweenSegments);
    2938              :         }
    2939              :     } else {
    2940            0 :         Measure* measure = seg->measure();
    2941              : 
    2942            0 :         double minDist = style().styleAbsolute(Sid::barNoteDistance);
    2943              : 
    2944            0 :         double diff = (ed.pos.x()) - (measure->pageX() + minDist);
    2945              : 
    2946            0 :         double distanceBetweenSegments = (measure->pageX() + minDist) - seg->pageX();
    2947              : 
    2948            0 :         if (diff < 0) {
    2949            0 :             ned->delta.setX(distanceBetweenSegments);
    2950              :         }
    2951              :     }
    2952            0 : }
    2953              : 
    2954              : //---------------------------------------------------------
    2955              : //   horizontalDrag
    2956              : //---------------------------------------------------------
    2957              : 
    2958            0 : void Note::horizontalDrag(EditData& ed)
    2959              : {
    2960            0 :     Chord* ch = chord();
    2961            0 :     Segment* seg = ch->segment();
    2962              : 
    2963            0 :     NoteEditData* ned = static_cast<NoteEditData*>(ed.getData(this).get());
    2964              : 
    2965            0 :     if (ed.moveDelta.x() < 0) {
    2966            0 :         normalizeLeftDragDelta(seg, ed, ned);
    2967              :     }
    2968              : 
    2969            0 :     const Spatium deltaSp = Spatium(ned->delta.x() / spatium());
    2970              : 
    2971            0 :     if (seg->extraLeadingSpace() + deltaSp < 0_sp) {
    2972            0 :         return;
    2973              :     }
    2974              : 
    2975            0 :     seg->undoChangeProperty(Pid::LEADING_SPACE, seg->extraLeadingSpace() + deltaSp);
    2976              : 
    2977            0 :     triggerLayout();
    2978              : }
    2979              : 
    2980              : //---------------------------------------------------------
    2981              : //   updateRelLine
    2982              : //    calculate the real note line depending on clef,
    2983              : //    absLine is the absolute line
    2984              : //---------------------------------------------------------
    2985              : 
    2986        56827 : void Note::updateRelLine(int absLine, bool undoable)
    2987              : {
    2988        56827 :     if (!staff()) {
    2989            0 :         return;
    2990              :     }
    2991              :     // int idx      = staffIdx() + chord()->staffMove();
    2992        56827 :     assert(staffIdx() == chord()->staffIdx());
    2993        56827 :     staff_idx_t idx      = chord()->vStaffIdx();
    2994              : 
    2995        56827 :     const Staff* staff  = score()->staff(idx);
    2996        56827 :     const StaffType* st = staff->staffTypeForElement(this);
    2997        56827 :     if (st->isTabStaff()) {
    2998              :         // tab staff is already correct, and the following relStep method doesn't apply whatsoever to tab staves
    2999            1 :         return;
    3000              :     }
    3001        56826 :     ClefType clef = staff->clef(chord()->tick());
    3002        56826 :     int line      = relStep(absLine, clef);
    3003              : 
    3004        56826 :     if (undoable && (m_line != INVALID_LINE) && (line != m_line)) {
    3005          726 :         undoChangeProperty(Pid::LINE, line);
    3006              :     } else {
    3007        56100 :         setLine(line);
    3008              :     }
    3009              : 
    3010        56826 :     int off  = st->stepOffset();
    3011        56826 :     double ld = st->lineDistance().val();
    3012        56826 :     mutldata()->setPosY((m_line + off * 2.0) * spatium() * .5 * ld);
    3013              : }
    3014              : 
    3015              : //---------------------------------------------------------
    3016              : //   updateLine
    3017              : //---------------------------------------------------------
    3018              : 
    3019          495 : void Note::updateLine()
    3020              : {
    3021          495 :     int absLine = absStep(tpc(), epitch());
    3022          495 :     updateRelLine(absLine, false);
    3023          495 : }
    3024              : 
    3025              : //---------------------------------------------------------
    3026              : //   setNval
    3027              : //    set note properties from NoteVal
    3028              : //---------------------------------------------------------
    3029              : 
    3030         5227 : void Note::setNval(const NoteVal& nval, Fraction tick)
    3031              : {
    3032         5227 :     setPitch(nval.pitch);
    3033         5227 :     m_userVelocity = nval.velocityOverride;
    3034         5227 :     m_fret   = nval.fret;
    3035         5227 :     m_string = nval.string;
    3036              : 
    3037         5227 :     m_tpc[0] = nval.tpc1;
    3038         5227 :     m_tpc[1] = nval.tpc2;
    3039              : 
    3040         5227 :     if (tick == Fraction(-1, 1) && chord()) {
    3041         1657 :         tick = chord()->tick();
    3042              :     }
    3043         5227 :     Interval v = staff()->transpose(tick);
    3044         5227 :     if (nval.tpc1 == Tpc::TPC_INVALID) {
    3045         3327 :         if (nval.tpc2 == Tpc::TPC_INVALID) {
    3046         1142 :             Key key = staff()->concertKey(tick);
    3047         1142 :             m_tpc[0] = pitch2tpc(nval.pitch, key, Prefer::NEAREST);
    3048              :         } else {
    3049         2185 :             if (v.isZero()) {
    3050         2060 :                 m_tpc[0] = m_tpc[1];
    3051              :             } else {
    3052          125 :                 m_tpc[0] = Transpose::transposeTpc(m_tpc[1], v, true);
    3053              :             }
    3054              :         }
    3055              :     }
    3056         5227 :     if (nval.tpc2 == Tpc::TPC_INVALID) {
    3057         1286 :         if (v.isZero()) {
    3058         1142 :             m_tpc[1] = m_tpc[0];
    3059              :         } else {
    3060          144 :             v.flip();
    3061          144 :             m_tpc[1] = Transpose::transposeTpc(m_tpc[0], v, true);
    3062              :         }
    3063              :     }
    3064              : 
    3065         5227 :     m_headGroup = NoteHeadGroup(nval.headGroup);
    3066         5227 : }
    3067              : 
    3068              : //---------------------------------------------------------
    3069              : //   localSpatiumChanged
    3070              : //---------------------------------------------------------
    3071              : 
    3072            0 : void Note::localSpatiumChanged(double oldValue, double newValue)
    3073              : {
    3074            0 :     EngravingItem::localSpatiumChanged(oldValue, newValue);
    3075            0 :     for (EngravingItem* e : dots()) {
    3076            0 :         e->localSpatiumChanged(oldValue, newValue);
    3077              :     }
    3078            0 :     for (EngravingItem* e : el()) {
    3079            0 :         e->localSpatiumChanged(oldValue, newValue);
    3080              :     }
    3081            0 :     for (Spanner* spanner : spannerBack()) {
    3082            0 :         for (auto k : spanner->spannerSegments()) {
    3083            0 :             k->localSpatiumChanged(oldValue, newValue);
    3084              :         }
    3085              :     }
    3086            0 : }
    3087              : 
    3088              : //---------------------------------------------------------
    3089              : //   getProperty
    3090              : //---------------------------------------------------------
    3091              : 
    3092       721938 : PropertyValue Note::getProperty(Pid propertyId) const
    3093              : {
    3094       721938 :     switch (propertyId) {
    3095        23580 :     case Pid::PITCH:
    3096        23580 :         return pitch();
    3097        23580 :     case Pid::CENT_OFFSET:
    3098        23580 :         return centOffset();
    3099        47355 :     case Pid::TPC1:
    3100        47355 :         return m_tpc[0];
    3101        24020 :     case Pid::TPC2:
    3102        24020 :         return m_tpc[1];
    3103        23580 :     case Pid::SMALL:
    3104        23580 :         return isSmall();
    3105        23580 :     case Pid::MIRROR_HEAD:
    3106        23580 :         return userMirror();
    3107        23580 :     case Pid::DOT_POSITION:
    3108        23580 :         return PropertyValue::fromValue<DirectionV>(userDotPosition());
    3109        23580 :     case Pid::HEAD_SCHEME:
    3110        23580 :         return headScheme();
    3111        26235 :     case Pid::HEAD_GROUP:
    3112        26235 :         return headGroup();
    3113        23580 :     case Pid::USER_VELOCITY:
    3114        23580 :         return userVelocity();
    3115        23580 :     case Pid::TUNING:
    3116        23580 :         return tuning();
    3117        24141 :     case Pid::FRET:
    3118        24141 :         return fret();
    3119        24134 :     case Pid::STRING:
    3120        24134 :         return string();
    3121        23580 :     case Pid::GHOST:
    3122        23580 :         return ghost();
    3123        23580 :     case Pid::DEAD:
    3124        23580 :         return deadNote();
    3125        23580 :     case Pid::HEAD_TYPE:
    3126        23580 :         return headType();
    3127            0 :     case Pid::VELO_TYPE:
    3128            0 :         return m_veloType;
    3129        23993 :     case Pid::PLAY:
    3130        23993 :         return play();
    3131         2325 :     case Pid::LINE:
    3132         2325 :         return m_line;
    3133        23924 :     case Pid::FIXED:
    3134        23924 :         return fixed();
    3135        23924 :     case Pid::FIXED_LINE:
    3136        23924 :         return fixedLine();
    3137        27623 :     case Pid::HAS_PARENTHESES:
    3138        27623 :         return m_hasParens ? ParenthesesMode::BOTH : ParenthesesMode::NONE;
    3139        23701 :     case Pid::HIDE_GENERATED_PARENTHESES:
    3140        23701 :         return m_hideGeneratedParens;
    3141        47192 :     case Pid::POSITION_LINKED_TO_MASTER:
    3142              :     case Pid::APPEARANCE_LINKED_TO_MASTER:
    3143        47192 :         if (chord()) {
    3144        47192 :             return EngravingItem::getProperty(propertyId).toBool() && chord()->getProperty(propertyId).toBool();
    3145              :         }
    3146              :     default:
    3147       143991 :         break;
    3148              :     }
    3149       143991 :     return EngravingItem::getProperty(propertyId);
    3150              : }
    3151              : 
    3152              : //---------------------------------------------------------
    3153              : //   setProperty
    3154              : //---------------------------------------------------------
    3155              : 
    3156         3575 : bool Note::setProperty(Pid propertyId, const PropertyValue& v)
    3157              : {
    3158         3575 :     Measure* m = chord() ? chord()->measure() : nullptr;
    3159         3575 :     switch (propertyId) {
    3160            1 :     case Pid::PITCH:
    3161            1 :         setPitch(v.toInt());
    3162            1 :         break;
    3163            0 :     case Pid::CENT_OFFSET:
    3164            0 :         setCentOffset(v.toDouble());
    3165            0 :         break;
    3166           67 :     case Pid::TPC1:
    3167           67 :         m_tpc[0] = v.toInt();
    3168           67 :         break;
    3169          143 :     case Pid::TPC2:
    3170          143 :         m_tpc[1] = v.toInt();
    3171          143 :         break;
    3172          873 :     case Pid::LINE:
    3173          873 :         setLine(v.toInt());
    3174          873 :         break;
    3175            2 :     case Pid::SMALL:
    3176            2 :         setSmall(v.toBool());
    3177            2 :         break;
    3178            7 :     case Pid::MIRROR_HEAD:
    3179            7 :         setUserMirror(v.value<DirectionH>());
    3180            7 :         break;
    3181            7 :     case Pid::DOT_POSITION:
    3182            7 :         setUserDotPosition(v.value<DirectionV>());
    3183            7 :         break;
    3184            6 :     case Pid::HEAD_SCHEME:
    3185            6 :         setHeadScheme(v.value<NoteHeadScheme>());
    3186            6 :         break;
    3187          753 :     case Pid::HEAD_GROUP:
    3188          753 :         setHeadGroup(v.value<NoteHeadGroup>());
    3189          753 :         if (links()) {
    3190            0 :             for (EngravingObject* scoreElement : *links()) {
    3191            0 :                 Note* note = toNote(scoreElement);
    3192            0 :                 note->setDeadNote(staff() && !staff()->isDrumStaff(tick()) && m_headGroup == NoteHeadGroup::HEAD_CROSS);
    3193            0 :                 note->setHeadGroup(m_headGroup);
    3194              :             }
    3195              :         } else {
    3196          753 :             setDeadNote(staff() && !staff()->isDrumStaff(tick()) && m_headGroup == NoteHeadGroup::HEAD_CROSS);
    3197          753 :             setHeadGroup(m_headGroup);
    3198              :         }
    3199          753 :         break;
    3200            1 :     case Pid::USER_VELOCITY:
    3201            1 :         setUserVelocity(v.toInt());
    3202            1 :         break;
    3203            1 :     case Pid::TUNING:
    3204            1 :         setTuning(v.toDouble());
    3205            1 :         break;
    3206          167 :     case Pid::FRET:
    3207          167 :         setFret(v.toInt());
    3208          167 :         break;
    3209          158 :     case Pid::STRING:
    3210          158 :         setString(v.toInt());
    3211          158 :         break;
    3212            2 :     case Pid::GHOST:
    3213            2 :         setGhost(v.toBool());
    3214            2 :         break;
    3215            0 :     case Pid::DEAD:
    3216            0 :         setDeadNote(v.toBool());
    3217            0 :         if (!staff()->isDrumStaff(tick())) {
    3218            0 :             NoteHeadGroup head
    3219            0 :                 = (m_deadNote && m_headGroup != NoteHeadGroup::HEAD_CROSS) ? NoteHeadGroup::HEAD_CROSS : NoteHeadGroup::HEAD_NORMAL;
    3220            0 :             setHeadGroup(head);
    3221              :         }
    3222            0 :         break;
    3223          118 :     case Pid::HEAD_TYPE:
    3224          118 :         setHeadType(v.value<NoteHeadType>());
    3225          118 :         break;
    3226            3 :     case Pid::VELO_TYPE:
    3227            3 :         m_veloType = v.value<VeloType>();
    3228            3 :         break;
    3229           79 :     case Pid::VISIBLE: {
    3230           79 :         setVisible(v.toBool());
    3231           79 :         if (m) {
    3232           79 :             m->checkMultiVoices(chord()->staffIdx());
    3233              :         }
    3234           79 :         break;
    3235              :     }
    3236          164 :     case Pid::PLAY:
    3237          164 :         setPlay(v.toBool());
    3238          164 :         break;
    3239          164 :     case Pid::FIXED:
    3240          164 :         setFixed(v.toBool());
    3241          164 :         break;
    3242          164 :     case Pid::FIXED_LINE:
    3243          164 :         setFixedLine(v.toInt());
    3244          164 :         break;
    3245          165 :     case Pid::HAS_PARENTHESES:
    3246          165 :         if (v.value<ParenthesesMode>() != ParenthesesMode::BOTH && v.value<ParenthesesMode>() != ParenthesesMode::NONE) {
    3247            0 :             ASSERT_X("Notes cannot set left & right parens individually");
    3248              :         }
    3249          165 :         m_hasParens = v.value<ParenthesesMode>() == ParenthesesMode::BOTH;
    3250          165 :         break;
    3251           53 :     case Pid::HIDE_GENERATED_PARENTHESES:
    3252           53 :         setHideGeneratedParens(v.toBool());
    3253           53 :         break;
    3254           32 :     case Pid::POSITION_LINKED_TO_MASTER:
    3255              :     case Pid::APPEARANCE_LINKED_TO_MASTER:
    3256           32 :         if (v.toBool() == true && chord()) {
    3257              :             // when re-linking, also re-link the parent chord
    3258            0 :             chord()->setProperty(propertyId, v);
    3259              :         }
    3260              :     // fall through
    3261              :     default:
    3262          477 :         if (!EngravingItem::setProperty(propertyId, v)) {
    3263            0 :             return false;
    3264              :         }
    3265          477 :         break;
    3266              :     }
    3267         3575 :     triggerLayout();
    3268         3575 :     return true;
    3269              : }
    3270              : 
    3271              : //---------------------------------------------------------
    3272              : //   propertyDefault
    3273              : //---------------------------------------------------------
    3274              : 
    3275       683940 : PropertyValue Note::propertyDefault(Pid propertyId) const
    3276              : {
    3277       683940 :     switch (propertyId) {
    3278        23580 :     case Pid::CENT_OFFSET:
    3279        23580 :         return 0.0;
    3280        70740 :     case Pid::GHOST:
    3281              :     case Pid::DEAD:
    3282              :     case Pid::SMALL:
    3283        70740 :         return false;
    3284        23580 :     case Pid::MIRROR_HEAD:
    3285        23580 :         return DirectionH::AUTO;
    3286        23580 :     case Pid::DOT_POSITION:
    3287        23580 :         return DirectionV::AUTO;
    3288        23580 :     case Pid::HEAD_SCHEME:
    3289        23580 :         return NoteHeadScheme::HEAD_AUTO;
    3290        23580 :     case Pid::HEAD_GROUP:
    3291        23580 :         return NoteHeadGroup::HEAD_NORMAL;
    3292        23580 :     case Pid::USER_VELOCITY:
    3293        23580 :         return 0;
    3294        23580 :     case Pid::TUNING:
    3295        23580 :         return 0.0;
    3296        47160 :     case Pid::FRET:
    3297              :     case Pid::STRING:
    3298        47160 :         return -1;
    3299        23580 :     case Pid::HEAD_TYPE:
    3300        23580 :         return NoteHeadType::HEAD_AUTO;
    3301            0 :     case Pid::VELO_TYPE:
    3302            0 :         return VeloType::USER_VAL;
    3303        23580 :     case Pid::PLAY:
    3304        23580 :         return true;
    3305        23580 :     case Pid::FIXED:
    3306        23580 :         return false;
    3307        23580 :     case Pid::FIXED_LINE:
    3308        23580 :         return 0;
    3309        23580 :     case Pid::TPC2:
    3310        23580 :         return getProperty(Pid::TPC1);
    3311        47160 :     case Pid::PITCH:
    3312              :     case Pid::TPC1:
    3313        47160 :         return PropertyValue();
    3314        23580 :     case Pid::VISIBLE:
    3315        23580 :         if (staffType() && staffType()->isTabStaff()) {
    3316          401 :             GuitarBend* bend = bendBack();
    3317          401 :             if (bend && !bend->isFullRelease()) {
    3318            0 :                 return false;
    3319              :             }
    3320              :         }
    3321        23580 :         return EngravingItem::propertyDefault(propertyId);
    3322        23629 :     case Pid::COLOR: {
    3323        23629 :         const StaffType* st = staffType();
    3324        23629 :         if (st && st->isTabStaff() && st->fretUseTextStyle()) {
    3325          448 :             return style().styleV(Sid::tabFretNumberColor);
    3326              :         }
    3327        23181 :         return EngravingItem::propertyDefault(propertyId);
    3328              :     }
    3329        23580 :     case Pid::HIDE_GENERATED_PARENTHESES:
    3330        23580 :         return false;
    3331       165131 :     default:
    3332       165131 :         break;
    3333              :     }
    3334       165131 :     return EngravingItem::propertyDefault(propertyId);
    3335              : }
    3336              : 
    3337          562 : void Note::styleChanged()
    3338              : {
    3339          562 :     const StaffType* st = staffType();
    3340          562 :     if (st && st->isTabStaff() && st->fretUseTextStyle()) {
    3341            0 :         setProperty(Pid::COLOR, style().styleV(Sid::tabFretNumberColor));
    3342              :     }
    3343          562 :     EngravingItem::styleChanged();
    3344          562 : }
    3345              : 
    3346              : //---------------------------------------------------------
    3347              : //   setHeadType
    3348              : //---------------------------------------------------------
    3349              : 
    3350          214 : void Note::setHeadType(NoteHeadType t)
    3351              : {
    3352          214 :     m_headType = t;
    3353          214 : }
    3354              : 
    3355              : //---------------------------------------------------------
    3356              : //   setOnTimeOffset
    3357              : //---------------------------------------------------------
    3358              : 
    3359            0 : void Note::setOnTimeOffset(int val)
    3360              : {
    3361            0 :     m_playEvents[0].setOntime(val);
    3362            0 :     chord()->setPlayEventType(PlayEventType::User);
    3363            0 : }
    3364              : 
    3365              : //---------------------------------------------------------
    3366              : //   setOffTimeOffset
    3367              : //---------------------------------------------------------
    3368              : 
    3369            0 : void Note::setOffTimeOffset(int val)
    3370              : {
    3371            0 :     m_playEvents[0].setLen(val - m_playEvents[0].ontime());
    3372            0 :     chord()->setPlayEventType(PlayEventType::User);
    3373            0 : }
    3374              : 
    3375              : //---------------------------------------------------------
    3376              : //   setScore
    3377              : //---------------------------------------------------------
    3378              : 
    3379         5574 : void Note::setScore(Score* s)
    3380              : {
    3381         5574 :     EngravingItem::setScore(s);
    3382         5574 :     if (m_tieFor) {
    3383           83 :         m_tieFor->setScore(s);
    3384              :     }
    3385         5574 :     if (m_accidental) {
    3386           32 :         m_accidental->setScore(s);
    3387              :     }
    3388         5603 :     for (NoteDot* dot : m_dots) {
    3389           29 :         dot->setScore(s);
    3390              :     }
    3391         5599 :     for (EngravingItem* el : m_el) {
    3392           25 :         el->setScore(s);
    3393              :     }
    3394         5574 : }
    3395              : 
    3396              : //---------------------------------------------------------
    3397              : //   accessibleInfo
    3398              : //---------------------------------------------------------
    3399              : 
    3400            0 : String Note::accessibleInfo() const
    3401              : {
    3402            0 :     if (!chord() || !staff()) {
    3403            0 :         return String();
    3404              :     }
    3405              : 
    3406            0 :     String duration = chord()->durationUserName();
    3407            0 :     String voice = muse::mtrc("engraving", "Voice: %1").arg(track() % VOICES + 1);
    3408            0 :     String pitchName;
    3409            0 :     String onofftime;
    3410            0 :     if (!m_playEvents.empty()) {
    3411            0 :         int on = m_playEvents[0].ontime();
    3412            0 :         int off = m_playEvents[0].offtime();
    3413            0 :         if (on != 0 || off != NoteEvent::NOTE_LENGTH) {
    3414              :             //: Note-on and note-off times relative to note duration, expressed in thousandths (per mille)
    3415            0 :             onofftime = u" " + muse::mtrc("engraving", "(on %1‰ off %2‰)").arg(on, off);
    3416              :         }
    3417              :     }
    3418              : 
    3419            0 :     const Drumset* drumset = originPart()->instrument(chord()->tick())->drumset();
    3420            0 :     if (fixed() && headGroup() == NoteHeadGroup::HEAD_SLASH) {
    3421            0 :         pitchName = chord()->noStem() ? muse::mtrc("engraving", "Beat slash") : muse::mtrc("engraving", "Rhythm slash");
    3422            0 :     } else if (staff()->isDrumStaff(tick()) && drumset) {
    3423            0 :         pitchName = drumset->translatedName(pitch());
    3424            0 :     } else if (staff()->isTabStaff(tick())) {
    3425            0 :         pitchName = muse::mtrc("engraving", "%1; String: %2; Fret: %3")
    3426            0 :                     .arg(tpcUserName(false), String::number(string() + 1), String::number(fret()));
    3427              :     } else {
    3428            0 :         pitchName = tpcUserName(false);
    3429              :     }
    3430              : 
    3431            0 :     return muse::mtrc("engraving", "%1; Pitch: %2; Duration: %3%4%5")
    3432            0 :            .arg(noteTypeUserName(), pitchName, duration, onofftime, (chord()->isGrace() ? u"" : String(u"; %1").arg(voice)));
    3433            0 : }
    3434              : 
    3435              : //---------------------------------------------------------
    3436              : //   screenReaderInfo
    3437              : //---------------------------------------------------------
    3438              : 
    3439            0 : String Note::screenReaderInfo() const
    3440              : {
    3441            0 :     const Part* part = originPart();
    3442            0 :     if (!part) {
    3443            0 :         return String(); // part is nullptr on Linux after an instrument is deleted.
    3444              :     }
    3445              : 
    3446            0 :     const Fraction tick = this->tick();
    3447            0 :     const Chord* chord = this->chord();
    3448            0 :     const Instrument* instrument = part->instrument(tick);
    3449              : 
    3450            0 :     IF_ASSERT_FAILED(chord && instrument) {
    3451            0 :         return String();
    3452              :     }
    3453              : 
    3454            0 :     String duration = chord->durationUserName();
    3455            0 :     Measure* m = chord->measure();
    3456            0 :     bool voices = m ? m->hasVoices(staffIdx()) : false;
    3457            0 :     String voice = voices ? muse::mtrc("engraving", "Voice: %1").arg(track() % VOICES + 1) : u"";
    3458            0 :     String pitchName;
    3459            0 :     String pitchOutOfRangeWarning;
    3460            0 :     if (fixed() && headGroup() == NoteHeadGroup::HEAD_SLASH) {
    3461            0 :         pitchName = chord->noStem() ? muse::mtrc("engraving", "Beat slash") : muse::mtrc("engraving", "Rhythm slash");
    3462            0 :     } else if (const Drumset* d = instrument->drumset(); d&& instrument->useDrumset()) {
    3463            0 :         pitchName = d->translatedName(m_pitch);
    3464            0 :     } else if (const Staff* staff = this->staff(); staff&& staff->isTabStaff(tick)) {
    3465            0 :         pitchName = muse::mtrc("engraving", "%1; String: %2; Fret: %3")
    3466            0 :                     .arg(tpcUserName(true, true), String::number(string() + 1), String::number(fret()));
    3467              :     } else {
    3468            0 :         pitchName = m_headGroup == NoteHeadGroup::HEAD_NORMAL
    3469            0 :                     ? tpcUserName(true, true)
    3470              :                     //: head as in note head. %1 is head type (circle, cross, etc.). %2 is pitch (e.g. Db4).
    3471            0 :                     : muse::mtrc("engraving", "%1 head %2").arg(translatedSubtypeUserName()).arg(tpcUserName(true));
    3472            0 :         if (chord->staffMove() < 0) {
    3473            0 :             duration += u"; " + muse::mtrc("engraving", "Cross-staff above");
    3474            0 :         } else if (chord->staffMove() > 0) {
    3475            0 :             duration += u"; " + muse::mtrc("engraving", "Cross-staff below");
    3476              :         }
    3477              : 
    3478            0 :         if (m_pitch < instrument->minPitchP()) {
    3479            0 :             pitchOutOfRangeWarning = u" " + muse::mtrc("engraving", "too low");
    3480            0 :         } else if (m_pitch > instrument->maxPitchP()) {
    3481            0 :             pitchOutOfRangeWarning = u" " + muse::mtrc("engraving", "too high");
    3482            0 :         } else if (m_pitch < instrument->minPitchA()) {
    3483            0 :             pitchOutOfRangeWarning = u" " + muse::mtrc("engraving", "too low for amateurs");
    3484            0 :         } else if (m_pitch > instrument->maxPitchA()) {
    3485            0 :             pitchOutOfRangeWarning = u" " + muse::mtrc("engraving", "too high for amateurs");
    3486              :         }
    3487              :     }
    3488            0 :     return String(u"%1 %2 %3%4%5").arg(noteTypeUserName(), pitchName, duration, pitchOutOfRangeWarning,
    3489            0 :                                        (chord->isGrace() ? u"" : String(u"; %1").arg(voice)));
    3490            0 : }
    3491              : 
    3492              : //---------------------------------------------------------
    3493              : //   accessibleExtraInfo
    3494              : //---------------------------------------------------------
    3495              : 
    3496            0 : String Note::accessibleExtraInfo() const
    3497              : {
    3498            0 :     String rez;
    3499            0 :     if (accidental()) {
    3500            0 :         rez = String(u"%1 %2").arg(rez, accidental()->screenReaderInfo());
    3501              :     }
    3502            0 :     if (!el().empty()) {
    3503            0 :         for (EngravingItem* e : el()) {
    3504            0 :             if (!score()->selectionFilter().canSelect(e)) {
    3505            0 :                 continue;
    3506              :             }
    3507            0 :             rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
    3508              :         }
    3509              :     }
    3510            0 :     if (tieFor()) {
    3511            0 :         rez += u" " + muse::mtrc("engraving", "Start of %1").arg(tieFor()->screenReaderInfo());
    3512              :     }
    3513              : 
    3514            0 :     if (tieBack()) {
    3515            0 :         rez += u" " + muse::mtrc("engraving", "End of %1").arg(tieBack()->screenReaderInfo());
    3516              :     }
    3517              : 
    3518            0 :     if (!spannerFor().empty()) {
    3519            0 :         for (Spanner* s : spannerFor()) {
    3520            0 :             if (!score()->selectionFilter().canSelect(s)) {
    3521            0 :                 continue;
    3522              :             }
    3523            0 :             rez += u" " + muse::mtrc("engraving", "Start of %1").arg(s->screenReaderInfo());
    3524              :         }
    3525              :     }
    3526            0 :     if (!spannerBack().empty()) {
    3527            0 :         for (Spanner* s : spannerBack()) {
    3528            0 :             if (!score()->selectionFilter().canSelect(s)) {
    3529            0 :                 continue;
    3530              :             }
    3531            0 :             rez += u" " + muse::mtrc("engraving", "End of %1").arg(s->screenReaderInfo());
    3532              :         }
    3533              :     }
    3534              : 
    3535              :     // only read extra information for top note of chord
    3536              :     // (it is reached directly on next/previous element)
    3537            0 :     if (this == chord()->upNote()) {
    3538            0 :         rez = String(u"%1 %2").arg(rez, chord()->accessibleExtraInfo());
    3539              :     }
    3540              : 
    3541            0 :     return rez;
    3542            0 : }
    3543              : 
    3544          100 : NoteVal Note::noteVal() const
    3545              : {
    3546          100 :     NoteVal nval;
    3547          100 :     nval.pitch = pitch();
    3548          100 :     nval.velocityOverride = userVelocity();
    3549          100 :     nval.tpc1 = tpc1();
    3550          100 :     nval.tpc2 = tpc2();
    3551          100 :     nval.fret = fret();
    3552          100 :     nval.string = string();
    3553          100 :     nval.headGroup = headGroup();
    3554              : 
    3555          100 :     return nval;
    3556              : }
    3557              : 
    3558              : //---------------------------------------------------------
    3559              : //   subtypeUserName
    3560              : //---------------------------------------------------------
    3561              : 
    3562            0 : TranslatableString Note::subtypeUserName() const
    3563              : {
    3564            0 :     return TConv::userName(m_headGroup);
    3565              : }
    3566              : 
    3567              : //---------------------------------------------------------
    3568              : //   nextInEl
    3569              : //   returns next element in _el
    3570              : //---------------------------------------------------------
    3571              : 
    3572            0 : EngravingItem* Note::nextInEl(EngravingItem* e)
    3573              : {
    3574            0 :     if (e == m_el.back()) {
    3575            0 :         return nullptr;
    3576              :     }
    3577            0 :     auto i = std::find(m_el.begin(), m_el.end(), e);
    3578            0 :     if (i == m_el.end()) {
    3579            0 :         return nullptr;
    3580              :     }
    3581            0 :     return *(i + 1);
    3582              : }
    3583              : 
    3584              : //---------------------------------------------------------
    3585              : //   prevInEl
    3586              : //   returns prev element in _el
    3587              : //---------------------------------------------------------
    3588              : 
    3589            0 : EngravingItem* Note::prevInEl(EngravingItem* e)
    3590              : {
    3591            0 :     if (e == m_el.front()) {
    3592            0 :         return nullptr;
    3593              :     }
    3594            0 :     auto i = std::find(m_el.begin(), m_el.end(), e);
    3595            0 :     if (i == m_el.end()) {
    3596            0 :         return nullptr;
    3597              :     }
    3598            0 :     return *(i - 1);
    3599              : }
    3600              : 
    3601            0 : static bool tieValid(Tie* tie)
    3602              : {
    3603            0 :     return tie && !tie->segmentsEmpty();
    3604              : }
    3605              : 
    3606              : //---------------------------------------------------------
    3607              : //   nextElement
    3608              : //---------------------------------------------------------
    3609              : 
    3610            0 : EngravingItem* Note::nextElement()
    3611              : {
    3612            0 :     EngravingItem* e = score()->selection().element();
    3613            0 :     if (!e && !score()->selection().elements().empty()) {
    3614            0 :         e = score()->selection().elements().front();
    3615              :     }
    3616            0 :     if (!e) {
    3617            0 :         return nullptr;
    3618              :     }
    3619            0 :     switch (e->type()) {
    3620            0 :     case ElementType::SYMBOL:
    3621              :     case ElementType::IMAGE:
    3622              :     case ElementType::FINGERING:
    3623              :     case ElementType::TEXT:
    3624              :     case ElementType::BEND: {
    3625            0 :         EngravingItem* next = nextInEl(e);           // return next element in _el
    3626            0 :         if (next) {
    3627            0 :             return next;
    3628            0 :         } else if (tieValid(m_tieFor)) {
    3629            0 :             return m_tieFor->frontSegment();
    3630            0 :         } else if (!m_spannerFor.empty()) {
    3631            0 :             for (auto i : m_spannerFor) {
    3632            0 :                 if (i->isGlissando()) {
    3633            0 :                     return i->spannerSegments().front();
    3634              :                 }
    3635              :             }
    3636              :         }
    3637            0 :         return nullptr;
    3638              :     }
    3639              : 
    3640            0 :     case ElementType::TIE_SEGMENT:
    3641              :     case ElementType::LAISSEZ_VIB_SEGMENT:
    3642              :     case ElementType::PARTIAL_TIE_SEGMENT:
    3643            0 :         if (!m_spannerFor.empty()) {
    3644            0 :             for (auto i : m_spannerFor) {
    3645            0 :                 if (i->isGlissando()) {
    3646            0 :                     return i->spannerSegments().front();
    3647              :                 }
    3648              :             }
    3649              :         }
    3650            0 :         return chord()->nextElement();
    3651              : 
    3652            0 :     case ElementType::NOTELINE_SEGMENT:
    3653              :     case ElementType::GLISSANDO_SEGMENT:
    3654              :     case ElementType::GUITAR_BEND_SEGMENT:
    3655            0 :         return chord()->nextElement();
    3656              : 
    3657            0 :     case ElementType::ACCIDENTAL:
    3658            0 :         if (!m_el.empty()) {
    3659            0 :             return m_el[0];
    3660              :         }
    3661            0 :         if (tieValid(m_tieFor)) {
    3662            0 :             return m_tieFor->frontSegment();
    3663              :         }
    3664            0 :         if (!m_spannerFor.empty()) {
    3665            0 :             for (auto i : m_spannerFor) {
    3666            0 :                 if (i->isGlissando()) {
    3667            0 :                     return i->spannerSegments().front();
    3668              :                 }
    3669              :             }
    3670              :         }
    3671            0 :         return nullptr;
    3672              : 
    3673            0 :     case ElementType::NOTE: {
    3674            0 :         if (isPreBendOrDiveStart() || isGraceBendStart()) {
    3675            0 :             return bendFor()->frontSegment();
    3676              :         }
    3677              : 
    3678            0 :         GraceNotesGroup& graceNotesAfter = chord()->graceNotesAfter();
    3679            0 :         if (!graceNotesAfter.empty()) {
    3680            0 :             Chord* graceNotesAfterFirstChord = graceNotesAfter.front();
    3681            0 :             if (graceNotesAfterFirstChord) {
    3682            0 :                 return graceNotesAfterFirstChord->notes().front();
    3683              :             }
    3684              :         }
    3685              : 
    3686            0 :         if (!m_el.empty()) {
    3687            0 :             return m_el[0];
    3688              :         }
    3689            0 :         if (tieValid(m_tieFor)) {
    3690            0 :             return m_tieFor->frontSegment();
    3691              :         }
    3692            0 :         if (!m_spannerFor.empty()) {
    3693            0 :             for (auto i : m_spannerFor) {
    3694            0 :                 if (i->isGlissando() || i->isGuitarBend()) {
    3695            0 :                     return i->spannerSegments().front();
    3696              :                 }
    3697              :             }
    3698              :         }
    3699            0 :         return nullptr;
    3700              :     }
    3701            0 :     default:
    3702            0 :         return nullptr;
    3703              :     }
    3704              : }
    3705              : 
    3706              : //---------------------------------------------------------
    3707              : //   prevElement
    3708              : //---------------------------------------------------------
    3709              : 
    3710            0 : EngravingItem* Note::prevElement()
    3711              : {
    3712            0 :     EngravingItem* e = score()->selection().element();
    3713            0 :     if (!e && !score()->selection().elements().empty()) {
    3714            0 :         e = score()->selection().elements().back();
    3715              :     }
    3716            0 :     if (!e) {
    3717            0 :         return nullptr;
    3718              :     }
    3719            0 :     switch (e->type()) {
    3720            0 :     case ElementType::SYMBOL:
    3721              :     case ElementType::IMAGE:
    3722              :     case ElementType::FINGERING:
    3723              :     case ElementType::TEXT:
    3724              :     case ElementType::BEND: {
    3725            0 :         EngravingItem* prev = prevInEl(e);           // return prev element in _el
    3726            0 :         if (prev) {
    3727            0 :             return prev;
    3728              :         }
    3729              :     }
    3730            0 :         return this;
    3731            0 :     case ElementType::TIE_SEGMENT:
    3732              :     case ElementType::PARTIAL_TIE_SEGMENT:
    3733              :     case ElementType::LAISSEZ_VIB_SEGMENT:
    3734            0 :         if (!m_el.empty()) {
    3735            0 :             return m_el.back();
    3736              :         }
    3737            0 :         return this;
    3738            0 :     case ElementType::NOTELINE_SEGMENT:
    3739              :     case ElementType::GLISSANDO_SEGMENT:
    3740              :     case ElementType::GUITAR_BEND_SEGMENT:
    3741            0 :         if (tieValid(m_tieFor)) {
    3742            0 :             return m_tieFor->frontSegment();
    3743            0 :         } else if (!m_el.empty()) {
    3744            0 :             return m_el.back();
    3745              :         }
    3746            0 :         return this;
    3747            0 :     case ElementType::ACCIDENTAL:
    3748            0 :         return this;
    3749            0 :     default:
    3750            0 :         return nullptr;
    3751              :     }
    3752              : }
    3753              : 
    3754              : //---------------------------------------------------------
    3755              : //   lastElementBeforeSegment
    3756              : //---------------------------------------------------------
    3757              : 
    3758            0 : EngravingItem* Note::lastElementBeforeSegment()
    3759              : {
    3760            0 :     if (!m_spannerFor.empty()) {
    3761            0 :         for (auto i : m_spannerFor) {
    3762            0 :             if (i->isGlissando() || i->isGuitarBend() || i->isNoteLine()) {
    3763            0 :                 return i->spannerSegments().front();
    3764              :             }
    3765              :         }
    3766              :     }
    3767            0 :     if (tieValid(m_tieFor)) {
    3768            0 :         return m_tieFor->frontSegment();
    3769              :     }
    3770            0 :     if (!m_el.empty()) {
    3771            0 :         return m_el.back();
    3772              :     }
    3773            0 :     return this;
    3774              : }
    3775              : 
    3776              : //---------------------------------------------------------
    3777              : //   nextSegmentElement
    3778              : //---------------------------------------------------------
    3779              : 
    3780            0 : EngravingItem* Note::nextSegmentElement()
    3781              : {
    3782            0 :     if (chord()->isGrace()) {
    3783            0 :         return EngravingItem::nextSegmentElement();
    3784              :     }
    3785              : 
    3786            0 :     const std::vector<Note*>& notes = chord()->notes();
    3787            0 :     if (this == notes.front()) {
    3788            0 :         return chord()->nextSegmentElement();
    3789              :     }
    3790            0 :     auto i = std::find(notes.begin(), notes.end(), this);
    3791            0 :     return *(i - 1);
    3792              : }
    3793              : 
    3794              : //---------------------------------------------------------
    3795              : //   prevSegmentElement
    3796              : //---------------------------------------------------------
    3797              : 
    3798            0 : EngravingItem* Note::prevSegmentElement()
    3799              : {
    3800            0 :     if (chord()->isGrace()) {
    3801            0 :         return EngravingItem::prevSegmentElement();
    3802              :     }
    3803              : 
    3804            0 :     const std::vector<Note*>& notes = chord()->notes();
    3805            0 :     if (this == notes.back()) {
    3806            0 :         return chord()->prevSegmentElement();
    3807              :     }
    3808            0 :     auto i = std::find(notes.begin(), notes.end(), this);
    3809            0 :     return *++i;
    3810              : }
    3811              : 
    3812              : //---------------------------------------------------------
    3813              : //   lastTiedNote
    3814              : //---------------------------------------------------------
    3815              : 
    3816         7539 : Note* Note::lastTiedNote(bool ignorePlayback) const
    3817              : {
    3818         7539 :     std::vector<const Note*> notes;
    3819         7539 :     const Note* note = this;
    3820         7539 :     notes.push_back(note);
    3821         7999 :     while (note->tieFor() && (ignorePlayback || note->tieFor()->playSpanner())) {
    3822          468 :         if (std::find(notes.begin(), notes.end(), note->tieFor()->endNote()) != notes.end()) {
    3823            0 :             break;
    3824              :         }
    3825          468 :         if (!note->tieFor()->endNote()) {
    3826            8 :             break;
    3827              :         }
    3828          460 :         note = note->tieFor()->endNote();
    3829          460 :         notes.push_back(note);
    3830              :     }
    3831         7539 :     return const_cast<Note*>(note);
    3832         7539 : }
    3833              : 
    3834              : //---------------------------------------------------------
    3835              : //   firstTiedNote
    3836              : //    if note has ties, return last note in chain
    3837              : //    - handle recursion in connected notes
    3838              : //---------------------------------------------------------
    3839              : 
    3840         7624 : Note* Note::firstTiedNote(bool ignorePlayback) const
    3841              : {
    3842         7624 :     std::vector<const Note*> notes;
    3843         7624 :     const Note* note = this;
    3844         7624 :     notes.push_back(note);
    3845         8088 :     while (note->tieBack() && (ignorePlayback || note->tieBack()->playSpanner())) {
    3846          467 :         if (std::find(notes.begin(), notes.end(), note->tieBack()->startNote()) != notes.end()) {
    3847            0 :             break;
    3848              :         }
    3849          467 :         if (!note->tieBack()->startNote()) {
    3850            3 :             break;
    3851              :         }
    3852          464 :         note = note->tieBack()->startNote();
    3853          464 :         notes.push_back(note);
    3854              :     }
    3855         7624 :     return const_cast<Note*>(note);
    3856         7624 : }
    3857              : 
    3858              : //---------------------------------------------------------
    3859              : //   tiedNotes
    3860              : //---------------------------------------------------------
    3861              : 
    3862          134 : std::vector<Note*> Note::findTiedNotes(Note* startNote, bool followPartialTies)
    3863              : {
    3864              :     // Returns all notes ahead of startNote in a chain of ties
    3865              :     // Follows partial tie paths recursively
    3866          134 :     Note* note = startNote;
    3867          134 :     std::vector<Note*> notes;
    3868          134 :     notes.push_back(note);
    3869              : 
    3870          137 :     while (note->tieFor()) {
    3871            3 :         if (followPartialTies) {
    3872            3 :             for (TieJumpPoint* jumpPoint : *note->tieJumpPoints()) {
    3873            0 :                 if (!jumpPoint->active() || jumpPoint->followingNote()) {
    3874            0 :                     continue;
    3875              :                 }
    3876            0 :                 if (!jumpPoint->note() || std::find(notes.begin(), notes.end(), jumpPoint->note()) != notes.end()) {
    3877            0 :                     continue;
    3878              :                 }
    3879              :                 // ONLY backtrack when end point is a full tie eg. around a segno
    3880            0 :                 const bool endTieIsFullTie = jumpPoint->endTie() && !jumpPoint->endTie()->isPartialTie();
    3881            0 :                 Note* jumpPointNote = endTieIsFullTie ? jumpPoint->endTie()->startNote()->firstTiedNote() : jumpPoint->note();
    3882            0 :                 std::vector<Note*> partialTieNotes = findTiedNotes(jumpPointNote, !endTieIsFullTie);
    3883            0 :                 notes.insert(notes.end(), partialTieNotes.begin(), partialTieNotes.end());
    3884            0 :             }
    3885              :         }
    3886              : 
    3887            3 :         Note* endNote = note->tieFor()->endNote();
    3888            3 :         if (!endNote || std::find(notes.begin(), notes.end(), endNote) != notes.end()) {
    3889            0 :             break;
    3890              :         }
    3891            3 :         note = endNote;
    3892            3 :         notes.push_back(note);
    3893              :     }
    3894              : 
    3895          134 :     return notes;
    3896            0 : }
    3897              : 
    3898          134 : std::vector<Note*> Note::tiedNotes() const
    3899              : {
    3900              :     // Backtrack to the first tied note in a chain, then return all notes in the chain ahead of it
    3901          134 :     Note* note = firstTiedNote();
    3902              : 
    3903          134 :     std::vector<Note*> notes = findTiedNotes(note);
    3904              : 
    3905          134 :     return notes;
    3906              : }
    3907              : 
    3908              : //---------------------------------------------------------
    3909              : //   unisonIndex
    3910              : //---------------------------------------------------------
    3911              : 
    3912          869 : int Note::unisonIndex() const
    3913              : {
    3914          869 :     int index = 0;
    3915         1069 :     for (Note* n : chord()->notes()) {
    3916         1069 :         if (n->pitch() == pitch()) {
    3917          869 :             if (n == this) {
    3918          869 :                 return index;
    3919              :             } else {
    3920            0 :                 ++index;
    3921              :             }
    3922              :         }
    3923              :     }
    3924            0 :     return 0;
    3925              : }
    3926              : 
    3927              : //---------------------------------------------------------
    3928              : //   disconnectTiedNotes
    3929              : //---------------------------------------------------------
    3930              : 
    3931         2703 : void Note::disconnectTiedNotes()
    3932              : {
    3933         2703 :     if (tieBack() && tieBack()->startNote()) {
    3934            0 :         tieBack()->startNote()->remove(tieBack());
    3935              :     }
    3936         2703 :     if (tieFor() && tieFor()->endNote()) {
    3937            0 :         tieFor()->endNote()->setTieBack(0);
    3938              :     }
    3939         2703 : }
    3940              : 
    3941              : //---------------------------------------------------------
    3942              : //   connectTiedNotes
    3943              : //---------------------------------------------------------
    3944              : 
    3945        41532 : void Note::connectTiedNotes()
    3946              : {
    3947        41532 :     if (tieBack() && !tieBack()->isPartialTie()) {
    3948           43 :         tieBack()->setEndNote(this);
    3949           43 :         if (tieBack()->startNote()) {
    3950           43 :             tieBack()->startNote()->add(tieBack());
    3951              :         }
    3952              :     }
    3953        41532 :     if (tieFor() && tieFor()->endNote() && !tieFor()->isPartialTie()) {
    3954            0 :         tieFor()->endNote()->setTieBack(tieFor());
    3955              :     }
    3956        41532 : }
    3957              : 
    3958              : //---------------------------------------------------------
    3959              : //   accidentalType
    3960              : //---------------------------------------------------------
    3961              : 
    3962         1432 : AccidentalType Note::accidentalType() const
    3963              : {
    3964         1432 :     return m_accidental ? m_accidental->accidentalType() : AccidentalType::NONE;
    3965              : }
    3966              : 
    3967              : //---------------------------------------------------------
    3968              : //   setAccidentalType
    3969              : //---------------------------------------------------------
    3970              : 
    3971            0 : void Note::setAccidentalType(AccidentalType type)
    3972              : {
    3973            0 :     if (score()) {
    3974            0 :         EditNote::changeAccidental(score(), this, type);
    3975              :     }
    3976            0 : }
    3977              : 
    3978              : //---------------------------------------------------------
    3979              : //   undoUnlink
    3980              : //---------------------------------------------------------
    3981              : 
    3982          181 : void Note::undoUnlink()
    3983              : {
    3984          181 :     EngravingItem::undoUnlink();
    3985          190 :     for (EngravingItem* e : m_el) {
    3986            9 :         e->undoUnlink();
    3987              :     }
    3988          181 :     for (Spanner* s : m_spannerFor) {
    3989            0 :         s->undoUnlink();
    3990              :     }
    3991          181 :     if (m_tieFor) {
    3992            8 :         m_tieFor->undoUnlink();
    3993              :     }
    3994          181 : }
    3995              : 
    3996              : //---------------------------------------------------------
    3997              : //   slides
    3998              : //---------------------------------------------------------
    3999              : 
    4000          119 : static bool isSlideTo(Note::SlideType slideType)
    4001              : {
    4002          119 :     return slideType == Note::SlideType::UpToNote || slideType == Note::SlideType::DownToNote;
    4003              : }
    4004              : 
    4005           58 : static bool isSlideFrom(Note::SlideType slideType)
    4006              : {
    4007           58 :     return slideType == Note::SlideType::UpFromNote || slideType == Note::SlideType::DownFromNote;
    4008              : }
    4009              : 
    4010          119 : void Note::attachSlide(SlideType slideType)
    4011              : {
    4012          119 :     if (isSlideTo(slideType)) {
    4013           61 :         m_slideToType = slideType;
    4014           58 :     } else if (isSlideFrom(slideType)) {
    4015           58 :         m_slideFromType = slideType;
    4016              :     }
    4017          119 : }
    4018              : 
    4019          336 : bool Note::hasSlideToNote() const
    4020              : {
    4021          336 :     return m_slideToType != SlideType::Undefined;
    4022              : }
    4023              : 
    4024          719 : bool Note::hasSlideFromNote() const
    4025              : {
    4026          719 :     return m_slideFromType != SlideType::Undefined;
    4027              : }
    4028              : 
    4029          148 : void Note::setParenthesesMode(const ParenthesesMode& v, bool addToLinked, bool generated)
    4030              : {
    4031          148 :     IF_ASSERT_FAILED(v == ParenthesesMode::BOTH || v == ParenthesesMode::NONE) {
    4032            0 :         LOGE() << "Notes cannot set left & right parens individually";
    4033            0 :         return;
    4034              :     }
    4035              : 
    4036          148 :     if ((m_hasParens && v == ParenthesesMode::BOTH) || (!m_hasParens && v == ParenthesesMode::NONE)) {
    4037           50 :         return;
    4038              :     }
    4039              : 
    4040           98 :     const NoteParenthesisInfo* noteParenInfo = parenthesisInfo();
    4041              : 
    4042           98 :     Parenthesis* leftParen = noteParenInfo ? noteParenInfo->leftParen() : nullptr;
    4043              : 
    4044           98 :     const bool hasGeneratedParen = leftParen && leftParen->generated();
    4045           98 :     const bool hasUserParen = leftParen && !leftParen->generated();
    4046              : 
    4047           98 :     bool hasParen = v == ParenthesesMode::BOTH;
    4048              : 
    4049           98 :     if (generated && hasParen == hasGeneratedParen) {
    4050            0 :         return;
    4051              :     }
    4052              : 
    4053           98 :     if (!generated && hasParen == hasUserParen) {
    4054            0 :         return;
    4055              :     }
    4056              : 
    4057           98 :     m_hasParens = hasParen;
    4058              : 
    4059           98 :     if (hasParen) {
    4060          294 :         EditChord::addChordParentheses(chord(), { this }, addToLinked, generated);
    4061              :     } else {
    4062            0 :         EditChord::removeChordParentheses(chord(), { this }, addToLinked, generated);
    4063              :     }
    4064              : }
    4065              : 
    4066        71744 : const NoteParenthesisInfo* Note::parenthesisInfo() const
    4067              : {
    4068        71744 :     return chord() ? chord()->findNoteParenthesisInfo(this) : nullptr;
    4069              : }
    4070              : 
    4071      1457956 : bool Note::isGrace() const
    4072              : {
    4073      1457956 :     return noteType() != NoteType::NORMAL;
    4074              : }
    4075              : 
    4076          392 : bool Note::isPreBendOrDiveStart() const
    4077              : {
    4078          392 :     if (!isGrace()) {
    4079          269 :         return false;
    4080              :     }
    4081              : 
    4082          123 :     const GuitarBend* bend = bendFor();
    4083          123 :     if (!bend) {
    4084           84 :         return false;
    4085              :     }
    4086              : 
    4087           39 :     const GuitarBendType bendType = bend->bendType();
    4088           39 :     return bendType == GuitarBendType::PRE_BEND || bendType == GuitarBendType::PRE_DIVE;
    4089              : }
    4090              : 
    4091          328 : bool Note::isGraceBendStart() const
    4092              : {
    4093          328 :     if (!isGrace()) {
    4094          257 :         return false;
    4095              :     }
    4096              : 
    4097           71 :     const GuitarBend* bend = bendFor();
    4098              : 
    4099           71 :     return bend && bend->bendType() == GuitarBendType::GRACE_NOTE_BEND;
    4100              : }
    4101              : 
    4102          409 : bool Note::isContinuationOfBend() const
    4103              : {
    4104          409 :     if (bendBack()) {
    4105            4 :         return true;
    4106              :     }
    4107              : 
    4108          405 :     Tie* tie = tieBack();
    4109          405 :     Note* note = nullptr;
    4110          976 :     while (tie && tie->startNote()) {
    4111          583 :         note = tie->startNote();
    4112          583 :         if (note->bendBack()) {
    4113           12 :             return true;
    4114              :         }
    4115              : 
    4116          571 :         if (tie == note->tieBack()) {
    4117            0 :             return false;
    4118              :         }
    4119              : 
    4120          571 :         tie = note->tieBack();
    4121              :     }
    4122              : 
    4123          393 :     return false;
    4124              : }
    4125              : 
    4126         9107 : bool Note::hasAnotherStraightAboveOrBelow(bool above) const
    4127              : {
    4128         9107 :     if (!chord()) {
    4129            0 :         return false;
    4130              :     }
    4131              : 
    4132         9107 :     const std::vector<Note*>& notes = chord()->notes();
    4133              : 
    4134         9107 :     if ((above && this == notes.back()) || (!above && this == notes.front())) {
    4135         8568 :         return false;
    4136              :     }
    4137              : 
    4138          539 :     const double limitDiff = 0.5 * spatium();
    4139         1119 :     for (Note* note : notes) {
    4140         1111 :         if (note == this) {
    4141          154 :             continue;
    4142              :         }
    4143          957 :         if (std::fabs(note->pos().x() - pos().x()) > limitDiff) {
    4144          531 :             return false;
    4145              :         }
    4146          812 :         if ((above && note->line() < m_line) || (!above && note->line() > m_line)) {
    4147          386 :             return true;
    4148              :         }
    4149              :     }
    4150              : 
    4151            8 :     return false;
    4152              : }
    4153              : 
    4154        12167 : PointF Note::posInStaffCoordinates()
    4155              : {
    4156        12167 :     double X = x() + chord()->x() + chord()->segment()->x() + chord()->measure()->x();
    4157        12167 :     return PointF(X, y());
    4158              : }
    4159              : 
    4160           16 : void Note::setIsTrillCueNote(bool v)
    4161              : {
    4162           16 :     m_isTrillCueNote = v;
    4163           16 :     if (chord()) {
    4164           16 :         chord()->setIsTrillCueNote(v);
    4165              :     }
    4166           16 : }
    4167              : 
    4168        12167 : void Note::addLineAttachPoint(PointF point, EngravingItem* line, bool start)
    4169              : {
    4170              :     // IMPORTANT: the point is expected in *staff* coordinates
    4171              :     // We transform into note coordinates by subtracting the note position in staff coordinates
    4172        12167 :     point -= posInStaffCoordinates();
    4173        12167 :     m_lineAttachPoints.push_back(LineAttachPoint(line, point.x(), point.y(), start));
    4174        12167 : }
    4175              : 
    4176         5473 : bool Note::negativeFretUsed() const
    4177              : {
    4178         5473 :     return configuration()->negativeFretsAllowed() && m_fret < 0 && m_string != INVALID_STRING_INDEX;
    4179              : }
    4180              : 
    4181       108005 : int Note::stringOrLine() const
    4182              : {
    4183              :     // The number string() returns doesn't count spaces.  This should be used where it is expected even numbers are spaces and odd are lines
    4184       108005 :     return staff()->staffType(tick())->isTabStaff() ? string() * 2 : line();
    4185              : }
    4186              : 
    4187              : //---------------------------------------------------------
    4188              : //   Note::transposeDiatonic
    4189              : //---------------------------------------------------------
    4190              : 
    4191          662 : bool Note::transposeDiatonic(int interval, bool keepAlterations, bool useDoubleAccidentals)
    4192              : {
    4193              :     // compute note current absolute step
    4194              :     int alter;
    4195          662 :     Fraction tick = chord()->segment()->tick();
    4196          662 :     Key key       = staff() ? staff()->key(tick) : Key::C;
    4197          662 :     int absStep   = pitch2absStepByKey(epitch(), tpc(), key, alter);
    4198              : 
    4199              :     // get pitch and tcp corresponding to unaltered degree for this key
    4200          662 :     int newPitch = absStep2pitchByKey(absStep + interval, key);
    4201          662 :     int newTpc   = step2tpcByKey((absStep + interval) % STEP_DELTA_OCTAVE, key);
    4202              : 
    4203          662 :     if (!pitchIsValid(newPitch)) {
    4204            0 :         return false;
    4205              :     }
    4206              : 
    4207              :     // if required, transfer original degree alteration to new pitch and tpc
    4208          662 :     if (keepAlterations) {
    4209          232 :         newPitch += alter;
    4210          232 :         newTpc  += alter * TPC_DELTA_SEMITONE;
    4211              :     }
    4212              : 
    4213              :     // transpose appropriately
    4214          662 :     int newTpc1 = TPC_INVALID;
    4215          662 :     int newTpc2 = TPC_INVALID;
    4216          662 :     Interval v  = staff() ? staff()->transpose(tick) : Interval(0);
    4217          662 :     if (concertPitch()) {
    4218            0 :         v.flip();
    4219            0 :         newTpc1 = clampEnharmonic(newTpc, useDoubleAccidentals);
    4220            0 :         newTpc2 = Transpose::transposeTpc(newTpc, v, useDoubleAccidentals);
    4221              :     } else {
    4222          662 :         newPitch += v.chromatic;
    4223          662 :         newTpc1 = Transpose::transposeTpc(newTpc, v, useDoubleAccidentals);
    4224          662 :         newTpc2 = clampEnharmonic(newTpc, useDoubleAccidentals);
    4225              :     }
    4226              : 
    4227              :     // check pitch is in range
    4228          662 :     newPitch = clampPitchOctaved(newPitch);
    4229              : 
    4230              :     // store new data
    4231          662 :     EditNote::undoChangePitch(score(), this, newPitch, newTpc1, newTpc2);
    4232          662 :     return true;
    4233              : }
    4234              : 
    4235          630 : bool Note::transpose(Interval interval, bool useDoubleSharpsFlats)
    4236              : {
    4237          630 :     int npitch = pitch() + interval.chromatic;
    4238          630 :     if (!pitchIsValid(npitch)) {
    4239            0 :         return false;
    4240              :     }
    4241          630 :     int ntpc1 = Transpose::transposeTpc(tpc1(), interval, useDoubleSharpsFlats);
    4242          630 :     int ntpc2 = ntpc1;
    4243          630 :     if (transposition()) {
    4244            6 :         if (staff()) {
    4245            6 :             Interval v = staff()->transpose(tick());
    4246            6 :             v.flip();
    4247            6 :             ntpc2 = Transpose::transposeTpc(ntpc1, v, useDoubleSharpsFlats);
    4248              :         } else {
    4249            0 :             ntpc2 = Transpose::transposeTpc(tpc2(), interval, useDoubleSharpsFlats);
    4250              :         }
    4251              :     }
    4252          630 :     EditNote::undoChangePitch(score(), this, npitch, ntpc1, ntpc2);
    4253          630 :     return true;
    4254              : }
    4255              : 
    4256       134818 : staff_idx_t Note::vStaffIdx() const
    4257              : {
    4258       134818 :     const Chord* c = chord();
    4259       134818 :     return c ? c->vStaffIdx() : EngravingItem::vStaffIdx();
    4260              : }
    4261              : }
        

Generated by: LCOV version 2.0-1