1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2012 Werner Schweer
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2
9 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENCE.GPL
11 //=============================================================================
12 
13 /**
14  \file
15  Implementation of classes Note and ShadowNote.
16 */
17 
18 #include <assert.h>
19 
20 #include "global/log.h"
21 
22 #include "note.h"
23 #include "score.h"
24 #include "chord.h"
25 #include "sym.h"
26 #include "xml.h"
27 #include "slur.h"
28 #include "tie.h"
29 #include "text.h"
30 #include "clef.h"
31 #include "staff.h"
32 #include "pitchspelling.h"
33 #include "arpeggio.h"
34 #include "tremolo.h"
35 #include "utils.h"
36 #include "image.h"
37 #include "system.h"
38 #include "tuplet.h"
39 #include "articulation.h"
40 #include "drumset.h"
41 #include "segment.h"
42 #include "measure.h"
43 #include "undo.h"
44 #include "part.h"
45 #include "stafftype.h"
46 #include "stringdata.h"
47 #include "fret.h"
48 #include "harmony.h"
49 #include "fingering.h"
50 #include "bend.h"
51 #include "accidental.h"
52 #include "page.h"
53 #include "icon.h"
54 #include "notedot.h"
55 #include "spanner.h"
56 #include "glissando.h"
57 #include "bagpembell.h"
58 #include "hairpin.h"
59 #include "textline.h"
60 #include <QPointF>
61 #include <QtMath>
62 #include <QVector2D>
63 
64 namespace Ms {
65 
66 //---------------------------------------------------------
67 //   noteHeads
68 //    notehead groups
69 //---------------------------------------------------------
70 
71 //int(NoteHead::Group::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
72 static const SymId noteHeads[2][int(NoteHead::Group::HEAD_GROUPS) - 1][int(NoteHead::Type::HEAD_TYPES)] = {
73    {     // down stem
74       { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,               SymId::noteheadDoubleWhole  },
75       { SymId::noteheadXWhole,              SymId::noteheadXHalf,               SymId::noteheadXBlack,              SymId::noteheadXDoubleWhole  },
76       { SymId::noteheadPlusWhole,           SymId::noteheadPlusHalf,            SymId::noteheadPlusBlack,           SymId::noteheadPlusDoubleWhole  },
77       { SymId::noteheadCircleXWhole,        SymId::noteheadCircleXHalf,         SymId::noteheadCircleX,             SymId::noteheadCircleXDoubleWhole},
78       { SymId::noteheadWholeWithX,          SymId::noteheadHalfWithX,           SymId::noteheadVoidWithX,           SymId::noteheadDoubleWholeWithX},
79       { SymId::noteheadTriangleUpWhole,     SymId::noteheadTriangleUpHalf,      SymId::noteheadTriangleUpBlack,     SymId::noteheadTriangleUpDoubleWhole },
80       { SymId::noteheadTriangleDownWhole,   SymId::noteheadTriangleDownHalf,    SymId::noteheadTriangleDownBlack,   SymId::noteheadTriangleDownDoubleWhole },
81       { SymId::noteheadSlashedWhole1,       SymId::noteheadSlashedHalf1,        SymId::noteheadSlashedBlack1,       SymId::noteheadSlashedDoubleWhole1 },
82       { SymId::noteheadSlashedWhole2,       SymId::noteheadSlashedHalf2,        SymId::noteheadSlashedBlack2,       SymId::noteheadSlashedDoubleWhole2 },
83       { SymId::noteheadDiamondWhole,        SymId::noteheadDiamondHalf,         SymId::noteheadDiamondBlack,        SymId::noteheadDiamondDoubleWhole  },
84       { SymId::noteheadDiamondWholeOld,     SymId::noteheadDiamondHalfOld,      SymId::noteheadDiamondBlackOld,     SymId::noteheadDiamondDoubleWholeOld  },
85       { SymId::noteheadCircledWhole,        SymId::noteheadCircledHalf,         SymId::noteheadCircledBlack,        SymId::noteheadCircledDoubleWhole  },
86       { SymId::noteheadCircledWholeLarge,   SymId::noteheadCircledHalfLarge,    SymId::noteheadCircledBlackLarge,   SymId::noteheadCircledDoubleWholeLarge  },
87       { SymId::noteheadLargeArrowUpWhole,   SymId::noteheadLargeArrowUpHalf,    SymId::noteheadLargeArrowUpBlack,   SymId::noteheadLargeArrowUpDoubleWhole  },
88       { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,               SymId::noteheadDoubleWholeSquare   },
89 
90       { SymId::noteheadSlashWhiteWhole,     SymId::noteheadSlashWhiteHalf,      SymId::noteheadSlashHorizontalEnds, SymId::noteheadSlashWhiteWhole},
91 
92       { SymId::noteShapeRoundWhite,         SymId::noteShapeRoundWhite,         SymId::noteShapeRoundBlack,         SymId::noteShapeRoundDoubleWhole            },
93       { SymId::noteShapeSquareWhite,        SymId::noteShapeSquareWhite,        SymId::noteShapeSquareBlack,        SymId::noteShapeSquareDoubleWhole           },
94       { SymId::noteShapeTriangleRightWhite, SymId::noteShapeTriangleRightWhite, SymId::noteShapeTriangleRightBlack, SymId::noteShapeTriangleRightDoubleWhole    },
95       { SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondBlack,       SymId::noteShapeDiamondDoubleWhole          },
96       { SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpBlack,    SymId::noteShapeTriangleUpDoubleWhole       },
97       { SymId::noteShapeMoonWhite,          SymId::noteShapeMoonWhite,          SymId::noteShapeMoonBlack,          SymId::noteShapeMoonDoubleWhole            },
98       { SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundBlack, SymId::noteShapeTriangleRoundDoubleWhole    },
99 
100       { SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneBlack,          SymId::noteShapeKeystoneDoubleWhole    },
101       { SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonBlack,       SymId::noteShapeQuarterMoonDoubleWhole },
102       { SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleBlack, SymId::noteShapeIsoscelesTriangleDoubleWhole   },
103       { SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftBlack,          SymId::noteShapeMoonLeftDoubleWhole    },
104       { SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftBlack,     SymId::noteShapeArrowheadLeftDoubleWhole       },
105       { SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftBlack, SymId::noteShapeTriangleRoundLeftDoubleWhole   },
106 
107       { SymId::noteDoWhole,  SymId::noteDoHalf,  SymId::noteDoBlack,  SymId::noSym            },
108       { SymId::noteReWhole,  SymId::noteReHalf,  SymId::noteReBlack,  SymId::noSym            },
109       { SymId::noteMiWhole,  SymId::noteMiHalf,  SymId::noteMiBlack,  SymId::noSym            },
110       { SymId::noteFaWhole,  SymId::noteFaHalf,  SymId::noteFaBlack,  SymId::noSym            },
111       { SymId::noteSoWhole,  SymId::noteSoHalf,  SymId::noteSoBlack,  SymId::noSym            },
112       { SymId::noteLaWhole,  SymId::noteLaHalf,  SymId::noteLaBlack,  SymId::noSym            },
113       { SymId::noteTiWhole,  SymId::noteTiHalf,  SymId::noteTiBlack,  SymId::noSym            },
114       { SymId::noteSiWhole,  SymId::noteSiHalf,  SymId::noteSiBlack,  SymId::noSym            },
115 
116       { SymId::noteASharpWhole,  SymId::noteASharpHalf,  SymId::noteASharpBlack,  SymId::noSym            },
117       { SymId::noteAWhole,       SymId::noteAHalf,       SymId::noteABlack,       SymId::noSym            },
118       { SymId::noteAFlatWhole,   SymId::noteAFlatHalf,   SymId::noteAFlatBlack,   SymId::noSym            },
119       { SymId::noteBSharpWhole,  SymId::noteBSharpHalf,  SymId::noteBSharpBlack,  SymId::noSym            },
120       { SymId::noteBWhole,       SymId::noteBHalf,       SymId::noteBBlack,       SymId::noSym            },
121       { SymId::noteBFlatWhole,   SymId::noteBFlatHalf,   SymId::noteBFlatBlack,   SymId::noSym            },
122       { SymId::noteCSharpWhole,  SymId::noteCSharpHalf,  SymId::noteCSharpBlack,  SymId::noSym            },
123       { SymId::noteCWhole,       SymId::noteCHalf,       SymId::noteCBlack,       SymId::noSym            },
124       { SymId::noteCFlatWhole,   SymId::noteCFlatHalf,   SymId::noteCFlatBlack,   SymId::noSym            },
125       { SymId::noteDSharpWhole,  SymId::noteDSharpHalf,  SymId::noteDSharpBlack,  SymId::noSym            },
126       { SymId::noteDWhole,       SymId::noteDHalf,       SymId::noteDBlack,       SymId::noSym            },
127       { SymId::noteDFlatWhole,   SymId::noteDFlatHalf,   SymId::noteDFlatBlack,   SymId::noSym            },
128       { SymId::noteESharpWhole,  SymId::noteESharpHalf,  SymId::noteESharpBlack,  SymId::noSym            },
129       { SymId::noteEWhole,       SymId::noteEHalf,       SymId::noteEBlack,       SymId::noSym            },
130       { SymId::noteEFlatWhole,   SymId::noteEFlatHalf,   SymId::noteEFlatBlack,   SymId::noSym            },
131       { SymId::noteFSharpWhole,  SymId::noteFSharpHalf,  SymId::noteFSharpBlack,  SymId::noSym            },
132       { SymId::noteFWhole,       SymId::noteFHalf,       SymId::noteFBlack,       SymId::noSym            },
133       { SymId::noteFFlatWhole,   SymId::noteFFlatHalf,   SymId::noteFFlatBlack,   SymId::noSym            },
134       { SymId::noteGSharpWhole,  SymId::noteGSharpHalf,  SymId::noteGSharpBlack,  SymId::noSym            },
135       { SymId::noteGWhole,       SymId::noteGHalf,       SymId::noteGBlack,       SymId::noSym            },
136       { SymId::noteGFlatWhole,   SymId::noteGFlatHalf,   SymId::noteGFlatBlack,   SymId::noSym            },
137       { SymId::noteHWhole,       SymId::noteHHalf,       SymId::noteHBlack,       SymId::noSym            },
138       { SymId::noteHSharpWhole,  SymId::noteHSharpHalf,  SymId::noteHSharpBlack,  SymId::noSym            }
139 
140    },
141    {     // up stem
142       { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,               SymId::noteheadDoubleWhole  },
143       { SymId::noteheadXWhole,              SymId::noteheadXHalf,               SymId::noteheadXBlack,              SymId::noteheadXDoubleWhole       },
144       { SymId::noteheadPlusWhole,           SymId::noteheadPlusHalf,            SymId::noteheadPlusBlack,           SymId::noteheadPlusDoubleWhole  },
145       { SymId::noteheadCircleXWhole,        SymId::noteheadCircleXHalf,         SymId::noteheadCircleX,             SymId::noteheadCircleXDoubleWhole},
146       { SymId::noteheadWholeWithX,          SymId::noteheadHalfWithX,           SymId::noteheadVoidWithX,           SymId::noteheadDoubleWholeWithX},
147       { SymId::noteheadTriangleUpWhole,     SymId::noteheadTriangleUpHalf,      SymId::noteheadTriangleUpBlack,     SymId::noteheadTriangleUpDoubleWhole },
148       { SymId::noteheadTriangleDownWhole,   SymId::noteheadTriangleDownHalf,    SymId::noteheadTriangleDownBlack,   SymId::noteheadTriangleDownDoubleWhole },
149       { SymId::noteheadSlashedWhole1,       SymId::noteheadSlashedHalf1,        SymId::noteheadSlashedBlack1,       SymId::noteheadSlashedDoubleWhole1 },
150       { SymId::noteheadSlashedWhole2,       SymId::noteheadSlashedHalf2,        SymId::noteheadSlashedBlack2,       SymId::noteheadSlashedDoubleWhole2 },
151       { SymId::noteheadDiamondWhole,        SymId::noteheadDiamondHalf,         SymId::noteheadDiamondBlack,        SymId::noteheadDiamondDoubleWhole  },
152       { SymId::noteheadDiamondWholeOld,     SymId::noteheadDiamondHalfOld,      SymId::noteheadDiamondBlackOld,     SymId::noteheadDiamondDoubleWholeOld  },
153       { SymId::noteheadCircledWhole,        SymId::noteheadCircledHalf,         SymId::noteheadCircledBlack,        SymId::noteheadCircledDoubleWhole  },
154       { SymId::noteheadCircledWholeLarge,   SymId::noteheadCircledHalfLarge,    SymId::noteheadCircledBlackLarge,   SymId::noteheadCircledDoubleWholeLarge  },
155       // different from down, find source?
156       { SymId::noteheadLargeArrowDownWhole, SymId::noteheadLargeArrowDownHalf,  SymId::noteheadLargeArrowDownBlack, SymId::noteheadLargeArrowDownDoubleWhole  },
157       { SymId::noteheadWhole,               SymId::noteheadHalf,                SymId::noteheadBlack,               SymId::noteheadDoubleWholeSquare   },
158 
159       { SymId::noteheadSlashWhiteWhole,     SymId::noteheadSlashWhiteHalf,      SymId::noteheadSlashHorizontalEnds, SymId::noteheadSlashWhiteDoubleWhole},
160 
161       { SymId::noteShapeRoundWhite,         SymId::noteShapeRoundWhite,         SymId::noteShapeRoundBlack,         SymId::noteShapeRoundDoubleWhole       },
162       { SymId::noteShapeSquareWhite,        SymId::noteShapeSquareWhite,        SymId::noteShapeSquareBlack,        SymId::noteShapeSquareDoubleWhole      },
163       // different from down
164       { SymId::noteShapeTriangleLeftWhite,  SymId::noteShapeTriangleLeftWhite,  SymId::noteShapeTriangleLeftBlack,  SymId::noteShapeTriangleLeftDoubleWhole },
165       { SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondWhite,       SymId::noteShapeDiamondBlack,       SymId::noteShapeDiamondDoubleWhole      },
166       { SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpWhite,    SymId::noteShapeTriangleUpBlack,    SymId::noteShapeTriangleUpDoubleWhole   },
167       { SymId::noteShapeMoonWhite,          SymId::noteShapeMoonWhite,          SymId::noteShapeMoonBlack,          SymId::noteShapeMoonDoubleWhole         },
168       { SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundWhite, SymId::noteShapeTriangleRoundBlack, SymId::noteShapeTriangleRoundDoubleWhole },
169 
170       { SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneWhite,          SymId::noteShapeKeystoneBlack,          SymId::noteShapeKeystoneDoubleWhole },
171       { SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonWhite,       SymId::noteShapeQuarterMoonBlack,       SymId::noteShapeQuarterMoonDoubleWhole },
172       { SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleWhite, SymId::noteShapeIsoscelesTriangleBlack, SymId::noteShapeIsoscelesTriangleDoubleWhole },
173       { SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftWhite,          SymId::noteShapeMoonLeftBlack,          SymId::noteShapeMoonLeftDoubleWhole          },
174       { SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftWhite,     SymId::noteShapeArrowheadLeftBlack,     SymId::noteShapeArrowheadLeftDoubleWhole     },
175       { SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftWhite, SymId::noteShapeTriangleRoundLeftBlack, SymId::noteShapeTriangleRoundLeftDoubleWhole },
176 
177       { SymId::noteDoWhole,  SymId::noteDoHalf,  SymId::noteDoBlack,  SymId::noSym            },
178       { SymId::noteReWhole,  SymId::noteReHalf,  SymId::noteReBlack,  SymId::noSym            },
179       { SymId::noteMiWhole,  SymId::noteMiHalf,  SymId::noteMiBlack,  SymId::noSym            },
180       { SymId::noteFaWhole,  SymId::noteFaHalf,  SymId::noteFaBlack,  SymId::noSym            },
181       { SymId::noteSoWhole,  SymId::noteSoHalf,  SymId::noteSoBlack,  SymId::noSym            },
182       { SymId::noteLaWhole,  SymId::noteLaHalf,  SymId::noteLaBlack,  SymId::noSym            },
183       { SymId::noteTiWhole,  SymId::noteTiHalf,  SymId::noteTiBlack,  SymId::noSym            },
184       { SymId::noteSiWhole,  SymId::noteSiHalf,  SymId::noteSiBlack,  SymId::noSym            },
185 
186       { SymId::noteASharpWhole,  SymId::noteASharpHalf,  SymId::noteASharpBlack,  SymId::noSym            },
187       { SymId::noteAWhole,       SymId::noteAHalf,       SymId::noteABlack,       SymId::noSym            },
188       { SymId::noteAFlatWhole,   SymId::noteAFlatHalf,   SymId::noteAFlatBlack,   SymId::noSym            },
189       { SymId::noteBSharpWhole,  SymId::noteBSharpHalf,  SymId::noteBSharpBlack,  SymId::noSym            },
190       { SymId::noteBWhole,       SymId::noteBHalf,       SymId::noteBBlack,       SymId::noSym            },
191       { SymId::noteBFlatWhole,   SymId::noteBFlatHalf,   SymId::noteBFlatBlack,   SymId::noSym            },
192       { SymId::noteCSharpWhole,  SymId::noteCSharpHalf,  SymId::noteCSharpBlack,  SymId::noSym            },
193       { SymId::noteCWhole,       SymId::noteCHalf,       SymId::noteCBlack,       SymId::noSym            },
194       { SymId::noteCFlatWhole,   SymId::noteCFlatHalf,   SymId::noteCFlatBlack,   SymId::noSym            },
195       { SymId::noteDSharpWhole,  SymId::noteDSharpHalf,  SymId::noteDSharpBlack,  SymId::noSym            },
196       { SymId::noteDWhole,       SymId::noteDHalf,       SymId::noteDBlack,       SymId::noSym            },
197       { SymId::noteDFlatWhole,   SymId::noteDFlatHalf,   SymId::noteDFlatBlack,   SymId::noSym            },
198       { SymId::noteESharpWhole,  SymId::noteESharpHalf,  SymId::noteESharpBlack,  SymId::noSym            },
199       { SymId::noteEWhole,       SymId::noteEHalf,       SymId::noteEBlack,       SymId::noSym            },
200       { SymId::noteEFlatWhole,   SymId::noteEFlatHalf,   SymId::noteEFlatBlack,   SymId::noSym            },
201       { SymId::noteFSharpWhole,  SymId::noteFSharpHalf,  SymId::noteFSharpBlack,  SymId::noSym            },
202       { SymId::noteFWhole,       SymId::noteFHalf,       SymId::noteFBlack,       SymId::noSym            },
203       { SymId::noteFFlatWhole,   SymId::noteFFlatHalf,   SymId::noteFFlatBlack,   SymId::noSym            },
204       { SymId::noteGSharpWhole,  SymId::noteGSharpHalf,  SymId::noteGSharpBlack,  SymId::noSym            },
205       { SymId::noteGWhole,       SymId::noteGHalf,       SymId::noteGBlack,       SymId::noSym            },
206       { SymId::noteGFlatWhole,   SymId::noteGFlatHalf,   SymId::noteGFlatBlack,   SymId::noSym            },
207       { SymId::noteHWhole,       SymId::noteHHalf,       SymId::noteHBlack,       SymId::noSym            },
208       { SymId::noteHSharpWhole,  SymId::noteHSharpHalf,  SymId::noteHSharpBlack,  SymId::noSym            }
209 
210    }
211 };
212 
213 struct NoteHeadName {
214    const char* name;
215    const char* username;
216 };
217 
218 // same order as NoteHead::Scheme
219 static NoteHeadName noteHeadSchemeNames[] = {
220       {"auto",                QT_TRANSLATE_NOOP("noteheadschemes", "Auto") },
221       {"normal",              QT_TRANSLATE_NOOP("noteheadschemes", "Normal") },
222       {"name-pitch",          QT_TRANSLATE_NOOP("noteheadschemes", "Pitch Names") },
223       {"name-pitch-german",   QT_TRANSLATE_NOOP("noteheadschemes", "German Pitch Names") },
224       {"solfege-movable",     QT_TRANSLATE_NOOP("noteheadschemes", "Solf\u00e8ge Movable Do") }, // &egrave;
225       {"solfege-fixed",       QT_TRANSLATE_NOOP("noteheadschemes", "Solf\u00e8ge Fixed Do") },   // &egrave;
226       {"shape-4",             QT_TRANSLATE_NOOP("noteheadschemes", "4-shape (Walker)") },
227       {"shape-7-aikin",       QT_TRANSLATE_NOOP("noteheadschemes", "7-shape (Aikin)") },
228       {"shape-7-funk",        QT_TRANSLATE_NOOP("noteheadschemes", "7-shape (Funk)") },
229       {"shape-7-walker",      QT_TRANSLATE_NOOP("noteheadschemes", "7-shape (Walker)") }
230       };
231 
232 // same order as NoteHead::Group
233 static NoteHeadName noteHeadGroupNames[] = {
234       {"normal",         QT_TRANSLATE_NOOP("noteheadnames", "Normal") },
235       {"cross",          QT_TRANSLATE_NOOP("noteheadnames", "Cross") },
236       {"plus",           QT_TRANSLATE_NOOP("noteheadnames", "Plus") },
237       {"xcircle",        QT_TRANSLATE_NOOP("noteheadnames", "XCircle") },
238       {"withx",          QT_TRANSLATE_NOOP("noteheadnames", "With X") },
239       {"triangle-up",    QT_TRANSLATE_NOOP("noteheadnames", "Triangle Up") },
240       {"triangle-down",  QT_TRANSLATE_NOOP("noteheadnames", "Triangle Down") },
241       {"slashed1",       QT_TRANSLATE_NOOP("noteheadnames", "Slashed (Forwards)") },
242       {"slashed2",       QT_TRANSLATE_NOOP("noteheadnames", "Slashed (Backwards)") },
243       {"diamond",        QT_TRANSLATE_NOOP("noteheadnames", "Diamond") },
244       {"diamond-old",    QT_TRANSLATE_NOOP("noteheadnames", "Diamond (Old)") },
245       {"circled",        QT_TRANSLATE_NOOP("noteheadnames", "Circled") },
246       {"circled-large",  QT_TRANSLATE_NOOP("noteheadnames", "Circled Large") },
247       {"large-arrow",    QT_TRANSLATE_NOOP("noteheadnames", "Large Arrow") },
248       {"altbrevis",      QT_TRANSLATE_NOOP("noteheadnames", "Alt. Brevis") },
249 
250       {"slash",     QT_TRANSLATE_NOOP("noteheadnames", "Slash") },
251 
252       // shape notes
253       {"sol",       QT_TRANSLATE_NOOP("noteheadnames", "Sol") },
254       {"la",        QT_TRANSLATE_NOOP("noteheadnames", "La") },
255       {"fa",        QT_TRANSLATE_NOOP("noteheadnames", "Fa") },
256       {"mi",        QT_TRANSLATE_NOOP("noteheadnames", "Mi") },
257       {"do",        QT_TRANSLATE_NOOP("noteheadnames", "Do") },
258       {"re",        QT_TRANSLATE_NOOP("noteheadnames", "Re") },
259       {"ti",        QT_TRANSLATE_NOOP("noteheadnames", "Ti") },
260 
261       // not exposed
262       {"do-walker", QT_TRANSLATE_NOOP("noteheadnames", "Do (Walker)") },
263       {"re-walker", QT_TRANSLATE_NOOP("noteheadnames", "Re (Walker)") },
264       {"ti-walker", QT_TRANSLATE_NOOP("noteheadnames", "Ti (Walker)") },
265       {"do-funk",   QT_TRANSLATE_NOOP("noteheadnames", "Do (Funk)") },
266       {"re-funk",   QT_TRANSLATE_NOOP("noteheadnames", "Re (Funk)") },
267       {"ti-funk",   QT_TRANSLATE_NOOP("noteheadnames", "Ti (Funk)") },
268 
269       // note name
270       {"do-name",  QT_TRANSLATE_NOOP("noteheadnames",  "Do (Name)") },
271       {"re-name",  QT_TRANSLATE_NOOP("noteheadnames",  "Re (Name)") },
272       {"mi-name",  QT_TRANSLATE_NOOP("noteheadnames",  "Mi (Name)") },
273       {"fa-name",  QT_TRANSLATE_NOOP("noteheadnames",  "Fa (Name)") },
274       {"sol-name", QT_TRANSLATE_NOOP("noteheadnames",  "Sol (Name)") },
275       {"la-name",  QT_TRANSLATE_NOOP("noteheadnames",  "La (Name)") },
276       {"ti-name",  QT_TRANSLATE_NOOP("noteheadnames",  "Ti (Name)") },
277       {"si-name",  QT_TRANSLATE_NOOP("noteheadnames",  "Si (Name)") },
278 
279 
280       {"a-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "A♯ (Name)") },
281       {"a-name",       QT_TRANSLATE_NOOP("noteheadnames",  "A (Name)") },
282       {"a-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "A♭ (Name)") },
283       {"b-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "B♯ (Name)") },
284       {"b-name",       QT_TRANSLATE_NOOP("noteheadnames",  "B (Name)") },
285       {"b-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "B♭ (Name)") },
286       {"c-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "C♯ (Name)") },
287       {"c-name",       QT_TRANSLATE_NOOP("noteheadnames",  "C (Name)") },
288       {"c-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "C♭ (Name)") },
289       {"d-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "D♯ (Name)") },
290       {"d-name",       QT_TRANSLATE_NOOP("noteheadnames",  "D (Name)") },
291       {"d-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "D♭ (Name)") },
292       {"e-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "E♯ (Name)") },
293       {"e-name",       QT_TRANSLATE_NOOP("noteheadnames",  "E (Name)") },
294       {"e-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "E♭ (Name)") },
295       {"f-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "F♯ (Name)") },
296       {"f-name",       QT_TRANSLATE_NOOP("noteheadnames",  "F (Name)") },
297       {"f-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "F♭ (Name)") },
298       {"g-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "G♯ (Name)") },
299       {"g-name",       QT_TRANSLATE_NOOP("noteheadnames",  "G (Name)") },
300       {"g-flat-name",  QT_TRANSLATE_NOOP("noteheadnames",  "G♭ (Name)") },
301       {"h-name",       QT_TRANSLATE_NOOP("noteheadnames",  "H (Name)") },
302       {"h-sharp-name", QT_TRANSLATE_NOOP("noteheadnames",  "H♯ (Name)") },
303       {"custom",       QT_TRANSLATE_NOOP("noteheadnames",  "Custom") }
304       };
305 
306 // same order as NoteHead::Type
307 static NoteHeadName noteHeadTypeNames[] = {
308       {"auto",    QT_TRANSLATE_NOOP("noteheadnames", "Auto") },
309       {"whole",   QT_TRANSLATE_NOOP("noteheadnames", "Whole") },
310       {"half",    QT_TRANSLATE_NOOP("noteheadnames", "Half") },
311       {"quarter", QT_TRANSLATE_NOOP("noteheadnames", "Quarter") },
312       {"breve",   QT_TRANSLATE_NOOP("noteheadnames", "Breve") },
313       };
314 
315 //---------------------------------------------------------
316 //   scheme2userName
317 //---------------------------------------------------------
318 
scheme2userName(NoteHead::Scheme scheme)319 QString NoteHead::scheme2userName(NoteHead::Scheme scheme)
320       {
321       return qApp->translate("noteheadschemes", noteHeadSchemeNames[int(scheme) + 1].username);
322       }
323 
324 //---------------------------------------------------------
325 //   group2userName
326 //---------------------------------------------------------
327 
group2userName(NoteHead::Group group)328 QString NoteHead::group2userName(NoteHead::Group group)
329       {
330       return qApp->translate("noteheadnames", noteHeadGroupNames[int(group)].username);
331       }
332 
333 //---------------------------------------------------------
334 //   type2userName
335 //---------------------------------------------------------
336 
type2userName(NoteHead::Type type)337 QString NoteHead::type2userName(NoteHead::Type type)
338       {
339       return qApp->translate("noteheadnames", noteHeadTypeNames[int(type) + 1].username);
340       }
341 
342 //---------------------------------------------------------
343 //   scheme2name
344 //---------------------------------------------------------
345 
scheme2name(NoteHead::Scheme scheme)346 QString NoteHead::scheme2name(NoteHead::Scheme scheme)
347       {
348       return noteHeadSchemeNames[int(scheme) + 1].name;
349       }
350 
351 //---------------------------------------------------------
352 //   group2name
353 //---------------------------------------------------------
354 
group2name(NoteHead::Group group)355 QString NoteHead::group2name(NoteHead::Group group)
356       {
357       return noteHeadGroupNames[int(group)].name;
358       }
359 
360 //---------------------------------------------------------
361 //   type2name
362 //---------------------------------------------------------
363 
type2name(NoteHead::Type type)364 QString NoteHead::type2name(NoteHead::Type type)
365       {
366       return noteHeadTypeNames[int(type) + 1].name;
367       }
368 
369 //---------------------------------------------------------
370 //   name2scheme
371 //---------------------------------------------------------
372 
name2scheme(const QString & s)373 NoteHead::Scheme NoteHead::name2scheme(const QString& s)
374       {
375       for (int i = 0; i <= int(NoteHead::Scheme::HEAD_SCHEMES); ++i) {
376             if (noteHeadSchemeNames[i].name == s)
377                   return NoteHead::Scheme(i - 1);
378             }
379       return NoteHead::Scheme::HEAD_NORMAL;
380       }
381 
382 //---------------------------------------------------------
383 //   name2group
384 //---------------------------------------------------------
385 
name2group(const QString & s)386 NoteHead::Group NoteHead::name2group(const QString& s)
387       {
388       for (int i = 0; i < int(NoteHead::Group::HEAD_GROUPS); ++i) {
389             if (noteHeadGroupNames[i].name == s)
390                   return NoteHead::Group(i);
391             }
392       return NoteHead::Group::HEAD_NORMAL;
393       }
394 
395 //---------------------------------------------------------
396 //   name2type
397 //---------------------------------------------------------
398 
name2type(const QString & s)399 NoteHead::Type NoteHead::name2type(const QString& s)
400       {
401       for (int i = 0; i <= int(NoteHead::Type::HEAD_TYPES); ++i) {
402             if (noteHeadTypeNames[i].name == s)
403                   return NoteHead::Type(i - 1);
404             }
405       return NoteHead::Type::HEAD_AUTO;
406       }
407 
408 //---------------------------------------------------------
409 //   noteHead
410 //---------------------------------------------------------
411 
noteHead(int direction,NoteHead::Group group,NoteHead::Type t)412 SymId Note::noteHead(int direction, NoteHead::Group group, NoteHead::Type t)
413       {
414       return noteHeads[direction][int(group)][int(t)];
415       }
416 
noteHead(int direction,NoteHead::Group group,NoteHead::Type t,int tpc,Key key,NoteHead::Scheme scheme)417 SymId Note::noteHead(int direction, NoteHead::Group group, NoteHead::Type t, int tpc, Key key, NoteHead::Scheme scheme)
418       {
419       // shortcut
420       if (scheme == NoteHead::Scheme::HEAD_NORMAL)
421             return noteHeads[direction][int(group)][int(t)];
422       // other schemes
423       if (scheme == NoteHead::Scheme::HEAD_PITCHNAME || scheme == NoteHead::Scheme::HEAD_PITCHNAME_GERMAN) {
424             if (tpc == Tpc::TPC_A)
425                   group = NoteHead::Group::HEAD_A;
426             else if (tpc == Tpc::TPC_B) {
427                   if (scheme == NoteHead::Scheme::HEAD_PITCHNAME_GERMAN)
428                         group = NoteHead::Group::HEAD_H;
429                   else
430                         group = NoteHead::Group::HEAD_B;
431                   }
432             else if (tpc == Tpc::TPC_C)
433                   group = NoteHead::Group::HEAD_C;
434             else if (tpc == Tpc::TPC_D)
435                   group = NoteHead::Group::HEAD_D;
436             else if (tpc == Tpc::TPC_E)
437                   group = NoteHead::Group::HEAD_E;
438             else if (tpc == Tpc::TPC_F)
439                   group = NoteHead::Group::HEAD_F;
440             else if (tpc == Tpc::TPC_G)
441                   group = NoteHead::Group::HEAD_G;
442             else if (tpc == Tpc::TPC_A_S)
443                   group = NoteHead::Group::HEAD_A_SHARP;
444             else if (tpc == Tpc::TPC_B_S)
445                   if (scheme == NoteHead::Scheme::HEAD_PITCHNAME_GERMAN)
446                         group = NoteHead::Group::HEAD_H_SHARP;
447                   else
448                         group = NoteHead::Group::HEAD_B_SHARP;
449             else if (tpc == Tpc::TPC_C_S)
450                   group = NoteHead::Group::HEAD_C_SHARP;
451             else if (tpc == Tpc::TPC_D_S)
452                   group = NoteHead::Group::HEAD_D_SHARP;
453             else if (tpc == Tpc::TPC_E_S)
454                   group = NoteHead::Group::HEAD_E_SHARP;
455             else if (tpc == Tpc::TPC_F_S)
456                   group = NoteHead::Group::HEAD_F_SHARP;
457             else if (tpc == Tpc::TPC_G_S)
458                   group = NoteHead::Group::HEAD_G_SHARP;
459             else if (tpc == Tpc::TPC_A_B)
460                   group = NoteHead::Group::HEAD_A_FLAT;
461             else if (tpc == Tpc::TPC_B_B)
462                   if (scheme == NoteHead::Scheme::HEAD_PITCHNAME_GERMAN)
463                         group = NoteHead::Group::HEAD_B;
464                   else
465                         group = NoteHead::Group::HEAD_B_FLAT;
466             else if (tpc == Tpc::TPC_C_B)
467                   group = NoteHead::Group::HEAD_C_FLAT;
468             else if (tpc == Tpc::TPC_D_B)
469                   group = NoteHead::Group::HEAD_D_FLAT;
470             else if (tpc == Tpc::TPC_E_B)
471                   group = NoteHead::Group::HEAD_E_FLAT;
472             else if (tpc == Tpc::TPC_F_B)
473                   group = NoteHead::Group::HEAD_F_FLAT;
474             else if (tpc == Tpc::TPC_G_B)
475                   group = NoteHead::Group::HEAD_G_FLAT;
476             }
477       else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_4) {
478             int degree = tpc2degree(tpc, key);
479             switch (degree) {
480                   case 0:
481                   case 3:
482                         group = NoteHead::Group::HEAD_FA; break;
483                   case 1:
484                   case 4:
485                         group = NoteHead::Group::HEAD_SOL; break;
486                   case 2:
487                   case 5:
488                         group = NoteHead::Group::HEAD_LA; break;
489                   case 6:
490                         group = NoteHead::Group::HEAD_MI; break;
491                   }
492             }
493       else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_AIKIN
494          || scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_FUNK
495          || scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_WALKER) {
496             int degree = tpc2degree(tpc, key);
497             switch (degree) {
498                   case 0:
499                         if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_AIKIN)
500                               group = NoteHead::Group::HEAD_DO;
501                         else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_FUNK)
502                               group = NoteHead::Group::HEAD_DO_FUNK;
503                         else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_WALKER)
504                               group = NoteHead::Group::HEAD_DO_WALKER;
505                         break;
506                   case 1:
507                         if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_AIKIN)
508                               group = NoteHead::Group::HEAD_RE;
509                         else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_FUNK)
510                               group = NoteHead::Group::HEAD_RE_FUNK;
511                         else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_WALKER)
512                               group = NoteHead::Group::HEAD_RE_WALKER;
513                         break;
514                   case 2:
515                         group = NoteHead::Group::HEAD_MI; break;
516                   case 3:
517                         group = NoteHead::Group::HEAD_FA; break;
518                   case 4:
519                         group = NoteHead::Group::HEAD_SOL; break;
520                   case 5:
521                         group = NoteHead::Group::HEAD_LA; break;
522                   case 6:
523                         if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_AIKIN)
524                               group = NoteHead::Group::HEAD_TI;
525                         else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_FUNK)
526                               group = NoteHead::Group::HEAD_TI_FUNK;
527                         else if (scheme == NoteHead::Scheme::HEAD_SHAPE_NOTE_7_WALKER)
528                               group = NoteHead::Group::HEAD_TI_WALKER;
529                         break;
530                   }
531             }
532       else if (scheme == NoteHead::Scheme::HEAD_SOLFEGE) {
533             int degree = tpc2degree(tpc, key);
534             switch (degree) {
535                   case 0:
536                         group = NoteHead::Group::HEAD_DO_NAME; break;
537                   case 1:
538                         group = NoteHead::Group::HEAD_RE_NAME; break;
539                   case 2:
540                         group = NoteHead::Group::HEAD_MI_NAME; break;
541                   case 3:
542                         group = NoteHead::Group::HEAD_FA_NAME; break;
543                   case 4:
544                         group = NoteHead::Group::HEAD_SOL_NAME; break;
545                   case 5:
546                         group = NoteHead::Group::HEAD_LA_NAME; break;
547                   case 6:
548                         group = NoteHead::Group::HEAD_TI_NAME; break;
549                   }
550             }
551       else if (scheme == NoteHead::Scheme::HEAD_SOLFEGE_FIXED) {
552             QString stepName = tpc2stepName(tpc);
553             if (stepName == "C")
554                   group = NoteHead::Group::HEAD_DO_NAME;
555             else if (stepName == "D")
556                   group = NoteHead::Group::HEAD_RE_NAME;
557             else if (stepName == "E")
558                   group = NoteHead::Group::HEAD_MI_NAME;
559             else if (stepName == "F")
560                   group = NoteHead::Group::HEAD_FA_NAME;
561             else if (stepName == "G")
562                   group = NoteHead::Group::HEAD_SOL_NAME;
563             else if (stepName == "A")
564                   group = NoteHead::Group::HEAD_LA_NAME;
565             else if (stepName == "B")
566                   group = NoteHead::Group::HEAD_SI_NAME;
567             }
568       return noteHeads[direction][int(group)][int(t)];
569       };
570 
571 //---------------------------------------------------------
572 //   headGroup
573 //   used only when dropping a notehead from the palette
574 //   they are either half note, either double whole
575 //---------------------------------------------------------
576 
headGroup() const577 NoteHead::Group NoteHead::headGroup() const
578       {
579       Group group = Group::HEAD_INVALID;
580       for (int i = 0; i < int(Group::HEAD_DO_WALKER); ++i) {
581             if (noteHeads[0][i][1] == _sym || noteHeads[0][i][3] == _sym) {
582                   group = (Group)i;
583                         break;
584                   }
585             }
586       return group;
587       }
588 
589 //---------------------------------------------------------
590 //   Note
591 //---------------------------------------------------------
592 
Note(Score * s)593 Note::Note(Score* s)
594    : Element(s, ElementFlag::MOVABLE)
595       {
596       _playEvents.append(NoteEvent());    // add default play event
597       _cachedNoteheadSym = SymId::noSym;
598       _cachedSymNull = SymId::noSym;
599       }
600 
~Note()601 Note::~Note()
602       {
603       delete _accidental;
604       qDeleteAll(_el);
605       delete _tieFor;
606       qDeleteAll(_dots);
607       }
608 
Note(const Note & n,bool link)609 Note::Note(const Note& n, bool link)
610    : Element(n)
611       {
612       if (link)
613             score()->undo(new Link(this, const_cast<Note*>(&n)));
614       _subchannel        = n._subchannel;
615       _line              = n._line;
616       _fret              = n._fret;
617       _string            = n._string;
618       _fretConflict      = n._fretConflict;
619       _ghost             = n._ghost;
620       dragMode           = n.dragMode;
621       _pitch             = n._pitch;
622       _tpc[0]            = n._tpc[0];
623       _tpc[1]            = n._tpc[1];
624       _dotsHidden        = n._dotsHidden;
625       _hidden            = n._hidden;
626       _play              = n._play;
627       _tuning            = n._tuning;
628       _veloType          = n._veloType;
629       _veloOffset        = n._veloOffset;
630       _headScheme        = n._headScheme;
631       _headGroup         = n._headGroup;
632       _headType          = n._headType;
633       _mirror            = n._mirror;
634       _userMirror        = n._userMirror;
635       _small             = n._small;
636       _userDotPosition   = n._userDotPosition;
637       _fixed             = n._fixed;
638       _fixedLine         = n._fixedLine;
639       _accidental        = 0;
640       _cachedNoteheadSym = n._cachedNoteheadSym;
641       _cachedSymNull     = n._cachedSymNull;
642 
643       if (n._accidental)
644             add(new Accidental(*(n._accidental)));
645 
646       // types in _el: SYMBOL, IMAGE, FINGERING, TEXT, BEND
647       const Staff* stf = staff();
648       bool tabFingering = stf->staffTypeForElement(this)->showTabFingering();
649       for (Element* e : n._el) {
650             if (e->isFingering() && staff()->isTabStaff(tick()) && !tabFingering)    // tablature has no fingering
651                   continue;
652             Element* ce = e->clone();
653             add(ce);
654             if (link)
655                   score()->undo(new Link(ce, const_cast<Element*>(e)));
656             }
657 
658       _playEvents = n._playEvents;
659 
660       if (n._tieFor) {
661             _tieFor = new Tie(*n._tieFor);
662             _tieFor->setStartNote(this);
663             _tieFor->setTick(_tieFor->startNote()->tick());
664             _tieFor->setEndNote(0);
665             }
666       else
667             _tieFor = 0;
668       _tieBack  = 0;
669       for (NoteDot* dot : n._dots)
670             add(new NoteDot(*dot));
671       _mark      = n._mark;
672       }
673 
674 //---------------------------------------------------------
675 //   concertPitchIdx
676 //---------------------------------------------------------
677 
concertPitchIdx() const678 inline int Note::concertPitchIdx() const
679       {
680       return concertPitch() ? 0 : 1;
681       }
682 
683 //---------------------------------------------------------
684 //   setPitch
685 //---------------------------------------------------------
686 
setPitch(int val)687 void Note::setPitch(int val)
688       {
689       Q_ASSERT(pitchIsValid(val));
690       if (_pitch != val) {
691             _pitch = val;
692             score()->setPlaylistDirty();
693             }
694       }
695 
setPitch(int pitch,int tpc1,int tpc2)696 void Note::setPitch(int pitch, int tpc1, int tpc2)
697       {
698       Q_ASSERT(tpcIsValid(tpc1));
699       Q_ASSERT(tpcIsValid(tpc2));
700       _tpc[0] = tpc1;
701       _tpc[1] = tpc2;
702       setPitch(pitch);
703       }
704 
705 //---------------------------------------------------------
706 //   tpc1default
707 //---------------------------------------------------------
708 
tpc1default(int p) const709 int Note::tpc1default(int p) const
710       {
711       Key key = Key::C;
712       if (staff() && chord()) {
713             Fraction tick = chord()->tick();
714             key = staff()->key(tick);
715             if (!concertPitch()) {
716                   Interval interval = part()->instrument(tick)->transpose();
717                   if (!interval.isZero()) {
718                         interval.flip();
719                         key = transposeKey(key, interval);
720                         }
721                   }
722             }
723       return pitch2tpc(p, key, Prefer::NEAREST);
724       }
725 
726 //---------------------------------------------------------
727 //   tpc2default
728 //---------------------------------------------------------
729 
tpc2default(int p) const730 int Note::tpc2default(int p) const
731       {
732       Key key = Key::C;
733       if (staff() && chord()) {
734             Fraction tick = chord()->tick();
735             key = staff()->key(tick);
736             if (concertPitch()) {
737                   Interval interval = part()->instrument(tick)->transpose();
738                   if (!interval.isZero())
739                         key = transposeKey(key, interval);
740                   }
741             }
742       return pitch2tpc(p - transposition(), key, Prefer::NEAREST);
743       }
744 
745 //---------------------------------------------------------
746 //   setTpcFromPitch
747 //---------------------------------------------------------
748 
setTpcFromPitch()749 void Note::setTpcFromPitch()
750       {
751       // works best if note is already added to score, otherwise we can't determine transposition or key
752       Fraction tick = chord() ? chord()->tick() : Fraction(-1,1);
753       Interval v = staff() ? part()->instrument(tick)->transpose() : Interval();
754       Key key = (staff() && chord()) ? staff()->key(chord()->tick()) : Key::C;
755       // convert key to concert pitch
756       if (!concertPitch() && !v.isZero())
757             key = transposeKey(key, v);
758       // set concert pitch tpc
759       _tpc[0] = pitch2tpc(_pitch, key, Prefer::NEAREST);
760       // set transposed tpc
761       if (v.isZero())
762             _tpc[1] = _tpc[0];
763       else {
764             v.flip();
765             _tpc[1] = Ms::transposeTpc(_tpc[0], v, true);
766             }
767       Q_ASSERT(tpcIsValid(_tpc[0]));
768       Q_ASSERT(tpcIsValid(_tpc[1]));
769       }
770 
771 //---------------------------------------------------------
772 //   setTpc
773 //---------------------------------------------------------
774 
setTpc(int v)775 void Note::setTpc(int v)
776       {
777       if (!tpcIsValid(v))
778             qFatal("Note::setTpc: bad tpc %d", v);
779       _tpc[concertPitchIdx()] = v;
780       }
781 
782 //---------------------------------------------------------
783 //   undoSetTpc
784 //    change the current tpc
785 //---------------------------------------------------------
786 
undoSetTpc(int v)787 void Note::undoSetTpc(int v)
788       {
789       if (concertPitch()) {
790             if (v != tpc1())
791                   undoChangeProperty(Pid::TPC1, v);
792             }
793       else {
794             if (v != tpc2())
795                   undoChangeProperty(Pid::TPC2, v);
796             }
797       }
798 
799 //---------------------------------------------------------
800 //   tpc
801 //---------------------------------------------------------
802 
tpc() const803 int Note::tpc() const
804       {
805       return _tpc[concertPitchIdx()];
806       }
807 
808 //---------------------------------------------------------
809 //   tpcUserName
810 //---------------------------------------------------------
811 
tpcUserName(const int tpc,const int pitch,const bool explicitAccidental)812 QString Note::tpcUserName(const int tpc, const int pitch, const bool explicitAccidental)
813       {
814       const auto pitchStr = qApp->translate("InspectorAmbitus", tpc2name(tpc, NoteSpellingType::STANDARD, NoteCaseType::AUTO, explicitAccidental).replace("b", "♭").replace("#", "♯").toUtf8().constData());
815       const auto octaveStr = QString::number(((pitch - static_cast<int>(tpc2alter(tpc))) / PITCH_DELTA_OCTAVE) - 1);
816 
817       return pitchStr + (explicitAccidental ? " " : "") + octaveStr;
818       };
819 
820 //---------------------------------------------------------
821 //   tpcUserName
822 //---------------------------------------------------------
823 
tpcUserName(const bool explicitAccidental) const824 QString Note::tpcUserName(const bool explicitAccidental) const
825       {
826       QString pitchName = tpcUserName(tpc(), epitch() + ottaveCapoFret(), explicitAccidental);
827 
828       if (fixed() && headGroup() == NoteHead::Group::HEAD_SLASH)
829             // see Note::accessibleInfo(), but we return what we have
830             return pitchName;
831       if (staff()->isDrumStaff(tick()) && part()->instrument()->drumset())
832             // see Note::accessibleInfo(), but we return what we have
833             return pitchName;
834       if (staff()->isTabStaff(tick()))
835             // no further translation
836             return pitchName;
837 
838       QString pitchOffset;
839       if (tuning() != 0)
840             pitchOffset = QString::asprintf("%+.3f", tuning());
841 
842       if (!concertPitch() && transposition()) {
843             QString soundingPitch = tpcUserName(tpc1(), ppitch(), explicitAccidental);
844             return QObject::tr("%1 (sounding as %2%3)").arg(pitchName, soundingPitch, pitchOffset);
845             }
846       return pitchName + pitchOffset;
847       }
848 
849 //---------------------------------------------------------
850 //   transposeTpc
851 //    return transposed tpc
852 //    If in concertPitch mode return tpc for transposed view
853 //    else return tpc for concert pitch view.
854 //---------------------------------------------------------
855 
transposeTpc(int tpc)856 int Note::transposeTpc(int tpc)
857       {
858       Fraction tick = chord() ? chord()->tick() : Fraction(-1,1);
859       Interval v = part()->instrument(tick)->transpose();
860       if (v.isZero())
861             return tpc;
862       if (concertPitch()) {
863             v.flip();
864             return Ms::transposeTpc(tpc, v, true);
865             }
866       else
867             return Ms::transposeTpc(tpc, v, true);
868       }
869 
870 //---------------------------------------------------------
871 //   noteHead
872 //---------------------------------------------------------
873 
noteHead() const874 SymId Note::noteHead() const
875       {
876       int up;
877       NoteHead::Type ht;
878       if (chord()) {
879             up = chord()->up();
880             ht = chord()->durationType().headType();
881             }
882       else {
883             up = 1;
884             ht = NoteHead::Type::HEAD_QUARTER;
885             }
886       if (_headType != NoteHead::Type::HEAD_AUTO)
887             ht = _headType;
888 
889       const Staff* st = chord() ? chord()->staff() : nullptr;
890 
891       if (_headGroup == NoteHead::Group::HEAD_CUSTOM) {
892             if (st) {
893                   if (st->staffTypeForElement(chord())->isDrumStaff()) {
894                         Fraction t = chord()->tick();
895                         Instrument* inst = st->part()->instrument(t);
896                         Drumset* d = inst->drumset();
897                         if (d) {
898                               return d->noteHeads(_pitch, ht);
899                               }
900                         else {
901                               qDebug("no drumset");
902                               return noteHead(up, NoteHead::Group::HEAD_NORMAL, ht);
903                               }
904                         }
905                   }
906             else {
907                   return _cachedNoteheadSym;
908                   }
909             }
910 
911       Key key = Key::C;
912       NoteHead::Scheme scheme = _headScheme;
913       if (st) {
914             Fraction tick = chord()->tick();
915             if (tick >= Fraction(0,1)) {
916                   key    = st->key(tick);
917                   if (scheme == NoteHead::Scheme::HEAD_AUTO)
918                         scheme = st->staffTypeForElement(chord())->noteHeadScheme();
919                   }
920             }
921       if (scheme == NoteHead::Scheme::HEAD_AUTO)
922             scheme = NoteHead::Scheme::HEAD_NORMAL;
923       SymId t = noteHead(up, _headGroup, ht, tpc(), key, scheme);
924       if (t == SymId::noSym) {
925             qDebug("invalid notehead %d/%d", int(_headGroup), int(ht));
926             t = noteHead(up, NoteHead::Group::HEAD_NORMAL, ht);
927             }
928       return t;
929       }
930 
931 //---------------------------------------------------------
932 //   headWidth
933 //
934 //    returns the x of the symbol bbox. It is different from headWidth() because zero point could be different from leftmost bbox position.
935 //---------------------------------------------------------
bboxRightPos() const936 qreal Note::bboxRightPos() const
937       {
938       const auto& bbox = score()->scoreFont()->bbox(noteHead(), magS());
939       return bbox.right();
940       }
941 
942 //---------------------------------------------------------
943 //   headBodyWidth
944 //
945 //    returns the width of the notehead "body". It is actual for slashed noteheads like -O-, where O is body.
946 //---------------------------------------------------------
headBodyWidth() const947 qreal Note::headBodyWidth() const
948       {
949       return headWidth() + 2 * bboxXShift();
950       }
951 
952 //---------------------------------------------------------
953 //   headWidth
954 //
955 //    returns the width of the symbol bbox
956 //    or the width of the string representation of the fret mark
957 //---------------------------------------------------------
958 
headWidth() const959 qreal Note::headWidth() const
960       {
961       return symWidth(noteHead());
962       }
963 
964 //---------------------------------------------------------
965 //   bboxXShift
966 //
967 //    returns the x shift of the notehead bounding box
968 //---------------------------------------------------------
bboxXShift() const969 qreal Note::bboxXShift() const
970       {
971       const auto& bbox = score()->scoreFont()->bbox(noteHead(), magS());
972       return bbox.bottomLeft().x();
973       }
974 
975 //---------------------------------------------------------
976 //   noteheadCenterX
977 //
978 //    returns the x coordinate of the notehead center related to the basepoint of the notehead bbox
979 //---------------------------------------------------------
noteheadCenterX() const980 qreal Note::noteheadCenterX() const
981       {
982       return score()->scoreFont()->width(noteHead(), magS()) / 2 + bboxXShift();
983       }
984 //---------------------------------------------------------
985 //   tabHeadWidth
986 //---------------------------------------------------------
987 
tabHeadWidth(const StaffType * tab) const988 qreal Note::tabHeadWidth(const StaffType* tab) const
989       {
990       qreal val;
991       if (tab && _fret != FRET_NONE && _string != STRING_NONE) {
992             QFont f    = tab->fretFont();
993             f.setPointSizeF(tab->fretFontSize());
994             QFontMetricsF fm(f, MScore::paintDevice());
995             val  = fm.width(_fretString) * magS();
996             }
997       else
998             val = headWidth();
999       return val;
1000       }
1001 
1002 //---------------------------------------------------------
1003 //   headHeight
1004 //
1005 //    returns the height of the notehead symbol
1006 //    or the height of the string representation of the fret mark
1007 //---------------------------------------------------------
1008 
headHeight() const1009 qreal Note::headHeight() const
1010       {
1011       return symHeight(noteHead());
1012       }
1013 
1014 //---------------------------------------------------------
1015 //   tabHeadHeight
1016 //---------------------------------------------------------
1017 
tabHeadHeight(const StaffType * tab) const1018 qreal Note::tabHeadHeight(const StaffType* tab) const
1019       {
1020       if (tab && _fret != FRET_NONE && _string != STRING_NONE)
1021             return tab->fretBoxH() * magS();
1022       return headHeight();
1023       }
1024 
1025 //---------------------------------------------------------
1026 //   stemDownNW
1027 //---------------------------------------------------------
1028 
stemDownNW() const1029 QPointF Note::stemDownNW() const
1030       {
1031       return symStemDownNW(noteHead());
1032       }
1033 
1034 //---------------------------------------------------------
1035 //   stemUpSE
1036 //---------------------------------------------------------
1037 
stemUpSE() const1038 QPointF Note::stemUpSE() const
1039       {
1040       return symStemUpSE(noteHead());
1041       }
1042 
1043 //---------------------------------------------------------
1044 //   playTicks
1045 ///   Return total tick len of tied notes
1046 //---------------------------------------------------------
1047 
playTicks() const1048 int Note::playTicks() const
1049       {
1050       return playTicksFraction().ticks();
1051       }
1052 
1053 //---------------------------------------------------------
1054 //   playTicksFraction
1055 ///   Return total tick len of tied notes
1056 //---------------------------------------------------------
1057 
playTicksFraction() const1058 Fraction Note::playTicksFraction() const
1059       {
1060       Fraction stick = firstTiedNote()->chord()->tick();
1061       const Note* note = lastTiedNote();
1062       return note->chord()->tick() + note->chord()->actualTicks() - stick;
1063       }
1064 
1065 //---------------------------------------------------------
1066 //   addSpanner
1067 //---------------------------------------------------------
1068 
addSpanner(Spanner * l)1069 void Note::addSpanner(Spanner* l)
1070       {
1071       Element* e = l->endElement();
1072       if (e && e->isNote()) {
1073             Note* note = toNote(e);
1074             note->addSpannerBack(l);
1075             if (l->isGlissando())
1076                  note->chord()->setEndsGlissando(true);
1077             }
1078       addSpannerFor(l);
1079       }
1080 
1081 //---------------------------------------------------------
1082 //   removeSpanner
1083 //---------------------------------------------------------
1084 
removeSpanner(Spanner * l)1085 void Note::removeSpanner(Spanner* l)
1086       {
1087       Note* e = toNote(l->endElement());
1088       if (e && e->isNote()) {
1089             if (!e->removeSpannerBack(l)) {
1090                   qDebug("Note::removeSpanner(%p): cannot remove spannerBack %s %p", this, l->name(), l);
1091                   // abort();
1092                   }
1093             if (l->isGlissando())
1094                  e->chord()->updateEndsGlissando();
1095             }
1096       if (!removeSpannerFor(l)) {
1097             qDebug("Note(%p): cannot remove spannerFor %s %p", this, l->name(), l);
1098             // abort();
1099             }
1100       }
1101 
1102 //---------------------------------------------------------
1103 //   add
1104 //---------------------------------------------------------
1105 
add(Element * e)1106 void Note::add(Element* e)
1107       {
1108       e->setParent(this);
1109       e->setTrack(track());
1110 
1111       switch(e->type()) {
1112             case ElementType::NOTEDOT:
1113                   _dots.append(toNoteDot(e));
1114                   break;
1115             case ElementType::FINGERING:
1116             case ElementType::SYMBOL:
1117             case ElementType::IMAGE:
1118             case ElementType::TEXT:
1119             case ElementType::BEND:
1120                   _el.push_back(e);
1121                   break;
1122             case ElementType::TIE: {
1123                   Tie* tie = toTie(e);
1124                   tie->setStartNote(this);
1125                   tie->setTick(tie->startNote()->tick());
1126                   tie->setTrack(track());
1127                   setTieFor(tie);
1128                   if (tie->endNote())
1129                         tie->endNote()->setTieBack(tie);
1130                   }
1131                   break;
1132             case ElementType::ACCIDENTAL:
1133                   _accidental = toAccidental(e);
1134                   break;
1135             case ElementType::TEXTLINE:
1136             case ElementType::GLISSANDO:
1137                   addSpanner(toSpanner(e));
1138                   break;
1139             default:
1140                   qDebug("Note::add() not impl. %s", e->name());
1141                   break;
1142             }
1143       triggerLayout();
1144       }
1145 
1146 //---------------------------------------------------------
1147 //   remove
1148 //---------------------------------------------------------
1149 
remove(Element * e)1150 void Note::remove(Element* e)
1151       {
1152       switch(e->type()) {
1153             case ElementType::NOTEDOT:
1154                   _dots.takeLast();
1155                   break;
1156 
1157             case ElementType::TEXT:
1158             case ElementType::SYMBOL:
1159             case ElementType::IMAGE:
1160             case ElementType::FINGERING:
1161             case ElementType::BEND:
1162                   if (!_el.remove(e))
1163                         qDebug("Note::remove(): cannot find %s", e->name());
1164                   break;
1165             case ElementType::TIE: {
1166                   Tie* tie = toTie(e);
1167                   setTieFor(0);
1168                   if (tie->endNote())
1169                         tie->endNote()->setTieBack(0);
1170                   }
1171                   break;
1172 
1173             case ElementType::ACCIDENTAL:
1174                   _accidental = 0;
1175                   break;
1176 
1177             case ElementType::TEXTLINE:
1178             case ElementType::GLISSANDO:
1179                   removeSpanner(toSpanner(e));
1180                   break;
1181 
1182             default:
1183                   qDebug("Note::remove() not impl. %s", e->name());
1184                   break;
1185             }
1186       triggerLayout();
1187       }
1188 
1189 //---------------------------------------------------------
1190 //   isNoteName
1191 //---------------------------------------------------------
1192 
isNoteName() const1193 bool Note::isNoteName() const
1194       {
1195       if (chord() && chord()->staff()) {
1196             const Staff* st = staff();
1197             NoteHead::Scheme s = _headScheme;
1198             if (s == NoteHead::Scheme::HEAD_AUTO)
1199                   s = st->staffTypeForElement(this)->noteHeadScheme();
1200             return s == NoteHead::Scheme::HEAD_PITCHNAME || s == NoteHead::Scheme::HEAD_PITCHNAME_GERMAN || s == NoteHead::Scheme::HEAD_SOLFEGE || s == NoteHead::Scheme::HEAD_SOLFEGE_FIXED;
1201 
1202             }
1203       return false;
1204       }
1205 
1206 //---------------------------------------------------------
1207 //   draw
1208 //---------------------------------------------------------
1209 
draw(QPainter * painter) const1210 void Note::draw(QPainter* painter) const
1211       {
1212       if (_hidden)
1213             return;
1214 
1215       QColor c(curColor());
1216       painter->setPen(c);
1217       bool tablature = staff() && staff()->isTabStaff(chord()->tick());
1218 
1219       // tablature
1220       if (tablature) {
1221             const Staff* st = staff();
1222             const StaffType* tab = st->staffTypeForElement(this);
1223             if (tieBack() && !tab->showBackTied()) {
1224                   if (chord()->measure()->system() == tieBack()->startNote()->chord()->measure()->system() && el().size() == 0)
1225                         // fret should be hidden, so return without drawing it
1226                         return;
1227                   }
1228             // draw background, if required (to hide a segment of string line or to show a fretting conflict)
1229             if (!tab->linesThrough() || fretConflict()) {
1230                   qreal d  = spatium() * .1;
1231                   QRectF bb = QRectF(bbox().x()-d, tab->fretMaskY() * magS(), bbox().width() + 2 * d, tab->fretMaskH()*magS());
1232                   // we do not know which viewer did this draw() call
1233                   // so update all:
1234                   if (!score()->getViewer().empty()) {
1235                         for (MuseScoreView* view : score()->getViewer())
1236                               view->drawBackground(painter, bb);
1237                         }
1238                   else
1239                         painter->fillRect(bb, Qt::white);
1240 
1241                   if (fretConflict() && !score()->printing() && score()->showUnprintable()) {          //on fret conflict, draw on red background
1242                         painter->save();
1243                         painter->setPen(Qt::red);
1244                         painter->setBrush(QBrush(QColor(Qt::red)));
1245                         painter->drawRect(bb);
1246                         painter->restore();
1247                         }
1248                   }
1249             QFont f(tab->fretFont());
1250             f.setPointSizeF(f.pointSizeF() * magS() * MScore::pixelRatio);
1251             painter->setFont(f);
1252             painter->setPen(c);
1253             painter->drawText(QPointF(bbox().x(), tab->fretFontYOffset()), _fretString);
1254             }
1255 
1256       // NOT tablature
1257 
1258       else {
1259             // skip drawing, if second note of a cross-measure value
1260             if (chord() && chord()->crossMeasure() == CrossMeasure::SECOND)
1261                   return;
1262             // warn if pitch extends usable range of instrument
1263             // by coloring the notehead
1264             if (chord() && chord()->segment() && staff()
1265                && !score()->printing() && MScore::warnPitchRange && !staff()->isDrumStaff(chord()->tick())) {
1266                   const Instrument* in = part()->instrument(chord()->tick());
1267                   int i = ppitch();
1268                   if (i < in->minPitchP() || i > in->maxPitchP())
1269                         painter->setPen(selected() ? Qt::darkRed : Qt::red);
1270                   else if (i < in->minPitchA() || i > in->maxPitchA())
1271                         painter->setPen(selected() ? QColor("#565600") : Qt::darkYellow);
1272                   }
1273             // draw blank notehead to avoid staff and ledger lines
1274             if (_cachedSymNull != SymId::noSym) {
1275                   painter->save();
1276                   painter->setPen(Qt::white);
1277                   drawSymbol(_cachedSymNull, painter);
1278                   painter->restore();
1279                   }
1280             drawSymbol(_cachedNoteheadSym, painter);
1281             }
1282       }
1283 
1284 //--------------------------------------------------
1285 //   Note::write
1286 //---------------------------------------------------------
1287 
write(XmlWriter & xml) const1288 void Note::write(XmlWriter& xml) const
1289       {
1290       xml.stag(this);
1291       Element::writeProperties(xml);
1292 
1293       if (_accidental)
1294             _accidental->write(xml);
1295       _el.write(xml);
1296       bool write_dots = false;
1297       for (NoteDot* dot : _dots)
1298             if (!dot->offset().isNull() || !dot->visible() || dot->color() != Qt::black || dot->visible() != visible()) {
1299                   write_dots = true;
1300                   break;
1301                   }
1302       if (write_dots)
1303             for (NoteDot* dot : _dots)
1304                   dot->write(xml);
1305       if (_tieFor)
1306             _tieFor->writeSpannerStart(xml, this, track());
1307       if (_tieBack)
1308             _tieBack->writeSpannerEnd(xml, this, track());
1309       if ((chord() == 0 || chord()->playEventType() != PlayEventType::Auto) && !_playEvents.empty()) {
1310             xml.stag("Events");
1311             for (const NoteEvent& e : _playEvents)
1312                   e.write(xml);
1313             xml.etag();
1314             }
1315       for (Pid id : { Pid::PITCH, Pid::TPC1, Pid::TPC2, Pid::SMALL, Pid::MIRROR_HEAD, Pid::DOT_POSITION,
1316          Pid::HEAD_SCHEME, Pid::HEAD_GROUP, Pid::VELO_OFFSET, Pid::PLAY, Pid::TUNING, Pid::FRET, Pid::STRING,
1317          Pid::GHOST, Pid::HEAD_TYPE, Pid::VELO_TYPE, Pid::FIXED, Pid::FIXED_LINE
1318             }) {
1319             writeProperty(xml, id);
1320             }
1321 
1322       for (Spanner* e : _spannerFor)
1323             e->writeSpannerStart(xml, this, track());
1324       for (Spanner* e : _spannerBack)
1325             e->writeSpannerEnd(xml, this, track());
1326 
1327       xml.etag();
1328       }
1329 
1330 //---------------------------------------------------------
1331 //   Note::read
1332 //---------------------------------------------------------
1333 
read(XmlReader & e)1334 void Note::read(XmlReader& e)
1335       {
1336       setTpc1(Tpc::TPC_INVALID);
1337       setTpc2(Tpc::TPC_INVALID);
1338 
1339       while (e.readNextStartElement()) {
1340             if (readProperties(e))
1341                   ;
1342             else
1343                   e.unknown();
1344             }
1345       // ensure sane values:
1346       _pitch = limit(_pitch, 0, 127);
1347 
1348       if (!tpcIsValid(_tpc[0]) && !tpcIsValid(_tpc[1])) {
1349             Key key = (staff() && chord()) ? staff()->key(chord()->tick()) : Key::C;
1350             int tpc = pitch2tpc(_pitch, key, Prefer::NEAREST);
1351             if (concertPitch())
1352                   _tpc[0] = tpc;
1353             else
1354                   _tpc[1] = tpc;
1355             }
1356       if (!(tpcIsValid(_tpc[0]) && tpcIsValid(_tpc[1]))) {
1357             Fraction tick = chord() ? chord()->tick() : Fraction(-1,1);
1358             Interval v = staff() ? part()->instrument(tick)->transpose() : Interval();
1359             if (tpcIsValid(_tpc[0])) {
1360                   v.flip();
1361                   if (v.isZero())
1362                         _tpc[1] = _tpc[0];
1363                   else
1364                         _tpc[1] = Ms::transposeTpc(_tpc[0], v, true);
1365                   }
1366             else {
1367                   if (v.isZero())
1368                         _tpc[0] = _tpc[1];
1369                   else
1370                         _tpc[0] = Ms::transposeTpc(_tpc[1], v, true);
1371                   }
1372             }
1373 
1374       // check consistency of pitch, tpc1, tpc2, and transposition
1375       // see note in InstrumentChange::read() about a known case of tpc corruption produced in 2.0.x
1376       // but since there are other causes of tpc corruption (eg, https://musescore.org/en/node/74746)
1377       // including perhaps some we don't know about yet,
1378       // we will attempt to fix some problems here regardless of version
1379 
1380       if (staff() && !staff()->isDrumStaff(e.tick()) && !e.pasteMode() && !MScore::testMode) {
1381             int tpc1Pitch = (tpc2pitch(_tpc[0]) + 12) % 12;
1382             int tpc2Pitch = (tpc2pitch(_tpc[1]) + 12) % 12;
1383             int soundingPitch = _pitch % 12;
1384             if (tpc1Pitch != soundingPitch) {
1385                   qDebug("bad tpc1 - soundingPitch = %d, tpc1 = %d", soundingPitch, tpc1Pitch);
1386                   _pitch += tpc1Pitch - soundingPitch;
1387                   }
1388             if (staff()) {
1389                   Interval v = staff()->part()->instrument(e.tick())->transpose();
1390                   int writtenPitch = (_pitch - v.chromatic) % 12;
1391                   if (tpc2Pitch != writtenPitch) {
1392                         qDebug("bad tpc2 - writtenPitch = %d, tpc2 = %d", writtenPitch, tpc2Pitch);
1393                         if (concertPitch()) {
1394                               // assume we want to keep sounding pitch
1395                               // so fix written pitch (tpc only)
1396                               v.flip();
1397                               _tpc[1] = Ms::transposeTpc(_tpc[0], v, true);
1398                               }
1399                         else {
1400                               // assume we want to keep written pitch
1401                               // so fix sounding pitch (both tpc and pitch)
1402                               _tpc[0] = Ms::transposeTpc(_tpc[1], v, true);
1403                               _pitch += tpc2Pitch - writtenPitch;
1404                               }
1405                         }
1406                   }
1407             }
1408       }
1409 
1410 //---------------------------------------------------------
1411 //   readProperties
1412 //---------------------------------------------------------
1413 
readProperties(XmlReader & e)1414 bool Note::readProperties(XmlReader& e)
1415       {
1416       const QStringRef& tag(e.name());
1417 
1418       if (tag == "pitch")
1419             _pitch = e.readInt();
1420       else if (tag == "tpc") {
1421             _tpc[0] = e.readInt();
1422             _tpc[1] = _tpc[0];
1423             }
1424       else if (tag == "track")            // for performance
1425             setTrack(e.readInt());
1426       else if (tag == "Accidental") {
1427             Accidental* a = new Accidental(score());
1428             a->setTrack(track());
1429             a->read(e);
1430             add(a);
1431             }
1432       else if (tag == "Spanner")
1433             Spanner::readSpanner(e, this, track());
1434       else if (tag == "tpc2")
1435             _tpc[1] = e.readInt();
1436       else if (tag == "small")
1437             setSmall(e.readInt());
1438       else if (tag == "mirror")
1439             readProperty(e, Pid::MIRROR_HEAD);
1440       else if (tag == "dotPosition")
1441             readProperty(e, Pid::DOT_POSITION);
1442       else if (tag == "fixed")
1443             setFixed(e.readBool());
1444       else if (tag == "fixedLine")
1445             setFixedLine(e.readInt());
1446       else if (tag == "headScheme")
1447             readProperty(e, Pid::HEAD_SCHEME);
1448       else if (tag == "head")
1449             readProperty(e, Pid::HEAD_GROUP);
1450       else if (tag == "velocity")
1451             setVeloOffset(e.readInt());
1452       else if (tag == "play")
1453             setPlay(e.readInt());
1454       else if (tag == "tuning")
1455             setTuning(e.readDouble());
1456       else if (tag == "fret")
1457             setFret(e.readInt());
1458       else if (tag == "string")
1459             setString(e.readInt());
1460       else if (tag == "ghost")
1461             setGhost(e.readInt());
1462       else if (tag == "headType")
1463             readProperty(e, Pid::HEAD_TYPE);
1464       else if (tag == "veloType")
1465             readProperty(e, Pid::VELO_TYPE);
1466       else if (tag == "line")
1467             setLine(e.readInt());
1468       else if (tag == "Fingering") {
1469             Fingering* f = new Fingering(score());
1470             f->setTrack(track());
1471             f->read(e);
1472             add(f);
1473             }
1474       else if (tag == "Symbol") {
1475             Symbol* s = new Symbol(score());
1476             s->setTrack(track());
1477             s->read(e);
1478             add(s);
1479             }
1480       else if (tag == "Image") {
1481             if (MScore::noImages)
1482                   e.skipCurrentElement();
1483             else {
1484                   Image* image = new Image(score());
1485                   image->setTrack(track());
1486                   image->read(e);
1487                   add(image);
1488                   }
1489             }
1490       else if (tag == "Bend") {
1491             Bend* b = new Bend(score());
1492             b->setTrack(track());
1493             b->read(e);
1494             add(b);
1495             }
1496       else if (tag == "NoteDot") {
1497             NoteDot* dot = new NoteDot(score());
1498             dot->read(e);
1499             add(dot);
1500             }
1501       else if (tag == "Events") {
1502             _playEvents.clear();    // remove default event
1503             while (e.readNextStartElement()) {
1504                   const QStringRef& t(e.name());
1505                   if (t == "Event") {
1506                         NoteEvent ne;
1507                         ne.read(e);
1508                         _playEvents.append(ne);
1509                         }
1510                   else
1511                         e.unknown();
1512                   }
1513             if (chord())
1514                   chord()->setPlayEventType(PlayEventType::User);
1515             }
1516       else if (tag == "offset")
1517             Element::readProperties(e);
1518       else if (Element::readProperties(e))
1519             ;
1520       else
1521             return false;
1522       return true;
1523       }
1524 
1525 //---------------------------------------------------------
1526 //   Note::readAddConnector
1527 //---------------------------------------------------------
1528 
readAddConnector(ConnectorInfoReader * info,bool pasteMode)1529 void Note::readAddConnector(ConnectorInfoReader* info, bool pasteMode)
1530       {
1531       const ElementType type = info->type();
1532       const Location& l = info->location();
1533       switch(type) {
1534             case ElementType::TIE:
1535             case ElementType::TEXTLINE:
1536             case ElementType::GLISSANDO:
1537                   {
1538                   Spanner* sp = toSpanner(info->connector());
1539                   if (info->isStart()) {
1540                         sp->setTrack(l.track());
1541                         sp->setTick(tick());
1542                         if (sp->isTie()) {
1543                               Note* n = this;
1544                               while (n->tieFor())
1545                                     n = n->tieFor()->endNote();
1546                               Tie* tie = toTie(sp);
1547                               tie->setParent(n);
1548                               tie->setStartNote(n);
1549                               n->_tieFor = tie;
1550                               }
1551                         else {
1552                               sp->setAnchor(Spanner::Anchor::NOTE);
1553                               sp->setStartElement(this);
1554                               addSpannerFor(sp);
1555                               sp->setParent(this);
1556                               }
1557                         }
1558                   else if (info->isEnd()) {
1559                         sp->setTrack2(l.track());
1560                         sp->setTick2(tick());
1561                         sp->setEndElement(this);
1562                         if (sp->isTie())
1563                               _tieBack = toTie(sp);
1564                         else {
1565                               if (sp->isGlissando() && parent() && parent()->isChord())
1566                                     toChord(parent())->setEndsGlissando(true);
1567                               addSpannerBack(sp);
1568                               }
1569 
1570                         // As spanners get added after being fully read, they
1571                         // do not get cloned with the note when pasting to
1572                         // linked staves. So add this spanner explicitly.
1573                         if (pasteMode)
1574                               score()->undoAddElement(sp);
1575                         }
1576                   }
1577             default:
1578                   break;
1579             }
1580       }
1581 
1582 //---------------------------------------------------------
1583 //   transposition
1584 //---------------------------------------------------------
1585 
transposition() const1586 int Note::transposition() const
1587       {
1588       Fraction tick = chord() ? chord()->tick() : Fraction(-1,1);
1589       return staff() ? part()->instrument(tick)->transpose().chromatic : 0;
1590       }
1591 
1592 //---------------------------------------------------------
1593 //   NoteEditData
1594 //---------------------------------------------------------
1595 
1596 class NoteEditData : public ElementEditData {
1597    public:
1598       enum EditMode {
1599             EditMode_ChangePitch = 0,
1600             EditMode_AddSpacing,
1601             EditMode_Undefined,
1602             };
1603 
1604       int line = 0;
1605       int string = 0;
1606       EditMode mode = EditMode_Undefined;
1607       QPointF delta;
1608 
type()1609       virtual EditDataType type() override      { return EditDataType::NoteEditData; }
1610 
1611       static constexpr double MODE_TRANSITION_LIMIT_DEGREES = 15.0;
1612 
editModeByDragDirection(const qreal & deltaX,const qreal & deltaY)1613       static inline EditMode editModeByDragDirection(const qreal& deltaX, const qreal& deltaY)
1614             {
1615             qreal x = qAbs(deltaX);
1616             qreal y = qAbs(deltaY);
1617 
1618             QVector2D normalizedVector(x, y);
1619 
1620             normalizedVector.normalize();
1621 
1622             float radians = QVector2D::dotProduct(normalizedVector, QVector2D(1, 0));
1623 
1624             qreal degrees = (qAcos(radians) * 180.0) / M_PI;
1625 
1626             qDebug() << "NOTE DRAG DEGREES " << degrees;
1627 
1628             if (degrees >= MODE_TRANSITION_LIMIT_DEGREES)
1629                   return NoteEditData::EditMode_ChangePitch;
1630             else
1631                   return NoteEditData::EditMode_AddSpacing;
1632             }
1633       };
1634 
1635 //---------------------------------------------------------
1636 //   acceptDrop
1637 //---------------------------------------------------------
1638 
acceptDrop(EditData & data) const1639 bool Note::acceptDrop(EditData& data) const
1640       {
1641       Element* e = data.dropElement;
1642       ElementType type = e->type();
1643       if (type == ElementType::GLISSANDO) {
1644             for (auto ee : _spannerFor)
1645                   if (ee->isGlissando()) {
1646                         return false;
1647                   }
1648             return true;
1649             }
1650       const Staff* st   = staff();
1651       bool isTablature  = st->isTabStaff(tick());
1652       bool tabFingering = st->staffTypeForElement(this)->showTabFingering();
1653       return (type == ElementType::ARTICULATION
1654          || type == ElementType::FERMATA
1655          || type == ElementType::CHORDLINE
1656          || type == ElementType::TEXT
1657          || type == ElementType::REHEARSAL_MARK
1658          || (type == ElementType::FINGERING && (!isTablature || tabFingering))
1659          || type == ElementType::ACCIDENTAL
1660          || type == ElementType::BREATH
1661          || type == ElementType::ARPEGGIO
1662          || type == ElementType::NOTEHEAD
1663          || type == ElementType::NOTE
1664          || type == ElementType::TREMOLO
1665          || type == ElementType::STAFF_STATE
1666          || type == ElementType::INSTRUMENT_CHANGE
1667          || type == ElementType::IMAGE
1668          || type == ElementType::CHORD
1669          || type == ElementType::HARMONY
1670          || type == ElementType::DYNAMIC
1671          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::ACCIACCATURA)
1672          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::APPOGGIATURA)
1673          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::GRACE4)
1674          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::GRACE16)
1675          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::GRACE32)
1676          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::GRACE8_AFTER)
1677          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::GRACE16_AFTER)
1678          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::GRACE32_AFTER)
1679          || (noteType() == NoteType::NORMAL && type == ElementType::BAGPIPE_EMBELLISHMENT)
1680          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::SBEAM)
1681          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::MBEAM)
1682          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::NBEAM)
1683          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::BEAM32)
1684          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::BEAM64)
1685          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::AUTOBEAM)
1686          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::PARENTHESES)
1687          || (type == ElementType::ICON && toIcon(e)->iconType() == IconType::BRACES)
1688          || (type == ElementType::SYMBOL)
1689          || (type == ElementType::CLEF)
1690          || (type == ElementType::KEYSIG)
1691          || (type == ElementType::TIMESIG)
1692          || (type == ElementType::BAR_LINE)
1693          || (type == ElementType::SLUR)
1694          || (type == ElementType::HAIRPIN)
1695          || (type == ElementType::STAFF_TEXT)
1696          || (type == ElementType::SYSTEM_TEXT)
1697          || (type == ElementType::STICKING)
1698          || (type == ElementType::TEMPO_TEXT)
1699          || (type == ElementType::BEND)
1700          || (type == ElementType::TREMOLOBAR)
1701          || (type == ElementType::FRET_DIAGRAM)
1702          || (type == ElementType::FIGURED_BASS)
1703          || (type == ElementType::LYRICS));
1704       }
1705 
1706 //---------------------------------------------------------
1707 //   drop
1708 //---------------------------------------------------------
1709 
drop(EditData & data)1710 Element* Note::drop(EditData& data)
1711       {
1712       Element* e = data.dropElement;
1713 
1714       const Staff* st = staff();
1715       bool isTablature = st->isTabStaff(tick());
1716       bool tabFingering = st->staffTypeForElement(this)->showTabFingering();
1717       Chord* ch = chord();
1718 
1719       switch(e->type()) {
1720             case ElementType::REHEARSAL_MARK:
1721                   return ch->drop(data);
1722 
1723             case ElementType::SYMBOL:
1724             case ElementType::IMAGE:
1725                   e->setParent(this);
1726                   score()->undoAddElement(e);
1727                   return e;
1728 
1729             case ElementType::FINGERING:
1730                   if (!isTablature || tabFingering) {
1731                         e->setParent(this);
1732                         score()->undoAddElement(e);
1733                         return e;
1734                         }
1735                   else
1736                         delete e;
1737                   return 0;
1738 
1739             case ElementType::SLUR:
1740                   data.view->addSlur(chord(), nullptr, toSlur(e));
1741                   delete e;
1742                   return 0;
1743 
1744             case ElementType::HAIRPIN:
1745                   // forward this event to a chord
1746                   return chord()->drop(data);
1747 
1748             case ElementType::LYRICS:
1749                   e->setParent(ch);
1750                   e->setTrack(track());
1751                   score()->undoAddElement(e);
1752                   return e;
1753 
1754             case ElementType::ACCIDENTAL:
1755                   score()->changeAccidental(this, toAccidental(e)->accidentalType());
1756                   break;
1757 
1758             case ElementType::BEND:
1759                   e->setParent(this);
1760                   e->setTrack(track());
1761                   score()->undoAddElement(e);
1762                   return e;
1763 
1764             case ElementType::NOTEHEAD:
1765                   {
1766                   NoteHead* s = toNoteHead(e);
1767                   NoteHead::Group group = s->headGroup();
1768                   if (group == NoteHead::Group::HEAD_INVALID) {
1769                         qDebug("unknown notehead");
1770                         group = NoteHead::Group::HEAD_NORMAL;
1771                         }
1772                   delete s;
1773 
1774                   if (group != _headGroup) {
1775                         if (links()) {
1776                               for (ScoreElement* se : *links()) {
1777                                     se->undoChangeProperty(Pid::HEAD_GROUP, int(group));
1778                                     Note* note = toNote(se);
1779                                     if (note->staff() && note->staff()->isTabStaff(ch->tick()) && group == NoteHead::Group::HEAD_CROSS)
1780                                           se->undoChangeProperty(Pid::GHOST, true);
1781                                     }
1782                               }
1783                         else {
1784                               undoChangeProperty(Pid::HEAD_GROUP, int(group));
1785                               }
1786                         }
1787                   }
1788                   break;
1789 
1790             case ElementType::ICON:
1791                   {
1792                   switch (toIcon(e)->iconType()) {
1793                         case IconType::ACCIACCATURA:
1794                               score()->setGraceNote(ch, pitch(), NoteType::ACCIACCATURA, MScore::division/2);
1795                               break;
1796                         case IconType::APPOGGIATURA:
1797                               score()->setGraceNote(ch, pitch(), NoteType::APPOGGIATURA, MScore::division/2);
1798                               break;
1799                         case IconType::GRACE4:
1800                               score()->setGraceNote(ch, pitch(), NoteType::GRACE4, MScore::division);
1801                               break;
1802                         case IconType::GRACE16:
1803                               score()->setGraceNote(ch, pitch(), NoteType::GRACE16,  MScore::division/4);
1804                               break;
1805                         case IconType::GRACE32:
1806                               score()->setGraceNote(ch, pitch(), NoteType::GRACE32, MScore::division/8);
1807                               break;
1808                         case IconType::GRACE8_AFTER:
1809                               score()->setGraceNote(ch, pitch(), NoteType::GRACE8_AFTER, MScore::division/2);
1810                               break;
1811                         case IconType::GRACE16_AFTER:
1812                               score()->setGraceNote(ch, pitch(), NoteType::GRACE16_AFTER, MScore::division/4);
1813                               break;
1814                         case IconType::GRACE32_AFTER:
1815                               score()->setGraceNote(ch, pitch(), NoteType::GRACE32_AFTER, MScore::division/8);
1816                               break;
1817                         case IconType::SBEAM:
1818                         case IconType::MBEAM:
1819                         case IconType::NBEAM:
1820                         case IconType::BEAM32:
1821                         case IconType::BEAM64:
1822                         case IconType::AUTOBEAM:
1823                               return ch->drop(data);
1824                               break;
1825                         case IconType::PARENTHESES:
1826                               addParentheses();
1827                               break;
1828                         default:
1829                               break;
1830                         }
1831                   }
1832                   delete e;
1833                   break;
1834 
1835             case ElementType::BAGPIPE_EMBELLISHMENT:
1836                   {
1837                   BagpipeEmbellishment* b = toBagpipeEmbellishment(e);
1838                   noteList nl = b->getNoteList();
1839                   // add grace notes in reverse order, as setGraceNote adds a grace note
1840                   // before the current note
1841                   for (int i = nl.size() - 1; i >= 0; --i) {
1842                         int p = BagpipeEmbellishment::BagpipeNoteInfoList[nl.at(i)].pitch;
1843                         score()->setGraceNote(ch, p, NoteType::GRACE32, MScore::division/8);
1844                         }
1845                   }
1846                   delete e;
1847                   break;
1848 
1849             case ElementType::NOTE:
1850                   {
1851                   // calculate correct transposed tpc
1852                   Note* n = toNote(e);
1853                   Interval v = part()->instrument(ch->tick())->transpose();
1854                   v.flip();
1855                   n->setTpc2(Ms::transposeTpc(n->tpc1(), v, true));
1856                   // replace this note with new note
1857                   n->setParent(ch);
1858                   score()->undoRemoveElement(this);
1859                   score()->undoAddElement(n);
1860                   }
1861                   break;
1862 
1863             case ElementType::GLISSANDO:
1864                   {
1865                   for (auto ee : qAsConst(_spannerFor)) {
1866                         if (ee->type() == ElementType::GLISSANDO) {
1867                               qDebug("there is already a glissando");
1868                               delete e;
1869                               return 0;
1870                               }
1871                         }
1872 
1873                   // this is the glissando initial note, look for a suitable final note
1874                   Note* finalNote = Glissando::guessFinalNote(chord());
1875                   if (finalNote) {
1876                         // init glissando data
1877                         Glissando* gliss = toGlissando(e);
1878                         gliss->setAnchor(Spanner::Anchor::NOTE);
1879                         gliss->setStartElement(this);
1880                         gliss->setEndElement(finalNote);
1881                         gliss->setTick(ch->tick());
1882                         gliss->setTick2(finalNote->chord()->tick());
1883                         gliss->setTrack(track());
1884                         gliss->setTrack2(finalNote->track());
1885                         // in TAB, use straight line with no text
1886                         if (staff()->isTabStaff(finalNote->chord()->tick())) {
1887                               gliss->setGlissandoType(GlissandoType::STRAIGHT);
1888                               gliss->setShowText(false);
1889                               }
1890                         gliss->setParent(this);
1891                         score()->undoAddElement(e);
1892                         }
1893                   else {
1894                         qDebug("no segment for second note of glissando found");
1895                         delete e;
1896                         return 0;
1897                         }
1898                   }
1899                   break;
1900 
1901             case ElementType::CHORD:
1902                   {
1903                   Chord* c      = toChord(e);
1904                   Note* n       = c->upNote();
1905                   Direction dir = c->stemDirection();
1906                   int t         = track(); // (staff2track(staffIdx()) + n->voice());
1907                   score()->select(0, SelectType::SINGLE, 0);
1908                   NoteVal nval;
1909                   nval.pitch = n->pitch();
1910                   nval.headGroup = n->headGroup();
1911                   ChordRest* cr = nullptr;
1912                   if (data.modifiers & Qt::ShiftModifier) {
1913                         // add note to chord
1914                         score()->addNote(ch, nval);
1915                         }
1916                   else {
1917                         // replace current chord
1918                         Segment* seg = score()->setNoteRest(ch->segment(), t, nval,
1919                            score()->inputState().duration().fraction(), dir);
1920                         cr = seg ? toChordRest(seg->element(t)) : nullptr;
1921                         }
1922                   if (cr)
1923                         score()->nextInputPos(cr, false);
1924                   delete e;
1925                   }
1926                   break;
1927 
1928             default:
1929                   return ch->drop(data);
1930             }
1931       return 0;
1932       }
1933 
1934 //---------------------------------------------------------
1935 //   addParentheses
1936 //---------------------------------------------------------
1937 
addParentheses()1938 void Note::addParentheses()
1939       {
1940       Symbol* s = new Symbol(score());
1941       s->setSym(SymId::noteheadParenthesisLeft);
1942       s->setParent(this);
1943       score()->undoAddElement(s);
1944       s = new Symbol(score());
1945       s->setSym(SymId::noteheadParenthesisRight);
1946       s->setParent(this);
1947       score()->undoAddElement(s);
1948       }
1949 
1950 //---------------------------------------------------------
1951 //   setDotY
1952 //---------------------------------------------------------
1953 
setDotY(Direction pos)1954 void Note::setDotY(Direction pos)
1955       {
1956       bool onLine = false;
1957       qreal y = 0;
1958 
1959       if (staff()->isTabStaff(chord()->tick())) {
1960             // with TAB's, dotPosX is not set:
1961             // get dot X from width of fret text and use TAB default spacing
1962             const Staff* st = staff();
1963             const StaffType* tab = st->staffTypeForElement(this);
1964             if (tab->stemThrough() ) {
1965                   // if fret mark on lines, use standard processing
1966                   if (tab->onLines())
1967                         onLine = true;
1968                   else
1969                         // if fret marks above lines, raise the dots by half line distance
1970                         y = -0.5;
1971                   }
1972             // if stems beside staff, do nothing
1973             else
1974                   return;
1975             }
1976       else
1977             onLine = !(line() & 1);
1978 
1979       bool oddVoice = voice() & 1;
1980       if (onLine) {
1981             // displace dots by half spatium up or down according to voice
1982             if (pos == Direction::AUTO)
1983                   y = oddVoice ? 0.5 : -0.5;
1984             else if (pos == Direction::UP)
1985                   y = -0.5;
1986             else
1987                   y = 0.5;
1988             }
1989       else {
1990             if (pos == Direction::UP && !oddVoice)
1991                   y -= 1.0;
1992             else if (pos == Direction::DOWN && oddVoice)
1993                   y += 1.0;
1994             }
1995       y *= spatium() * staff()->lineDistance(tick());
1996 
1997       // apply to dots
1998 
1999       int cdots = chord()->dots();
2000       int ndots = _dots.size();
2001 
2002       int n = cdots - ndots;
2003       for (int i = 0; i < n; ++i) {
2004             NoteDot* dot = new NoteDot(score());
2005             dot->setParent(this);
2006             dot->setTrack(track());  // needed to know the staff it belongs to (and detect tablature)
2007             dot->setVisible(visible());
2008             score()->undoAddElement(dot);
2009             }
2010       if (n < 0) {
2011             for (int i = 0; i < -n; ++i)
2012                   score()->undoRemoveElement(_dots.back());
2013             }
2014       for (NoteDot* dot : qAsConst(_dots)) {
2015             dot->layout();
2016             dot->rypos() = y;
2017             }
2018       }
2019 
2020 //---------------------------------------------------------
2021 //   layout
2022 //---------------------------------------------------------
2023 
layout()2024 void Note::layout()
2025       {
2026       bool useTablature = staff() && staff()->isTabStaff(chord()->tick());
2027       if (useTablature) {
2028             const Staff* st = staff();
2029             const StaffType* tab = st->staffTypeForElement(this);
2030             qreal mags = magS();
2031             bool paren = false;
2032             if (tieBack() && !tab->showBackTied()) {
2033                   if (chord()->measure() != tieBack()->startNote()->chord()->measure() || el().size() > 0)
2034                         paren = true;
2035                   }
2036             // not complete but we need systems to be layouted to add parenthesis
2037             if (fixed())
2038                   _fretString = "/";
2039             else
2040                   _fretString = tab->fretString(_fret, _string, _ghost);
2041             if (paren)
2042                   _fretString = QString("(%1)").arg(_fretString);
2043             qreal w = tabHeadWidth(tab); // !! use _fretString
2044             bbox().setRect(0.0, tab->fretBoxY() * mags, w, tab->fretBoxH() * mags);
2045             }
2046       else {
2047             SymId nh = noteHead();
2048             _cachedNoteheadSym = nh;
2049             if (isNoteName()) {
2050                   _cachedSymNull = SymId::noteEmptyBlack;
2051                   NoteHead::Type ht = _headType == NoteHead::Type::HEAD_AUTO ? chord()->durationType().headType() : _headType;
2052                   if (ht == NoteHead::Type::HEAD_WHOLE)
2053                         _cachedSymNull = SymId::noteEmptyWhole;
2054                   else if (ht == NoteHead::Type::HEAD_HALF)
2055                         _cachedSymNull = SymId::noteEmptyHalf;
2056                   }
2057             else
2058                   _cachedSymNull = SymId::noSym;
2059             setbbox(symBbox(nh));
2060             }
2061       }
2062 
2063 //---------------------------------------------------------
2064 //   layout2
2065 //    called after final position of note is set
2066 //---------------------------------------------------------
2067 
layout2()2068 void Note::layout2()
2069       {
2070       // for standard staves this is done in Score::layoutChords3()
2071       // so that the results are available there
2072 
2073       int dots = chord()->dots();
2074       if (dots) {
2075             qreal d  = score()->point(score()->styleS(Sid::dotNoteDistance)) * mag();
2076             qreal dd = score()->point(score()->styleS(Sid::dotDotDistance)) * mag();
2077             qreal x  = chord()->dotPosX() - pos().x() - chord()->pos().x();
2078             // if TAB and stems through staff
2079             if (staff()->isTabStaff(chord()->tick())) {
2080                   const Staff* st = staff();
2081                   const StaffType* tab = st->staffTypeForElement(this);
2082                   if (tab->stemThrough()) {
2083                         // with TAB's, dot Y is not calculated during layoutChords3(),
2084                         // as layoutChords3() is not even called for TAB's;
2085                         // setDotY() actually also manages creation/deletion of NoteDot's
2086                         setDotY(Direction::AUTO);
2087 
2088                         // use TAB default note-to-dot spacing
2089                         dd = STAFFTYPE_TAB_DEFAULTDOTDIST_X * spatium();
2090                         d = dd * 0.5;
2091                         }
2092                   }
2093             // apply to dots
2094             qreal xx = x + d;
2095             for (NoteDot* dot : qAsConst(_dots)) {
2096                   dot->rxpos() = xx;
2097                   xx += dd;
2098                   }
2099             }
2100 
2101       // layout elements attached to note
2102       for (Element* e : _el) {
2103             if (!score()->tagIsValid(e->tag()))
2104                   continue;
2105             if (e->isSymbol()) {
2106                   e->setMag(mag());
2107                   qreal w = headWidth();
2108                   Symbol* sym = toSymbol(e);
2109                   e->layout();
2110                   if (sym->sym() == SymId::noteheadParenthesisRight) {
2111                         if (staff()->isTabStaff(chord()->tick())) {
2112                               const Staff* st = staff();
2113                               const StaffType* tab = st->staffTypeForElement(this);
2114                               w = tabHeadWidth(tab);
2115                               }
2116                         e->rxpos() += w;
2117                         }
2118                   else if (sym->sym() == SymId::noteheadParenthesisLeft) {
2119                         e->rxpos() -= symWidth(SymId::noteheadParenthesisLeft);
2120                         }
2121                   }
2122             else if (e->isFingering()) {
2123                   // don't set mag; fingerings should not scale with note
2124                   Fingering* f = toFingering(e);
2125                   if (f->propertyFlags(Pid::PLACEMENT) == PropertyFlags::STYLED)
2126                         f->setPlacement(f->calculatePlacement());
2127                   // layout fingerings that are placed relative to notehead
2128                   // fingerings placed relative to chord will be laid out later
2129                   if (f->layoutType() == ElementType::NOTE)
2130                         f->layout();
2131                   }
2132             else {
2133                   e->setMag(mag());
2134                   e->layout();
2135                   }
2136             }
2137       }
2138 
2139 //---------------------------------------------------------
2140 //   dotIsUp
2141 //---------------------------------------------------------
2142 
dotIsUp() const2143 bool Note::dotIsUp() const
2144       {
2145       if (_dots.empty())
2146             return true;
2147       if (_userDotPosition == Direction::AUTO)
2148             return _dots[0]->y() < spatium() * .1;
2149       else
2150             return (_userDotPosition == Direction::UP);
2151       }
2152 
2153 //---------------------------------------------------------
2154 //   updateAccidental
2155 //    set _accidental and _line depending on tpc
2156 //---------------------------------------------------------
2157 
updateAccidental(AccidentalState * as)2158 void Note::updateAccidental(AccidentalState* as)
2159       {
2160       int relLine = absStep(tpc(), epitch());
2161 
2162       // don't touch accidentals that don't concern tpc such as
2163       // quarter tones
2164       if (!(_accidental && Accidental::isMicrotonal(_accidental->accidentalType()))) {
2165             // calculate accidental
2166             AccidentalType acci = AccidentalType::NONE;
2167 
2168             AccidentalVal accVal = tpc2alter(tpc());
2169             bool error = false;
2170             int eRelLine = absStep(tpc(), epitch()+ottaveCapoFret());
2171             AccidentalVal relLineAccVal = as->accidentalVal(eRelLine, error);
2172             if (error) {
2173                   qDebug("error accidentalVal()");
2174                   return;
2175                   }
2176             if ((accVal != relLineAccVal) || hidden() || as->tieContext(eRelLine)) {
2177                   as->setAccidentalVal(eRelLine, accVal, _tieBack != 0 && _accidental == 0);
2178                   acci = Accidental::value2subtype(accVal);
2179                   // if previous tied note has same tpc, don't show accidental
2180                   if (_tieBack && _tieBack->startNote()->tpc1() == tpc1())
2181                         acci = AccidentalType::NONE;
2182                   else if (acci == AccidentalType::NONE)
2183                         acci = AccidentalType::NATURAL;
2184                   }
2185             if (acci != AccidentalType::NONE && !_hidden) {
2186                   if (_accidental == 0) {
2187                         Accidental* a = new Accidental(score());
2188                         a->setParent(this);
2189                         a->setAccidentalType(acci);
2190                         score()->undoAddElement(a);
2191                         }
2192                   else if (_accidental->accidentalType() != acci) {
2193                         Accidental* a = _accidental->clone();
2194                         a->setParent(this);
2195                         a->setAccidentalType(acci);
2196                         score()->undoChangeElement(_accidental, a);
2197                         }
2198                   }
2199             else {
2200                   if (_accidental) {
2201                         // remove this if it was AUTO:
2202                         if (_accidental->role() == AccidentalRole::AUTO)
2203                               score()->undoRemoveElement(_accidental);
2204                         else {
2205                               // keep it, but update type if needed
2206                               acci = Accidental::value2subtype(accVal);
2207                               if (acci == AccidentalType::NONE)
2208                                     acci = AccidentalType::NATURAL;
2209                               if (_accidental->accidentalType() != acci) {
2210                                     Accidental* a = _accidental->clone();
2211                                     a->setParent(this);
2212                                     a->setAccidentalType(acci);
2213                                     score()->undoChangeElement(_accidental, a);
2214                                     }
2215                               }
2216                         }
2217                   }
2218             }
2219 
2220       else {
2221             // microtonal accidentals playback as naturals
2222             // in 1.X, they had no effect on accidental state of measure
2223             // ultimetely, they should probably get their own state
2224             // for now, at least change state to natural, so subsequent notes playback as might be expected
2225             // this is an incompatible change, but better to break it for 2.0 than wait until later
2226             AccidentalVal accVal = Accidental::subtype2value(_accidental->accidentalType());
2227             as->setAccidentalVal(relLine, accVal, _tieBack != 0 && _accidental == 0);
2228             }
2229 
2230       updateRelLine(relLine, true);
2231       }
2232 
2233 //---------------------------------------------------------
2234 //   noteType
2235 //---------------------------------------------------------
2236 
noteType() const2237 NoteType Note::noteType() const
2238       {
2239       return chord()->noteType();
2240       }
2241 
2242 //---------------------------------------------------------
2243 //   noteTypeUserName
2244 //---------------------------------------------------------
2245 
noteTypeUserName() const2246 QString Note::noteTypeUserName() const
2247       {
2248       switch (noteType()) {
2249             case NoteType::ACCIACCATURA:
2250                   return QObject::tr("Acciaccatura");
2251             case NoteType::APPOGGIATURA:
2252                   return QObject::tr("Appoggiatura");
2253             case NoteType::GRACE8_AFTER:
2254             case NoteType::GRACE16_AFTER:
2255             case NoteType::GRACE32_AFTER:
2256                   return QObject::tr("Grace note after");
2257             case NoteType::GRACE4:
2258             case NoteType::GRACE16:
2259             case NoteType::GRACE32:
2260                   return QObject::tr("Grace note before");
2261             default:
2262                   return QObject::tr("Note");
2263             }
2264       }
2265 
2266 //---------------------------------------------------------
2267 //   scanElements
2268 //---------------------------------------------------------
2269 
scanElements(void * data,void (* func)(void *,Element *),bool all)2270 void Note::scanElements(void* data, void (*func)(void*, Element*), bool all)
2271       {
2272       func(data, this);
2273       // tie segments are collected from System
2274       //      if (_tieFor && !staff()->isTabStaff(chord->tick()))  // no ties in tablature
2275       //            _tieFor->scanElements(data, func, all);
2276       for (Element* e : _el) {
2277             if (score()->tagIsValid(e->tag()))
2278                   e->scanElements(data, func, all);
2279             }
2280       for (Spanner* sp : qAsConst(_spannerFor))
2281             sp->scanElements(data, func, all);
2282 
2283       if (!dragMode && _accidental)
2284             func(data, _accidental);
2285       for (NoteDot* dot : qAsConst(_dots))
2286             func(data, dot);
2287       // see above - tie segments are still collected from System!
2288       //if (_tieFor && !_tieFor->spannerSegments().empty())
2289       //      _tieFor->spannerSegments().front()->scanElements(data, func, all);
2290       //if (_tieBack && _tieBack->spannerSegments().size() > 1)
2291       //      _tieBack->spannerSegments().back()->scanElements(data, func, all);
2292       }
2293 
2294 //---------------------------------------------------------
2295 //   setTrack
2296 //---------------------------------------------------------
2297 
setTrack(int val)2298 void Note::setTrack(int val)
2299       {
2300       Element::setTrack(val);
2301       if (_tieFor) {
2302             _tieFor->setTrack(val);
2303             for (SpannerSegment* seg : _tieFor->spannerSegments())
2304                   seg->setTrack(val);
2305             }
2306       for (Spanner* s : qAsConst(_spannerFor)) {
2307             s->setTrack(val);
2308             }
2309       for (Spanner* s : qAsConst(_spannerBack)) {
2310             s->setTrack2(val);
2311             }
2312       for (Element* e : _el)
2313             e->setTrack(val);
2314       if (_accidental)
2315             _accidental->setTrack(val);
2316       if (!chord())     // if note is dragged with shift+ctrl
2317             return;
2318       for (NoteDot* dot : qAsConst(_dots))
2319             dot->setTrack(val);
2320       }
2321 
2322 //---------------------------------------------------------
2323 //    reset
2324 //---------------------------------------------------------
2325 
reset()2326 void Note::reset()
2327       {
2328       undoChangeProperty(Pid::OFFSET, QPointF());
2329       chord()->undoChangeProperty(Pid::OFFSET, QPointF());
2330       chord()->undoChangeProperty(Pid::STEM_DIRECTION, QVariant::fromValue<Direction>(Direction::AUTO));
2331       }
2332 
2333 //---------------------------------------------------------
2334 //   mag
2335 //---------------------------------------------------------
2336 
mag() const2337 qreal Note::mag() const
2338       {
2339       qreal m = chord()->mag();
2340       if (_small)
2341             m *= score()->styleD(Sid::smallNoteMag);
2342       return m;
2343       }
2344 
2345 //---------------------------------------------------------
2346 //   setSmall
2347 //---------------------------------------------------------
2348 
setSmall(bool val)2349 void Note::setSmall(bool val)
2350       {
2351       _small = val;
2352       }
2353 
2354 //---------------------------------------------------------
2355 //   line
2356 //---------------------------------------------------------
2357 
line() const2358 int Note::line() const
2359       {
2360       return fixed() ? _fixedLine : _line;
2361       }
2362 
2363 //---------------------------------------------------------
2364 //   setString
2365 //---------------------------------------------------------
2366 
setString(int val)2367 void Note::setString(int val)
2368       {
2369       _string = val;
2370       rypos() = _string * spatium() * 1.5;
2371       }
2372 
2373 //---------------------------------------------------------
2374 //   setHeadScheme
2375 //---------------------------------------------------------
2376 
setHeadScheme(NoteHead::Scheme val)2377 void Note::setHeadScheme(NoteHead::Scheme val)
2378       {
2379       IF_ASSERT_FAILED(int(val) >= -1 && int(val) < int(NoteHead::Scheme::HEAD_SCHEMES)) {
2380             val = NoteHead::Scheme::HEAD_AUTO;
2381             }
2382       _headScheme = val;
2383       }
2384 
2385 //---------------------------------------------------------
2386 //   setHeadGroup
2387 //---------------------------------------------------------
2388 
setHeadGroup(NoteHead::Group val)2389 void Note::setHeadGroup(NoteHead::Group val)
2390       {
2391       Q_ASSERT(int(val) >= 0 && int(val) < int(NoteHead::Group::HEAD_GROUPS));
2392       _headGroup = val;
2393       }
2394 
2395 //---------------------------------------------------------
2396 //   ottaveCapoFret
2397 //    offset added by Ottava's and Capo Fret.
2398 //---------------------------------------------------------
2399 
ottaveCapoFret() const2400 int Note::ottaveCapoFret() const
2401       {
2402       Chord* ch = chord();
2403       int capoFretId = staff()->capo(ch->segment()->tick());
2404       if (capoFretId != 0)
2405             capoFretId -= 1;
2406 
2407       return staff()->pitchOffset(ch->segment()->tick()) + capoFretId;
2408       }
2409 
2410 //---------------------------------------------------------
2411 //   ppitch
2412 //    playback pitch
2413 //---------------------------------------------------------
2414 
ppitch() const2415 int Note::ppitch() const
2416       {
2417       Chord* ch = chord();
2418       // if staff is drum
2419       // match tremolo and articulation between variants and chord
2420       if (play() && ch && ch->staff() && ch->staff()->isDrumStaff(ch->tick())) {
2421             const Drumset* ds = ch->staff()->part()->instrument(ch->tick())->drumset();
2422             if (ds) {
2423                   DrumInstrumentVariant div = ds->findVariant(_pitch, ch->articulations(), ch->tremolo());
2424                   if (div.pitch != INVALID_PITCH)
2425                         return div.pitch;
2426                   }
2427             }
2428 
2429       return _pitch + ottaveCapoFret();
2430       }
2431 
2432 //---------------------------------------------------------
2433 //   epitch
2434 //    effective pitch, i.e. a pitch which is visible in the
2435 //    currently used written notation.
2436 //    honours transposing instruments
2437 //---------------------------------------------------------
2438 
epitch() const2439 int Note::epitch() const
2440       {
2441       return _pitch - (concertPitch() ? 0 : transposition());
2442       }
2443 
2444 //---------------------------------------------------------
2445 //   customizeVelocity
2446 //    Input is the global velocity determined by dynamic
2447 //    signs and crescende/decrescendo etc.
2448 //    Returns the actual play velocity for this note
2449 //    modified by veloOffset
2450 //---------------------------------------------------------
2451 
customizeVelocity(int velo) const2452 int Note::customizeVelocity(int velo) const
2453       {
2454       if (veloType() == ValueType::OFFSET_VAL)
2455             velo = velo + (velo * veloOffset()) / 100;
2456       else if (veloType() == ValueType::USER_VAL)
2457             velo = veloOffset();
2458       return limit(velo, 1, 127);
2459       }
2460 
2461 //---------------------------------------------------------
2462 //   startDrag
2463 //---------------------------------------------------------
2464 
startDrag(EditData & ed)2465 void Note::startDrag(EditData& ed)
2466       {
2467       NoteEditData* ned = new NoteEditData();
2468       ned->e      = this;
2469       ned->line   = _line;
2470       ned->string = _string;
2471       ned->pushProperty(Pid::PITCH);
2472       ned->pushProperty(Pid::TPC1);
2473       ned->pushProperty(Pid::TPC2);
2474       ned->pushProperty(Pid::FRET);
2475       ned->pushProperty(Pid::STRING);
2476 
2477       ed.addData(ned);
2478       }
2479 
2480 //---------------------------------------------------------
2481 //   drag
2482 //---------------------------------------------------------
2483 
drag(EditData & ed)2484 QRectF Note::drag(EditData& ed)
2485       {
2486       NoteEditData* noteEditData = static_cast<NoteEditData*>(ed.getData(this));
2487       IF_ASSERT_FAILED(noteEditData) {
2488             return QRectF();
2489             }
2490 
2491       QPointF delta = ed.evtDelta;
2492       noteEditData->delta = delta;
2493 
2494       if (noteEditData->mode == NoteEditData::EditMode_Undefined) {
2495             noteEditData->mode = NoteEditData::editModeByDragDirection(delta.x(), delta.y());
2496             }
2497 
2498       if (noteEditData->mode == NoteEditData::EditMode_AddSpacing)
2499             horizontalDrag(ed);
2500       else if (noteEditData->mode == NoteEditData::EditMode_ChangePitch)
2501             verticalDrag(ed);
2502 
2503       return QRectF();
2504       }
2505 
2506 //---------------------------------------------------------
2507 //   endDrag
2508 //---------------------------------------------------------
2509 
endDrag(EditData & ed)2510 void Note::endDrag(EditData& ed)
2511       {
2512       NoteEditData* ned = static_cast<NoteEditData*>(ed.getData(this));
2513       IF_ASSERT_FAILED(ned) {
2514             return;
2515             }
2516       for (Note* nn : tiedNotes()) {
2517             for (const PropertyData& pd : qAsConst(ned->propertyData)) {
2518                   setPropertyFlags(pd.id, pd.f); // reset initial property flags state
2519                   score()->undoPropertyChanged(nn, pd.id, pd.data);
2520                   }
2521           }
2522       }
2523 
2524 //---------------------------------------------------------
2525 //   editDrag
2526 //---------------------------------------------------------
2527 
editDrag(EditData & editData)2528 void Note::editDrag(EditData& editData)
2529       {
2530       Chord* ch = chord();
2531       Segment* seg = ch->segment();
2532 
2533       if (editData.modifiers & Qt::ShiftModifier) {
2534             const Spatium deltaSp = Spatium(editData.delta.x() / spatium());
2535             seg->undoChangeProperty(Pid::LEADING_SPACE, seg->extraLeadingSpace() + deltaSp);
2536             }
2537       else if (ch->notes().size() == 1) {
2538             // if the chord contains only this note, then move the whole chord
2539             // including stem, flag etc.
2540             ch->undoChangeProperty(Pid::OFFSET, ch->offset() + offset() + editData.evtDelta);
2541             setOffset(QPointF());
2542             }
2543       else
2544             setOffset(offset() + editData.evtDelta);
2545 
2546       triggerLayout();
2547       }
2548 
2549 //---------------------------------------------------------
2550 //   verticalDrag
2551 //---------------------------------------------------------
2552 
verticalDrag(EditData & ed)2553 void Note::verticalDrag(EditData &ed)
2554       {
2555       Fraction _tick      = chord()->tick();
2556       const Staff* stf    = staff();
2557       const StaffType* st = stf->staffType(_tick);
2558       const Instrument* instr = part()->instrument(_tick);
2559 
2560       if (instr->useDrumset())
2561             return;
2562 
2563       NoteEditData* ned   = static_cast<NoteEditData*>(ed.getData(this));
2564 
2565       qreal _spatium      = spatium();
2566       bool tab            = st->isTabStaff();
2567       qreal step          = _spatium * (tab ? st->lineDistance().val() : 0.5);
2568       int lineOffset      = lrint(ed.moveDelta.y() / step);
2569 
2570       if (tab) {
2571             const StringData* strData = staff()->part()->instrument(_tick)->stringData();
2572             int nString = ned->string + (st->upsideDown() ? -lineOffset : lineOffset);
2573             int nFret   = strData->fret(_pitch, nString, staff(), _tick);
2574 
2575             if (nFret >= 0) {                    // no fret?
2576                   if (fret() != nFret || string() != nString) {
2577                         for (Note* nn : tiedNotes()) {
2578                               nn->setFret(nFret);
2579                               nn->setString(nString);
2580                               strData->fretChords(nn->chord());
2581                               nn->triggerLayout();
2582                               }
2583                         }
2584                   }
2585             }
2586       else {
2587             Key key = staff()->key(_tick);
2588             int idx = chord()->vStaffIdx();
2589             int newPitch = line2pitch(ned->line + lineOffset, score()->staff(idx)->clef(_tick), key);
2590 
2591             if (!concertPitch()) {
2592                   Interval interval = staff()->part()->instrument(_tick)->transpose();
2593                   newPitch += interval.chromatic;
2594                   }
2595 
2596             int newTpc1 = pitch2tpc(newPitch, key, Prefer::NEAREST);
2597             int newTpc2 = pitch2tpc(newPitch - transposition(), key, Prefer::NEAREST);
2598             for (Note* nn : tiedNotes()) {
2599                   nn->setPitch(newPitch, newTpc1, newTpc2);
2600                   nn->triggerLayout();
2601                   }
2602             }
2603       }
2604 
2605 //---------------------------------------------------------
2606 //   normalizeLeftDragDelta
2607 //---------------------------------------------------------
2608 
normalizeLeftDragDelta(Segment * seg,EditData & ed,NoteEditData * ned)2609 void Note::normalizeLeftDragDelta(Segment* seg, EditData &ed, NoteEditData* ned)
2610       {
2611       Segment* previous = seg->prev();
2612 
2613       if (previous) {
2614 
2615             qreal minDist = previous->minHorizontalCollidingDistance(seg);
2616 
2617             qreal diff = (ed.pos.x()) - (previous->pageX() + minDist);
2618 
2619             qreal distanceBetweenSegments = (previous->pageX() + minDist) - seg->pageX();
2620 
2621             if (diff < 0)
2622                   ned->delta.setX(distanceBetweenSegments);
2623             }
2624       else {
2625             Measure* measure = seg->measure();
2626 
2627             qreal minDist = score()->styleP(Sid::barNoteDistance);
2628 
2629             qreal diff = (ed.pos.x()) - (measure->pageX() + minDist);
2630 
2631             qreal distanceBetweenSegments = (measure->pageX() + minDist) - seg->pageX();
2632 
2633             if (diff < 0)
2634                   ned->delta.setX(distanceBetweenSegments);
2635             }
2636       }
2637 
2638 //---------------------------------------------------------
2639 //   horizontalDrag
2640 //---------------------------------------------------------
2641 
horizontalDrag(EditData & ed)2642 void Note::horizontalDrag(EditData &ed)
2643       {
2644       Chord* ch = chord();
2645       Segment* seg = ch->segment();
2646 
2647       NoteEditData* ned = static_cast<NoteEditData*>(ed.getData(this));
2648 
2649       if (ed.moveDelta.x() < 0)
2650             normalizeLeftDragDelta(seg, ed, ned);
2651 
2652       const Spatium deltaSp = Spatium(ned->delta.x() / spatium());
2653 
2654       if (seg->extraLeadingSpace() + deltaSp < Spatium(0)) {
2655           return;
2656       }
2657 
2658       seg->undoChangeProperty(Pid::LEADING_SPACE, seg->extraLeadingSpace() + deltaSp);
2659 
2660       triggerLayout();
2661       }
2662 
2663 //---------------------------------------------------------
2664 //   updateRelLine
2665 //    calculate the real note line depending on clef,
2666 //    _line is the absolute line
2667 //---------------------------------------------------------
2668 
updateRelLine(int relLine,bool undoable)2669 void Note::updateRelLine(int relLine, bool undoable)
2670       {
2671       if (!staff())
2672             return;
2673       // int idx      = staffIdx() + chord()->staffMove();
2674       Q_ASSERT(staffIdx() == chord()->staffIdx());
2675       int idx      = chord()->vStaffIdx();
2676 
2677       const Staff* staff  = score()->staff(idx);
2678       const StaffType* st = staff->staffTypeForElement(this);
2679 
2680       if (chord()->staffMove()) {
2681             // check that destination staff makes sense (might have been deleted)
2682             int minStaff = part()->startTrack() / VOICES;
2683             int maxStaff = part()->endTrack() / VOICES;
2684             const Staff* stf = this->staff();
2685             if (idx < minStaff || idx >= maxStaff || st->group() != stf->staffTypeForElement(this)->group()) {
2686                   qDebug("staffMove out of scope %d + %d min %d max %d",
2687                      staffIdx(), chord()->staffMove(), minStaff, maxStaff);
2688                   chord()->undoChangeProperty(Pid::STAFF_MOVE, 0);
2689                   }
2690             }
2691 
2692       ClefType clef = staff->clef(chord()->tick());
2693       int line      = relStep(relLine, clef);
2694 
2695       if (undoable && (_line != INVALID_LINE) && (line != _line))
2696             undoChangeProperty(Pid::LINE, line);
2697       else
2698             setLine(line);
2699 
2700       int off  = st->stepOffset();
2701       qreal ld = st->lineDistance().val();
2702       rypos()  = (_line + off * 2.0) * spatium() * .5 * ld;
2703       }
2704 
2705 //---------------------------------------------------------
2706 //   updateLine
2707 //---------------------------------------------------------
2708 
updateLine()2709 void Note::updateLine()
2710       {
2711       int relLine = absStep(tpc(), epitch());
2712       updateRelLine(relLine, false);
2713       }
2714 
2715 //---------------------------------------------------------
2716 //   setNval
2717 //    set note properties from NoteVal
2718 //---------------------------------------------------------
2719 
setNval(const NoteVal & nval,Fraction tick)2720 void Note::setNval(const NoteVal& nval, Fraction tick)
2721       {
2722       setPitch(nval.pitch);
2723       _fret   = nval.fret;
2724       _string = nval.string;
2725 
2726       _tpc[0] = nval.tpc1;
2727       _tpc[1] = nval.tpc2;
2728 
2729       if (tick == Fraction(-1,1) && chord())
2730             tick = chord()->tick();
2731       Interval v = part()->instrument(tick)->transpose();
2732       if (nval.tpc1 == Tpc::TPC_INVALID) {
2733             Key key = staff()->key(tick);
2734             if (!concertPitch() && !v.isZero())
2735                   key = transposeKey(key, v);
2736             _tpc[0] = pitch2tpc(nval.pitch, key, Prefer::NEAREST);
2737             }
2738       if (nval.tpc2 == Tpc::TPC_INVALID) {
2739             if (v.isZero())
2740                   _tpc[1] = _tpc[0];
2741             else {
2742                   v.flip();
2743                   _tpc[1] = Ms::transposeTpc(_tpc[0], v, true);
2744                   }
2745             }
2746 
2747       _headGroup = NoteHead::Group(nval.headGroup);
2748       }
2749 
2750 //---------------------------------------------------------
2751 //   localSpatiumChanged
2752 //---------------------------------------------------------
2753 
localSpatiumChanged(qreal oldValue,qreal newValue)2754 void Note::localSpatiumChanged(qreal oldValue, qreal newValue)
2755       {
2756       Element::localSpatiumChanged(oldValue, newValue);
2757       for (Element* e : dots())
2758             e->localSpatiumChanged(oldValue, newValue);
2759       for (Element* e : el())
2760             e->localSpatiumChanged(oldValue, newValue);
2761       for (Spanner* spanner : spannerBack()) {
2762             for (auto k : spanner->spannerSegments())
2763                   k->localSpatiumChanged(oldValue, newValue);
2764             }
2765       }
2766 
2767 //---------------------------------------------------------
2768 //   getProperty
2769 //---------------------------------------------------------
2770 
getProperty(Pid propertyId) const2771 QVariant Note::getProperty(Pid propertyId) const
2772       {
2773       switch (propertyId) {
2774             case Pid::PITCH:
2775                   return pitch();
2776             case Pid::TPC1:
2777                   return _tpc[0];
2778             case Pid::TPC2:
2779                   return _tpc[1];
2780             case Pid::SMALL:
2781                   return small();
2782             case Pid::MIRROR_HEAD:
2783                   return int(userMirror());
2784             case Pid::DOT_POSITION:
2785                   return QVariant::fromValue<Direction>(userDotPosition());
2786             case Pid::HEAD_SCHEME:
2787                   return int(headScheme());
2788             case Pid::HEAD_GROUP:
2789                   return int(headGroup());
2790             case Pid::VELO_OFFSET:
2791                   return veloOffset();
2792             case Pid::TUNING:
2793                   return tuning();
2794             case Pid::FRET:
2795                   return fret();
2796             case Pid::STRING:
2797                   return string();
2798             case Pid::GHOST:
2799                   return ghost();
2800             case Pid::HEAD_TYPE:
2801                   return int(headType());
2802             case Pid::VELO_TYPE:
2803                   return int(veloType());
2804             case Pid::PLAY:
2805                   return play();
2806             case Pid::LINE:
2807                   return _line;
2808             case Pid::FIXED:
2809                   return fixed();
2810             case Pid::FIXED_LINE:
2811                   return fixedLine();
2812             default:
2813                   break;
2814             }
2815       return Element::getProperty(propertyId);
2816       }
2817 
2818 //---------------------------------------------------------
2819 //   setProperty
2820 //---------------------------------------------------------
2821 
setProperty(Pid propertyId,const QVariant & v)2822 bool Note::setProperty(Pid propertyId, const QVariant& v)
2823       {
2824       Measure* m = chord() ? chord()->measure() : nullptr;
2825       switch(propertyId) {
2826             case Pid::PITCH:
2827                   setPitch(v.toInt());
2828                   score()->setPlaylistDirty();
2829                   break;
2830             case Pid::TPC1:
2831                   _tpc[0] = v.toInt();
2832                   break;
2833             case Pid::TPC2:
2834                   _tpc[1] = v.toInt();
2835                   break;
2836             case Pid::LINE:
2837                   setLine(v.toInt());
2838                   break;
2839             case Pid::SMALL:
2840                   setSmall(v.toBool());
2841                   break;
2842             case Pid::MIRROR_HEAD:
2843                   setUserMirror(MScore::DirectionH(v.toInt()));
2844                   break;
2845             case Pid::DOT_POSITION:
2846                   setUserDotPosition(v.value<Direction>());
2847                   triggerLayout();
2848                   return true;
2849             case Pid::HEAD_SCHEME:
2850                   setHeadScheme(NoteHead::Scheme(v.toInt()));
2851                   break;
2852             case Pid::HEAD_GROUP:
2853                   setHeadGroup(NoteHead::Group(v.toInt()));
2854                   break;
2855             case Pid::VELO_OFFSET:
2856                   setVeloOffset(v.toInt());
2857                   score()->setPlaylistDirty();
2858                   break;
2859             case Pid::TUNING:
2860                   setTuning(v.toDouble());
2861                   score()->setPlaylistDirty();
2862                   break;
2863             case Pid::FRET:
2864                   setFret(v.toInt());
2865                   break;
2866             case Pid::STRING:
2867                   setString(v.toInt());
2868                   break;
2869             case Pid::GHOST:
2870                   setGhost(v.toBool());
2871                   break;
2872             case Pid::HEAD_TYPE:
2873                   setHeadType(NoteHead::Type(v.toInt()));
2874                   break;
2875             case Pid::VELO_TYPE:
2876                   setVeloType(ValueType(v.toInt()));
2877                   score()->setPlaylistDirty();
2878                   break;
2879             case Pid::VISIBLE: {
2880                   setVisible(v.toBool());
2881                   if (m)
2882                         m->checkMultiVoices(chord()->staffIdx());
2883                   break;
2884                   }
2885             case Pid::PLAY:
2886                   setPlay(v.toBool());
2887                   score()->setPlaylistDirty();
2888                   break;
2889             case Pid::FIXED:
2890                   setFixed(v.toBool());
2891                   break;
2892             case Pid::FIXED_LINE:
2893                   setFixedLine(v.toInt());
2894                   break;
2895             default:
2896                   if (!Element::setProperty(propertyId, v))
2897                         return false;
2898                   break;
2899             }
2900       triggerLayout();
2901       return true;
2902       }
2903 
2904 //---------------------------------------------------------
2905 //   undoChangeDotsVisible
2906 //---------------------------------------------------------
2907 
undoChangeDotsVisible(bool v)2908 void Note::undoChangeDotsVisible(bool v)
2909       {
2910       for (NoteDot* dot : qAsConst(_dots))
2911             dot->undoChangeProperty(Pid::VISIBLE, QVariant(v));
2912       }
2913 
2914 //---------------------------------------------------------
2915 //   propertyDefault
2916 //---------------------------------------------------------
2917 
propertyDefault(Pid propertyId) const2918 QVariant Note::propertyDefault(Pid propertyId) const
2919       {
2920       switch(propertyId) {
2921             case Pid::GHOST:
2922             case Pid::SMALL:
2923                   return false;
2924             case Pid::MIRROR_HEAD:
2925                   return int(MScore::DirectionH::AUTO);
2926             case Pid::DOT_POSITION:
2927                   return QVariant::fromValue<Direction>(Direction::AUTO);
2928             case Pid::HEAD_SCHEME:
2929                   return int(NoteHead::Scheme::HEAD_AUTO);
2930             case Pid::HEAD_GROUP:
2931                   return int(NoteHead::Group::HEAD_NORMAL);
2932             case Pid::VELO_OFFSET:
2933                   return 0;
2934             case Pid::TUNING:
2935                   return 0.0;
2936             case Pid::FRET:
2937             case Pid::STRING:
2938                   return -1;
2939             case Pid::HEAD_TYPE:
2940                   return int(NoteHead::Type::HEAD_AUTO);
2941             case Pid::VELO_TYPE:
2942                   return int (ValueType::OFFSET_VAL);
2943             case Pid::PLAY:
2944                   return true;
2945             case Pid::FIXED:
2946                   return false;
2947             case Pid::FIXED_LINE:
2948                   return 0;
2949             case Pid::TPC2:
2950                   return getProperty(Pid::TPC1);
2951             case Pid::PITCH:
2952             case Pid::TPC1:
2953                   return QVariant();
2954             default:
2955                   break;
2956             }
2957       return Element::propertyDefault(propertyId);
2958       }
2959 
2960 //---------------------------------------------------------
2961 //   propertyUserValue
2962 //---------------------------------------------------------
2963 
propertyUserValue(Pid pid) const2964 QString Note::propertyUserValue(Pid pid) const
2965       {
2966       switch(pid) {
2967             case Pid::PITCH:
2968                   return tpcUserName();
2969             case Pid::TPC1:
2970             case Pid::TPC2:
2971                   {
2972                   int idx = (pid == Pid::TPC1) ? 0 : 1;
2973                   int tpc = _tpc[idx];
2974                   return tpc2name(tpc, NoteSpellingType::STANDARD, NoteCaseType::AUTO, false);
2975                   }
2976             default:
2977                   return Element::propertyUserValue(pid);
2978             }
2979       }
2980 
2981 //---------------------------------------------------------
2982 //   setHeadType
2983 //---------------------------------------------------------
2984 
setHeadType(NoteHead::Type t)2985 void Note::setHeadType(NoteHead::Type t)
2986       {
2987       _headType = t;
2988       }
2989 
2990 //---------------------------------------------------------
2991 //   setOnTimeOffset
2992 //---------------------------------------------------------
2993 
setOnTimeOffset(int val)2994 void Note::setOnTimeOffset(int val)
2995       {
2996       _playEvents[0].setOntime(val);
2997       chord()->setPlayEventType(PlayEventType::User);
2998       }
2999 
3000 //---------------------------------------------------------
3001 //   setOffTimeOffset
3002 //---------------------------------------------------------
3003 
setOffTimeOffset(int val)3004 void Note::setOffTimeOffset(int val)
3005       {
3006       _playEvents[0].setLen(val - _playEvents[0].ontime());
3007       chord()->setPlayEventType(PlayEventType::User);
3008       }
3009 
3010 //---------------------------------------------------------
3011 //   setScore
3012 //---------------------------------------------------------
3013 
setScore(Score * s)3014 void Note::setScore(Score* s)
3015       {
3016       Element::setScore(s);
3017       if (_tieFor)
3018             _tieFor->setScore(s);
3019       if (_accidental)
3020             _accidental->setScore(s);
3021       for (NoteDot* dot : qAsConst(_dots))
3022             dot->setScore(s);
3023       for (Element* el : _el)
3024             el->setScore(s);
3025       }
3026 
3027 //---------------------------------------------------------
3028 //   accessibleInfo
3029 //---------------------------------------------------------
3030 
accessibleInfo() const3031 QString Note::accessibleInfo() const
3032       {
3033       QString duration = chord()->durationUserName();
3034       QString voice = QObject::tr("Voice: %1").arg(QString::number(track() % VOICES + 1));
3035       QString pitchName;
3036       QString onofftime;
3037       if (!_playEvents.empty()) {
3038             int on = _playEvents[0].ontime();
3039             int off = _playEvents[0].offtime();
3040             if (on != 0 || off != NoteEvent::NOTE_LENGTH)
3041                   onofftime = QObject::tr(" (on %1‰ off %2‰)").arg(on).arg(off);
3042             }
3043       const Drumset* drumset = part()->instrument(chord()->tick())->drumset();
3044       if (fixed() && headGroup() == NoteHead::Group::HEAD_SLASH)
3045             pitchName = chord()->noStem() ? QObject::tr("Beat slash") : QObject::tr("Rhythm slash");
3046       else if (staff()->isDrumStaff(tick()) && drumset)
3047             pitchName = qApp->translate("drumset", drumset->name(pitch()).toUtf8().constData());
3048       else if (staff()->isTabStaff(tick()))
3049             pitchName = QObject::tr("%1; String: %2; Fret: %3").arg(tpcUserName(false), QString::number(string() + 1), QString::number(fret()));
3050       else
3051             pitchName = tpcUserName(false);
3052       return QObject::tr("%1; Pitch: %2; Duration: %3%4%5").arg(noteTypeUserName(), pitchName, duration, onofftime, (chord()->isGrace() ? "" : QString("; %1").arg(voice)));
3053       }
3054 
3055 //---------------------------------------------------------
3056 //   screenReaderInfo
3057 //---------------------------------------------------------
3058 
screenReaderInfo() const3059 QString Note::screenReaderInfo() const
3060       {
3061       QString duration = chord()->durationUserName();
3062       Measure* m = chord()->measure();
3063       bool voices = m ? m->hasVoices(staffIdx()) : false;
3064       QString voice = voices ? QObject::tr("Voice: %1").arg(QString::number(track() % VOICES + 1)) : "";
3065       QString pitchName;
3066       const Drumset* drumset = part()->instrument(chord()->tick())->drumset();
3067       if (fixed() && headGroup() == NoteHead::Group::HEAD_SLASH)
3068             pitchName = chord()->noStem() ? QObject::tr("Beat Slash") : QObject::tr("Rhythm Slash");
3069       else if (staff()->isDrumStaff(tick()) && drumset)
3070             pitchName = qApp->translate("drumset", drumset->name(pitch()).toUtf8().constData());
3071       else if (staff()->isTabStaff(tick()))
3072             pitchName = QObject::tr("%1; String: %2; Fret: %3").arg(tpcUserName(true), QString::number(string() + 1), QString::number(fret()));
3073       else
3074             pitchName = tpcUserName(true);
3075       return QString("%1 %2 %3%4").arg(noteTypeUserName(), pitchName, duration, (chord()->isGrace() ? "" : QString("; %1").arg(voice)));
3076       }
3077 
3078 //---------------------------------------------------------
3079 //   accessibleExtraInfo
3080 //---------------------------------------------------------
3081 
accessibleExtraInfo() const3082 QString Note::accessibleExtraInfo() const
3083       {
3084       QString rez = "";
3085       if (accidental()) {
3086             rez = QString("%1 %2").arg(rez, accidental()->screenReaderInfo());
3087             }
3088       if (!el().empty()) {
3089             for (Element* e : el()) {
3090                   if (!score()->selectionFilter().canSelect(e)) continue;
3091                   rez = QString("%1 %2").arg(rez, e->screenReaderInfo());
3092                   }
3093             }
3094       if (tieFor())
3095             rez = QObject::tr("%1 Start of %2").arg(rez, tieFor()->screenReaderInfo());
3096 
3097       if (tieBack())
3098             rez = QObject::tr("%1 End of %2").arg(rez, tieBack()->screenReaderInfo());
3099 
3100       if (!spannerFor().empty()) {
3101             for (Spanner* s : spannerFor()) {
3102                   if (!score()->selectionFilter().canSelect(s))
3103                         continue;
3104                   rez = QObject::tr("%1 Start of %2").arg(rez, s->screenReaderInfo());
3105                   }
3106             }
3107       if (!spannerBack().empty()) {
3108             for (Spanner* s : spannerBack()) {
3109                   if (!score()->selectionFilter().canSelect(s))
3110                         continue;
3111                   rez = QObject::tr("%1 End of %2").arg(rez, s->screenReaderInfo());
3112                   }
3113             }
3114 
3115       // only read extra information for top note of chord
3116       // (it is reached directly on next/previous element)
3117       if (this == chord()->upNote())
3118             rez = QString("%1 %2").arg(rez, chord()->accessibleExtraInfo());
3119 
3120       return rez;
3121       }
3122 
3123 //---------------------------------------------------------
3124 //   noteVal
3125 //---------------------------------------------------------
3126 
noteVal() const3127 NoteVal Note::noteVal() const
3128       {
3129       NoteVal nval;
3130       nval.pitch     = pitch();
3131       nval.tpc1      = tpc1();
3132       nval.tpc2      = tpc2();
3133       nval.fret      = fret();
3134       nval.string    = string();
3135       nval.headGroup = headGroup();
3136       return nval;
3137       }
3138 
3139 //---------------------------------------------------------
3140 //   qmlDotsCount
3141 //    returns number of dots for plugins
3142 //---------------------------------------------------------
3143 
qmlDotsCount()3144 int Note::qmlDotsCount()
3145       {
3146       return _dots.size();
3147       }
3148 
3149 //---------------------------------------------------------
3150 //   subtypeName
3151 //---------------------------------------------------------
3152 
subtypeName() const3153 QString Note::subtypeName() const
3154       {
3155       return NoteHead::group2userName(_headGroup);
3156       }
3157 
3158 //---------------------------------------------------------
3159 //   nextInEl
3160 //   returns next element in _el
3161 //---------------------------------------------------------
3162 
nextInEl(Element * e)3163 Element* Note::nextInEl(Element* e)
3164       {
3165       if (e == _el.back())
3166             return nullptr;
3167       auto i = std::find(_el.begin(), _el.end(), e);
3168       if (i == _el.end())
3169             return nullptr;
3170       return *(i+1);
3171       }
3172 
3173 //---------------------------------------------------------
3174 //   prevInEl
3175 //   returns prev element in _el
3176 //---------------------------------------------------------
3177 
prevInEl(Element * e)3178 Element* Note::prevInEl(Element* e)
3179       {
3180       if (e == _el.front())
3181             return nullptr;
3182       auto i = std::find(_el.begin(), _el.end(), e);
3183       if (i == _el.end())
3184             return nullptr;
3185       return *(i-1);
3186       }
3187 
tieValid(Tie * tie)3188 static bool tieValid(Tie* tie)
3189       {
3190       return (tie && !tie->segmentsEmpty());
3191       }
3192 
3193 //---------------------------------------------------------
3194 //   nextElement
3195 //---------------------------------------------------------
3196 
nextElement()3197 Element* Note::nextElement()
3198       {
3199       Element* e = score()->selection().element();
3200       if (!e && !score()->selection().elements().isEmpty() )
3201             e = score()->selection().elements().first();
3202       if (!e)
3203             return nullptr;
3204       switch (e->type()) {
3205             case ElementType::SYMBOL:
3206             case ElementType::IMAGE:
3207             case ElementType::FINGERING:
3208             case ElementType::TEXT:
3209             case ElementType::BEND: {
3210                   Element* next = nextInEl(e); // return next element in _el
3211                   if (next)
3212                         return next;
3213                   else if (tieValid(_tieFor))
3214                         return _tieFor->frontSegment();
3215                   else if (!_spannerFor.empty()) {
3216                         for (auto i : qAsConst(_spannerFor)) {
3217                               if (i->type() == ElementType::GLISSANDO)
3218                                     return i->spannerSegments().front();
3219                               }
3220                         }
3221                   return nullptr;
3222                   }
3223 
3224             case ElementType::TIE_SEGMENT:
3225                   if (!_spannerFor.empty()) {
3226                       for (auto i : qAsConst(_spannerFor)) {
3227                             if (i->type() == ElementType::GLISSANDO)
3228                                   return i->spannerSegments().front();
3229                                   }
3230                             }
3231                   return chord()->nextElement();
3232 
3233             case ElementType::GLISSANDO_SEGMENT:
3234                   return chord()->nextElement();
3235 
3236             case ElementType::ACCIDENTAL:
3237                   if (!_el.empty())
3238                         return _el[0];
3239                   if (tieValid(_tieFor))
3240                         return _tieFor->frontSegment();
3241                   if (!_spannerFor.empty()) {
3242                         for (auto i : qAsConst(_spannerFor)) {
3243                               if (i->isGlissando())
3244                                     return i->spannerSegments().front();
3245                               }
3246                         }
3247                   return nullptr;
3248 
3249             case ElementType::NOTE:
3250                   if (!_el.empty())
3251                         return _el[0];
3252                   if (tieValid(_tieFor))
3253                         return _tieFor->frontSegment();
3254                   if (!_spannerFor.empty()) {
3255                         for (auto i : qAsConst(_spannerFor)) {
3256                               if (i->isGlissando())
3257                                     return i->spannerSegments().front();
3258                               }
3259                         }
3260                   return nullptr;
3261 
3262             default:
3263                   return nullptr;
3264             }
3265       }
3266 
3267 //---------------------------------------------------------
3268 //   prevElement
3269 //---------------------------------------------------------
3270 
prevElement()3271 Element* Note::prevElement()
3272       {
3273       Element* e = score()->selection().element();
3274       if (!e && !score()->selection().elements().isEmpty() )
3275             e = score()->selection().elements().last();
3276       if (!e)
3277             return nullptr;
3278       switch (e->type()) {
3279             case ElementType::SYMBOL:
3280             case ElementType::IMAGE:
3281             case ElementType::FINGERING:
3282             case ElementType::TEXT:
3283             case ElementType::BEND: {
3284                   Element* prev = prevInEl(e); // return prev element in _el
3285                   if (prev)
3286                         return prev;
3287                   }
3288                   return this;
3289             case ElementType::TIE_SEGMENT:
3290                   if (!_el.empty())
3291                         return _el.back();
3292                   return this;
3293             case ElementType::GLISSANDO_SEGMENT:
3294                   if (tieValid(_tieFor))
3295                         return _tieFor->frontSegment();
3296                   else if (!_el.empty())
3297                         return _el.back();
3298                   return this;
3299             case ElementType::ACCIDENTAL:
3300                   return this;
3301             default:
3302                   return nullptr;
3303             }
3304       }
3305 
3306 //---------------------------------------------------------
3307 //   lastElementBeforeSegment
3308 //---------------------------------------------------------
3309 
lastElementBeforeSegment()3310 Element* Note::lastElementBeforeSegment()
3311       {
3312       if (!_spannerFor.empty()) {
3313             for (auto i : qAsConst(_spannerFor)) {
3314                   if (i->type() == ElementType::GLISSANDO)
3315                         return i->spannerSegments().front();
3316                   }
3317             }
3318       if (tieValid(_tieFor))
3319             return _tieFor->frontSegment();
3320       if (!_el.empty())
3321             return _el.back();
3322       return this;
3323       }
3324 
3325 //---------------------------------------------------------
3326 //   nextSegmentElement
3327 //---------------------------------------------------------
3328 
nextSegmentElement()3329 Element* Note::nextSegmentElement()
3330       {
3331       if (chord()->isGrace())
3332             return Element::nextSegmentElement();
3333 
3334       const std::vector<Note*>& notes = chord()->notes();
3335       if (this == notes.front())
3336             return chord()->nextSegmentElement();
3337       auto i = std::find(notes.begin(), notes.end(), this);
3338       return *(i-1);
3339       }
3340 
3341 //---------------------------------------------------------
3342 //   prevSegmentElement
3343 //---------------------------------------------------------
3344 
prevSegmentElement()3345 Element* Note::prevSegmentElement()
3346       {
3347       if (chord()->isGrace())
3348             return Element::prevSegmentElement();
3349 
3350       const std::vector<Note*>& notes = chord()->notes();
3351       if (this == notes.back())
3352             return chord()->prevSegmentElement();
3353       auto i = std::find(notes.begin(), notes.end(), this);
3354       return *++i;
3355       }
3356 
3357 //---------------------------------------------------------
3358 //   lastTiedNote
3359 //---------------------------------------------------------
3360 
lastTiedNote() const3361 const Note* Note::lastTiedNote() const
3362       {
3363       std::vector<const Note*> notes;
3364       const Note* note = this;
3365       notes.push_back(note);
3366       while (note->tieFor()) {
3367             if (std::find(notes.begin(), notes.end(), note->tieFor()->endNote()) != notes.end())
3368                   break;
3369             if (!note->tieFor()->endNote())
3370                   break;
3371             note = note->tieFor()->endNote();
3372             notes.push_back(note);
3373             }
3374       return note;
3375       }
3376 
3377 //---------------------------------------------------------
3378 //   firstTiedNote
3379 //    if note has ties, return last note in chain
3380 //    - handle recursion in connected notes
3381 //---------------------------------------------------------
3382 
firstTiedNote() const3383 Note* Note::firstTiedNote() const
3384       {
3385       std::vector<const Note*> notes;
3386       const Note* note = this;
3387       notes.push_back(note);
3388       while (note->tieBack()) {
3389             if (std::find(notes.begin(), notes.end(), note->tieBack()->startNote()) != notes.end())
3390                   break;
3391             note = note->tieBack()->startNote();
3392             notes.push_back(note);
3393             }
3394       return const_cast<Note*>(note);
3395       }
3396 
3397 //---------------------------------------------------------
3398 //   tiedNotes
3399 //---------------------------------------------------------
3400 
tiedNotes() const3401 std::vector<Note*> Note::tiedNotes() const
3402       {
3403       std::vector<Note*> notes;
3404       Note* note = firstTiedNote();
3405 
3406       notes.push_back(note);
3407       while (note->tieFor()) {
3408             Note* endNote = note->tieFor()->endNote();
3409             if (!endNote || std::find(notes.begin(), notes.end(), endNote) != notes.end())
3410                   break;
3411             note = endNote;
3412             notes.push_back(note);
3413             }
3414       return notes;
3415       }
3416 
3417 //---------------------------------------------------------
3418 //   unisonIndex
3419 //---------------------------------------------------------
3420 
unisonIndex() const3421 int Note::unisonIndex() const
3422       {
3423       int index = 0;
3424       for (Note* n : chord()->notes()) {
3425             if (n->pitch() == pitch()) {
3426                   if (n == this)
3427                         return index;
3428                   else
3429                         ++index;
3430                   }
3431             }
3432       return 0;
3433       }
3434 
3435 //---------------------------------------------------------
3436 //   disconnectTiedNotes
3437 //---------------------------------------------------------
3438 
disconnectTiedNotes()3439 void Note::disconnectTiedNotes()
3440       {
3441       if (tieBack() && tieBack()->startNote()) {
3442             tieBack()->startNote()->remove(tieBack());
3443             }
3444       if (tieFor() && tieFor()->endNote()) {
3445             tieFor()->endNote()->setTieBack(0);
3446             }
3447       }
3448 
3449 //---------------------------------------------------------
3450 //   connectTiedNotes
3451 //---------------------------------------------------------
3452 
connectTiedNotes()3453 void Note::connectTiedNotes()
3454       {
3455       if (tieBack()) {
3456             tieBack()->setEndNote(this);
3457             if (tieBack()->startNote())
3458                   tieBack()->startNote()->add(tieBack());
3459             }
3460       if (tieFor() && tieFor()->endNote()) {
3461             tieFor()->endNote()->setTieBack(tieFor());
3462             }
3463       }
3464 
3465 //---------------------------------------------------------
3466 //   accidentalType
3467 //---------------------------------------------------------
3468 
accidentalType() const3469 AccidentalType Note::accidentalType() const
3470       {
3471       return _accidental ? _accidental->accidentalType() : AccidentalType::NONE;
3472       }
3473 
3474 //---------------------------------------------------------
3475 //   setAccidentalType
3476 //---------------------------------------------------------
3477 
setAccidentalType(AccidentalType type)3478 void Note::setAccidentalType(AccidentalType type)
3479       {
3480       if (score())
3481          score()->changeAccidental(this, type);
3482       }
3483 
3484 //---------------------------------------------------------
3485 //   shape
3486 //---------------------------------------------------------
3487 
shape() const3488 Shape Note::shape() const
3489       {
3490       QRectF r(bbox());
3491 
3492 #ifndef NDEBUG
3493       Shape shape(r, name());
3494       for (NoteDot* dot : _dots)
3495             shape.add(symBbox(SymId::augmentationDot).translated(dot->pos()), dot->name());
3496       if (_accidental && _accidental->addToSkyline())
3497             shape.add(_accidental->bbox().translated(_accidental->pos()), _accidental->name());
3498       for (auto e : _el) {
3499             if (e->addToSkyline()) {
3500                   if (e->isFingering() && toFingering(e)->layoutType() != ElementType::NOTE)
3501                         continue;
3502                   shape.add(e->bbox().translated(e->pos()), e->name());
3503                   }
3504             }
3505 #else
3506       Shape shape(r);
3507       for (NoteDot* dot : _dots)
3508             shape.add(symBbox(SymId::augmentationDot).translated(dot->pos()));
3509       if (_accidental && _accidental->addToSkyline())
3510             shape.add(_accidental->bbox().translated(_accidental->pos()));
3511       for (auto e : _el) {
3512             if (e->addToSkyline()) {
3513                   if (e->isFingering() && toFingering(e)->layoutType() != ElementType::NOTE)
3514                         continue;
3515                   shape.add(e->bbox().translated(e->pos()));
3516                   }
3517             }
3518 #endif
3519       return shape;
3520       }
3521 
3522 //---------------------------------------------------------
3523 //   undoUnlink
3524 //---------------------------------------------------------
3525 
undoUnlink()3526 void Note::undoUnlink()
3527       {
3528       Element::undoUnlink();
3529       for (Element* e : _el)
3530             e->undoUnlink();
3531       }
3532 
3533 }
3534