1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A MIDI and audio sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7
8 Other copyrights also apply to some parts of this work. Please
9 see the AUTHORS file and individual file headers for details.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version. See the file
15 COPYING included with this distribution for more information.
16 */
17
18
19 #include "NoteStyle.h"
20
21 #include "base/NotationTypes.h"
22 #include "base/PropertyName.h"
23 #include "NoteCharacterNames.h"
24 #include "NoteStyleFactory.h"
25 #include "misc/Strings.h"
26 #include "misc/Debug.h"
27
28
29 namespace Rosegarden
30 {
31
~NoteStyle()32 NoteStyle::~NoteStyle()
33 {
34 // nothing
35 }
36
37 const NoteStyle::NoteHeadShape NoteStyle::AngledOval = "angled oval";
38
39 const NoteStyle::NoteHeadShape NoteStyle::LevelOval = "level oval";
40
41 const NoteStyle::NoteHeadShape NoteStyle::Breve = "breve";
42
43 const NoteStyle::NoteHeadShape NoteStyle::Cross = "cross";
44
45 const NoteStyle::NoteHeadShape NoteStyle::TriangleUp = "triangle up";
46
47 const NoteStyle::NoteHeadShape NoteStyle::TriangleDown = "triangle down";
48
49 const NoteStyle::NoteHeadShape NoteStyle::Diamond = "diamond";
50
51 const NoteStyle::NoteHeadShape NoteStyle::Rectangle = "rectangle";
52
53 const NoteStyle::NoteHeadShape NoteStyle::Number = "number";
54
55 const NoteStyle::NoteHeadShape NoteStyle::CustomCharName = "custom character";
56
57
58
59 NoteStyle::NoteHeadShape
getShape(Note::Type type)60 NoteStyle::getShape(Note::Type type)
61 {
62 NoteDescriptionMap::iterator i = m_notes.find(type);
63 if (i == m_notes.end()) {
64 if (m_baseStyle)
65 return m_baseStyle->getShape(type);
66 RG_WARNING
67 << "WARNING: NoteStyle::getShape: No shape defined for note type "
68 << type << ", defaulting to AngledOval";
69 return AngledOval;
70 }
71
72 return i->second.shape;
73 }
74
75 bool
isFilled(Note::Type type)76 NoteStyle::isFilled(Note::Type type)
77 {
78 NoteDescriptionMap::iterator i = m_notes.find(type);
79 if (i == m_notes.end()) {
80 if (m_baseStyle)
81 return m_baseStyle->isFilled(type);
82 RG_WARNING
83 << "WARNING: NoteStyle::isFilled: No definition for note type "
84 << type << ", defaulting to true";
85 return true;
86 }
87
88 return i->second.filled;
89 }
90
91 bool
hasStem(Note::Type type)92 NoteStyle::hasStem(Note::Type type)
93 {
94 NoteDescriptionMap::iterator i = m_notes.find(type);
95 if (i == m_notes.end()) {
96 if (m_baseStyle)
97 return m_baseStyle->hasStem(type);
98 RG_WARNING
99 << "WARNING: NoteStyle::hasStem: No definition for note type "
100 << type << ", defaulting to true";
101 return true;
102 }
103
104 return i->second.stem;
105 }
106
107 int
getFlagCount(Note::Type type)108 NoteStyle::getFlagCount(Note::Type type)
109 {
110 NoteDescriptionMap::iterator i = m_notes.find(type);
111 if (i == m_notes.end()) {
112 if (m_baseStyle)
113 return m_baseStyle->getFlagCount(type);
114 RG_WARNING
115 << "WARNING: NoteStyle::getFlagCount: No definition for note type "
116 << type << ", defaulting to 0";
117 return 0;
118 }
119
120 return i->second.flags;
121 }
122
123 int
getSlashCount(Note::Type type)124 NoteStyle::getSlashCount(Note::Type type)
125 {
126 NoteDescriptionMap::iterator i = m_notes.find(type);
127 if (i == m_notes.end()) {
128 if (m_baseStyle)
129 return m_baseStyle->getSlashCount(type);
130 RG_WARNING
131 << "WARNING: NoteStyle::getSlashCount: No definition for note type "
132 << type << ", defaulting to 0";
133 return 0;
134 }
135
136 return i->second.slashes;
137 }
138
139 void
getStemFixPoints(Note::Type type,HFixPoint & hfix,VFixPoint & vfix)140 NoteStyle::getStemFixPoints(Note::Type type,
141 HFixPoint &hfix, VFixPoint &vfix)
142 {
143 NoteDescriptionMap::iterator i = m_notes.find(type);
144 if (i == m_notes.end()) {
145 if (m_baseStyle) {
146 m_baseStyle->getStemFixPoints(type, hfix, vfix);
147 return ;
148 }
149 RG_WARNING
150 << "WARNING: NoteStyle::getStemFixPoints: "
151 << "No definition for note type " << type
152 << ", defaulting to (Normal,Middle)";
153 hfix = Normal;
154 vfix = Middle;
155 return ;
156 }
157
158 hfix = i->second.hfix;
159 vfix = i->second.vfix;
160 }
161
162 NoteStyle::CharNameRec
163
getNoteHeadCharName(Note::Type type)164 NoteStyle::getNoteHeadCharName(Note::Type type)
165 {
166 NoteDescriptionMap::iterator i = m_notes.find(type);
167 if (i == m_notes.end()) {
168 if (m_baseStyle)
169 return m_baseStyle->getNoteHeadCharName(type);
170 RG_WARNING
171 << "WARNING: NoteStyle::getNoteHeadCharName: No definition for note type "
172 << type << ", defaulting to NOTEHEAD_BLACK";
173 return CharNameRec(NoteCharacterNames::NOTEHEAD_BLACK, false);
174 }
175
176 const NoteDescription &desc(i->second);
177 CharName name = NoteCharacterNames::UNKNOWN;
178 bool inverted = false;
179
180 if (desc.shape == AngledOval) {
181
182 name = desc.filled ? NoteCharacterNames::NOTEHEAD_BLACK
183 : NoteCharacterNames::VOID_NOTEHEAD;
184
185 } else if (desc.shape == LevelOval) {
186
187 if (desc.filled) {
188 RG_WARNING << "WARNING: NoteStyle::getNoteHeadCharName: No filled level oval head";
189 }
190 name = NoteCharacterNames::WHOLE_NOTE;
191
192 } else if (desc.shape == Breve) {
193
194 if (desc.filled) {
195 RG_WARNING << "WARNING: NoteStyle::getNoteHeadCharName: No filled breve head";
196 }
197 name = NoteCharacterNames::BREVE;
198
199 } else if (desc.shape == Cross) {
200
201 name = desc.filled ? NoteCharacterNames::X_NOTEHEAD
202 : NoteCharacterNames::CIRCLE_X_NOTEHEAD;
203
204 } else if (desc.shape == TriangleUp) {
205
206 name = desc.filled ? NoteCharacterNames::TRIANGLE_NOTEHEAD_UP_BLACK
207 : NoteCharacterNames::TRIANGLE_NOTEHEAD_UP_WHITE;
208
209 } else if (desc.shape == TriangleDown) {
210
211 name = desc.filled ? NoteCharacterNames::TRIANGLE_NOTEHEAD_UP_BLACK
212 : NoteCharacterNames::TRIANGLE_NOTEHEAD_UP_WHITE;
213 inverted = true;
214
215 } else if (desc.shape == Diamond) {
216
217 name = desc.filled ? NoteCharacterNames::SEMIBREVIS_BLACK
218 : NoteCharacterNames::SEMIBREVIS_WHITE;
219
220 } else if (desc.shape == Rectangle) {
221
222 name = desc.filled ? NoteCharacterNames::SQUARE_NOTEHEAD_BLACK
223 : NoteCharacterNames::SQUARE_NOTEHEAD_WHITE;
224
225 } else if (desc.shape == Number) {
226
227 RG_WARNING << "WARNING: NoteStyle::getNoteHeadCharName: Number not yet implemented";
228 name = NoteCharacterNames::UNKNOWN; //!!!
229
230 } else if (desc.shape == CustomCharName) {
231
232 name = desc.charName;
233
234 } else {
235
236 name = NoteCharacterNames::UNKNOWN;
237 }
238
239 return CharNameRec(name, inverted);
240 }
241
242 CharName
getAccidentalCharName(const Accidental & a)243 NoteStyle::getAccidentalCharName(const Accidental &a)
244 {
245 if (a == Accidentals::Sharp)
246 return NoteCharacterNames::SHARP;
247 else if (a == Accidentals::Flat)
248 return NoteCharacterNames::FLAT;
249 else if (a == Accidentals::Natural)
250 return NoteCharacterNames::NATURAL;
251 else if (a == Accidentals::DoubleSharp)
252 return NoteCharacterNames::DOUBLE_SHARP;
253 else if (a == Accidentals::DoubleFlat)
254 return NoteCharacterNames::DOUBLE_FLAT;
255 return NoteCharacterNames::UNKNOWN;
256 }
257
258 CharName
getMarkCharName(const Mark & mark)259 NoteStyle::getMarkCharName(const Mark &mark)
260 {
261 if (mark == Marks::Accent)
262 return NoteCharacterNames::ACCENT;
263 else if (mark == Marks::Tenuto)
264 return NoteCharacterNames::TENUTO;
265 else if (mark == Marks::Staccato)
266 return NoteCharacterNames::STACCATO;
267 else if (mark == Marks::Staccatissimo)
268 return NoteCharacterNames::STACCATISSIMO;
269 else if (mark == Marks::Marcato)
270 return NoteCharacterNames::MARCATO;
271 else if (mark == Marks::Open)
272 return NoteCharacterNames::OPEN;
273 else if (mark == Marks::Stopped)
274 return NoteCharacterNames::STOPPED;
275 else if (mark == Marks::Trill)
276 return NoteCharacterNames::TRILL;
277 else if (mark == Marks::LongTrill)
278 return NoteCharacterNames::TRILL;
279 else if (mark == Marks::TrillLine)
280 return NoteCharacterNames::TRILL_LINE;
281 else if (mark == Marks::Turn)
282 return NoteCharacterNames::TURN;
283 else if (mark == Marks::Pause)
284 return NoteCharacterNames::FERMATA;
285 else if (mark == Marks::UpBow)
286 return NoteCharacterNames::UP_BOW;
287 else if (mark == Marks::DownBow)
288 return NoteCharacterNames::DOWN_BOW;
289 else if (mark == Marks::Harmonic)
290 return NoteCharacterNames::HARMONIC;
291 else if (mark == Marks::Mordent)
292 return NoteCharacterNames::MORDENT;
293 else if (mark == Marks::MordentInverted)
294 return NoteCharacterNames::MORDENT_INVERTED;
295 else if (mark == Marks::MordentLong)
296 return NoteCharacterNames::MORDENT_LONG;
297 else if (mark == Marks::MordentLongInverted)
298 return NoteCharacterNames::MORDENT_LONG_INVERTED;
299 // Things like "sf" and "rf" are generated from text fonts
300 return NoteCharacterNames::UNKNOWN;
301 }
302
303 CharName
getClefCharName(const Clef & clef)304 NoteStyle::getClefCharName(const Clef &clef)
305 {
306 std::string clefType(clef.getClefType());
307
308 if (clefType == Clef::Bass || clefType == Clef::Varbaritone || clefType == Clef::Subbass) {
309 return NoteCharacterNames::F_CLEF;
310 } else if (clefType == Clef::Treble || clefType == Clef::French) {
311 return NoteCharacterNames::G_CLEF;
312 } else if (clefType == Clef::TwoBar) {
313 return NoteCharacterNames::TWO_BAR_CLEF;
314 } else {
315 return NoteCharacterNames::C_CLEF;
316 }
317 }
318
319 CharName
getSymbolCharName(const Symbol & symbol)320 NoteStyle::getSymbolCharName(const Symbol &symbol)
321 {
322 std::string symbolType(symbol.getSymbolType());
323
324 if (symbolType == Symbol::Segno)
325 return NoteCharacterNames::SEGNO;
326 else if (symbolType == Symbol::Coda)
327 return NoteCharacterNames::CODA;
328 else if (symbolType == Symbol::Breath)
329 return NoteCharacterNames::BREATH_MARK;
330 else
331 return NoteCharacterNames::UNKNOWN;
332 }
333
334 CharName
getRestCharName(Note::Type type,bool restOutsideStave)335 NoteStyle::getRestCharName(Note::Type type, bool restOutsideStave)
336 {
337 switch (type) {
338 case Note::Hemidemisemiquaver:
339 return NoteCharacterNames::SIXTY_FOURTH_REST;
340 case Note::Demisemiquaver:
341 return NoteCharacterNames::THIRTY_SECOND_REST;
342 case Note::Semiquaver:
343 return NoteCharacterNames::SIXTEENTH_REST;
344 case Note::Quaver:
345 return NoteCharacterNames::EIGHTH_REST;
346 case Note::Crotchet:
347 return NoteCharacterNames::QUARTER_REST;
348 case Note::Minim:
349 return restOutsideStave ?
350 NoteCharacterNames::HALF_REST
351 : NoteCharacterNames::HALF_REST_ON_STAFF;
352 case Note::Semibreve:
353 return restOutsideStave ?
354 NoteCharacterNames::WHOLE_REST
355 : NoteCharacterNames::WHOLE_REST_ON_STAFF;
356 case Note::Breve:
357 return restOutsideStave ?
358 NoteCharacterNames::MULTI_REST
359 : NoteCharacterNames::MULTI_REST_ON_STAFF;
360 default:
361 return NoteCharacterNames::UNKNOWN;
362 }
363 }
364
365 CharName
getPartialFlagCharName(bool final)366 NoteStyle::getPartialFlagCharName(bool final)
367 {
368 if (final)
369 return NoteCharacterNames::FLAG_PARTIAL_FINAL;
370 else
371 return NoteCharacterNames::FLAG_PARTIAL;
372 }
373
374 CharName
getFlagCharName(int flagCount)375 NoteStyle::getFlagCharName(int flagCount)
376 {
377 switch (flagCount) {
378 case 1:
379 return NoteCharacterNames::FLAG_1;
380 case 2:
381 return NoteCharacterNames::FLAG_2;
382 case 3:
383 return NoteCharacterNames::FLAG_3;
384 case 4:
385 return NoteCharacterNames::FLAG_4;
386 default:
387 return NoteCharacterNames::UNKNOWN;
388 }
389 }
390
391 CharName
getTimeSignatureDigitName(int digit)392 NoteStyle::getTimeSignatureDigitName(int digit)
393 {
394 switch (digit) {
395 case 0:
396 return NoteCharacterNames::DIGIT_ZERO;
397 case 1:
398 return NoteCharacterNames::DIGIT_ONE;
399 case 2:
400 return NoteCharacterNames::DIGIT_TWO;
401 case 3:
402 return NoteCharacterNames::DIGIT_THREE;
403 case 4:
404 return NoteCharacterNames::DIGIT_FOUR;
405 case 5:
406 return NoteCharacterNames::DIGIT_FIVE;
407 case 6:
408 return NoteCharacterNames::DIGIT_SIX;
409 case 7:
410 return NoteCharacterNames::DIGIT_SEVEN;
411 case 8:
412 return NoteCharacterNames::DIGIT_EIGHT;
413 case 9:
414 return NoteCharacterNames::DIGIT_NINE;
415 default:
416 return NoteCharacterNames::UNKNOWN;
417 }
418 }
419
420 CharName
getSomeCharName(QString qthing)421 NoteStyle::getSomeCharName(QString qthing)
422 {
423 CharName name;
424 std::string thing = qstrtostr(qthing);
425
426 try {
427 name = getAccidentalCharName(Accidental(thing));
428 if (!(name == NoteCharacterNames::UNKNOWN)) return name;
429 } catch (const Exception &) { }
430
431 try {
432 name = getMarkCharName(Mark(thing));
433 RG_DEBUG << thing << " -> " << name;
434 if (!(name == NoteCharacterNames::UNKNOWN)) return name;
435 } catch (const Exception &) { }
436
437 try {
438 name = getClefCharName(Clef(thing));
439 if (!(name == NoteCharacterNames::UNKNOWN)) return name;
440 } catch (const Exception &) { }
441
442 return NoteCharacterNames::UNKNOWN;
443 }
444
445 void
setBaseStyle(NoteStyleName name)446 NoteStyle::setBaseStyle(NoteStyleName name)
447 {
448 try {
449 m_baseStyle = NoteStyleFactory::getStyle(name);
450 if (m_baseStyle == this)
451 m_baseStyle.reset();
452 } catch (const NoteStyleFactory::StyleUnavailable &u) {
453 if (name != NoteStyleFactory::DefaultStyle) {
454 RG_WARNING
455 << "NoteStyle::setBaseStyle: Base style "
456 << name << " not available, defaulting to "
457 << NoteStyleFactory::DefaultStyle;
458 setBaseStyle(NoteStyleFactory::DefaultStyle);
459 } else {
460 RG_WARNING
461 << "NoteStyle::setBaseStyle: Base style "
462 << name << " not available";
463 m_baseStyle.reset();
464 }
465 }
466 }
467
468 void
checkDescription(Note::Type note)469 NoteStyle::checkDescription(Note::Type note)
470 {
471 if (m_baseStyle && (m_notes.find(note) == m_notes.end())) {
472 m_baseStyle->checkDescription(note);
473 m_notes[note] = m_baseStyle->m_notes[note];
474 }
475 }
476
477 void
setShape(Note::Type note,NoteHeadShape shape)478 NoteStyle::setShape(Note::Type note, NoteHeadShape shape)
479 {
480 checkDescription(note);
481 m_notes[note].shape = shape;
482 }
483
484 void
setCharName(Note::Type note,CharName charName)485 NoteStyle::setCharName(Note::Type note, CharName charName)
486 {
487 checkDescription(note);
488 m_notes[note].charName = charName;
489 }
490
491 void
setFilled(Note::Type note,bool filled)492 NoteStyle::setFilled(Note::Type note, bool filled)
493 {
494 checkDescription(note);
495 m_notes[note].filled = filled;
496 }
497
498 void
setStem(Note::Type note,bool stem)499 NoteStyle::setStem(Note::Type note, bool stem)
500 {
501 checkDescription(note);
502 m_notes[note].stem = stem;
503 }
504
505 void
setFlagCount(Note::Type note,int flags)506 NoteStyle::setFlagCount(Note::Type note, int flags)
507 {
508 checkDescription(note);
509 m_notes[note].flags = flags;
510 }
511
512 void
setSlashCount(Note::Type note,int slashes)513 NoteStyle::setSlashCount(Note::Type note, int slashes)
514 {
515 checkDescription(note);
516 m_notes[note].slashes = slashes;
517 }
518
519 void
setStemFixPoints(Note::Type note,HFixPoint hfix,VFixPoint vfix)520 NoteStyle::setStemFixPoints(Note::Type note, HFixPoint hfix, VFixPoint vfix)
521 {
522 checkDescription(note);
523 m_notes[note].hfix = hfix;
524 m_notes[note].vfix = vfix;
525 }
526
527 }
528