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