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") }, // è
225 {"solfege-fixed", QT_TRANSLATE_NOOP("noteheadschemes", "Solf\u00e8ge Fixed Do") }, // è
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