Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #pragma once
24 :
25 : #include <map>
26 :
27 : #include "global/allocator.h"
28 : #include "global/types/string.h"
29 :
30 : #include "../types/types.h"
31 :
32 : namespace muse::io {
33 : class IODevice;
34 : }
35 :
36 : namespace mu::engraving::compat {
37 : class ReadChordListHook;
38 : }
39 :
40 : namespace mu::engraving {
41 : class ChordList;
42 : class MStyle;
43 : class XmlWriter;
44 : class XmlReader;
45 :
46 : //---------------------------------------------------------
47 : // class HDegree
48 : //---------------------------------------------------------
49 :
50 : enum class HDegreeType : char {
51 : UNDEF, ADD, ALTER, SUBTRACT
52 : };
53 :
54 : class HDegree
55 : {
56 : public:
57 : HDegree() = default;
58 15946 : HDegree(int v, int a, HDegreeType t) { m_value = v; m_alter = a; m_type = t; }
59 31897 : int value() const { return m_value; }
60 15960 : int alter() const { return m_alter; }
61 25220 : HDegreeType type() const { return m_type; }
62 : String text() const;
63 :
64 : private:
65 : int m_value = 0;
66 : int m_alter = 0; // -1, 0, 1 (b - - #)
67 : HDegreeType m_type = HDegreeType::UNDEF;
68 : };
69 :
70 : //---------------------------------------------------------
71 : // HChord
72 : //---------------------------------------------------------
73 :
74 : class HChord
75 : {
76 : public:
77 22646 : HChord() = default;
78 349 : HChord(int k) { m_keys = k; }
79 : HChord(int a, int b, int c=-1, int d=-1, int e=-1, int f=-1, int g=-1, int h=-1, int i=-1, int k=-1, int l=-1);
80 : HChord(const String&);
81 :
82 : void rotate(int semiTones);
83 :
84 15008 : bool contains(int key) const // key in chord?
85 : {
86 15008 : return (1 << (key % 12)) & m_keys;
87 : }
88 :
89 113939 : HChord& operator+=(int key)
90 : {
91 113939 : m_keys |= (1 << (key % 12));
92 113939 : return *this;
93 : }
94 :
95 9183 : HChord& operator-=(int key)
96 : {
97 9183 : m_keys &= ~(1 << (key % 12));
98 9183 : return *this;
99 : }
100 :
101 0 : bool operator==(const HChord& o) const { return m_keys == o.m_keys; }
102 : bool operator!=(const HChord& o) const { return m_keys != o.m_keys; }
103 :
104 16704 : int getKeys() const { return m_keys; }
105 : void print() const;
106 :
107 : String name(int tpc) const;
108 : String voicing() const;
109 : void add(const std::vector<HDegree>& degreeList);
110 :
111 : protected:
112 : int m_keys = 0;
113 :
114 : private:
115 : String m_str;
116 : };
117 :
118 : //---------------------------------------------------------
119 : // RenderAction
120 : // Render commands to be passed to and executed by Harmony
121 : //---------------------------------------------------------
122 :
123 : struct RenderAction
124 : {
125 : enum class RenderActionType : char {
126 : SET, MOVE, MOVEXHEIGHT, PUSH, POP, NOTE, ACCIDENTAL, STOPHALIGN, SCALE, PAREN
127 : };
128 :
129 : virtual RenderActionType actionType() const = 0;
130 :
131 0 : virtual void print() const { print(actionType(), u""); }
132 :
133 271068 : virtual ~RenderAction() {}
134 :
135 : protected:
136 : void print(RenderActionType type, const String& info) const;
137 : };
138 :
139 : struct RenderActionMove : RenderAction
140 : {
141 : RenderActionMove() {}
142 41527 : RenderActionMove(double movex, double movey)
143 41527 : : m_vec(PointF(movex, movey)) {}
144 :
145 3233 : RenderActionType actionType() const override { return RenderActionType::MOVE; }
146 : void print() const override;
147 :
148 0 : double x() const { return m_vec.x(); }
149 0 : double y() const { return m_vec.y(); }
150 3233 : PointF vec() const { return m_vec; }
151 3233 : bool scaled() const { return m_scaled; }
152 :
153 : protected:
154 20130 : RenderActionMove(double movex, double movey, bool scaled)
155 20130 : : m_vec(PointF(movex, movey)), m_scaled(scaled) {}
156 :
157 : private:
158 : PointF m_vec = PointF(0.0, 0.0);
159 : bool m_scaled = false;
160 : };
161 :
162 : struct RenderActionMoveScaled : RenderActionMove
163 : {
164 20130 : RenderActionMoveScaled(double movex, double movey)
165 20130 : : RenderActionMove(movex, movey, true) {}
166 :
167 : void print() const override;
168 : };
169 :
170 : struct RenderActionMoveXHeight : RenderAction
171 : {
172 10003 : RenderActionMoveXHeight(bool up)
173 10003 : : m_up(up) {}
174 12 : RenderActionType actionType() const override { return RenderActionType::MOVEXHEIGHT; }
175 :
176 12 : bool up() const { return m_up; }
177 12 : bool scaled() const { return m_scaled; }
178 : void print() const override;
179 :
180 : protected:
181 915 : RenderActionMoveXHeight(bool up, bool scaled)
182 915 : : m_up(up), m_scaled(scaled) {}
183 :
184 : private:
185 : bool m_up = true;
186 : bool m_scaled = false;
187 : };
188 :
189 : struct RenderActionMoveXHeightScaled : RenderActionMoveXHeight
190 : {
191 915 : RenderActionMoveXHeightScaled(bool up)
192 915 : : RenderActionMoveXHeight(up, true) {}
193 : };
194 :
195 : struct RenderActionSet : RenderAction
196 : {
197 : RenderActionSet() {}
198 167514 : RenderActionSet(String s)
199 167514 : : m_text(s) {}
200 :
201 7099 : RenderActionType actionType() const override { return RenderActionType::SET; }
202 : void print() const override;
203 :
204 9340 : const String& text() const { return m_text; }
205 7099 : bool renderText() const { return m_renderText; }
206 :
207 : protected:
208 0 : RenderActionSet(String s, bool renderText)
209 0 : : m_text(s), m_renderText(renderText) {}
210 :
211 : private:
212 : String m_text;
213 : bool m_renderText = true;
214 : };
215 :
216 : struct RenderActionMoveTextWidth : RenderActionSet
217 : {
218 0 : RenderActionMoveTextWidth(String s)
219 0 : : RenderActionSet(s, false) {}
220 : };
221 :
222 : struct RenderActionPush : RenderAction
223 : {
224 15574 : RenderActionPush() {}
225 16 : RenderActionType actionType() const override { return RenderActionType::PUSH; }
226 : };
227 :
228 : struct RenderActionPop : RenderAction
229 : {
230 1449 : RenderActionPop() {}
231 :
232 16 : RenderActionType actionType() const override { return RenderActionType::POP; }
233 : void print() const override;
234 :
235 16 : double popX() const { return m_popx; }
236 16 : double popY() const { return m_popy; }
237 : protected:
238 12313 : RenderActionPop(bool popx, bool popy)
239 12313 : : m_popx(popx), m_popy(popy) {}
240 : private:
241 : bool m_popx = true, m_popy = true;
242 : };
243 :
244 : struct RenderActionPopX : RenderActionPop
245 : {
246 2310 : RenderActionPopX()
247 2310 : : RenderActionPop(true, false) {}
248 : };
249 :
250 : struct RenderActionPopY : RenderActionPop
251 : {
252 10003 : RenderActionPopY()
253 10003 : : RenderActionPop(false, true) {}
254 : };
255 :
256 : struct RenderActionNote : RenderAction
257 : {
258 5314 : RenderActionNote() {}
259 2897 : RenderActionType actionType() const override { return RenderActionType::NOTE; }
260 : };
261 :
262 : struct RenderActionAccidental : RenderAction
263 : {
264 5314 : RenderActionAccidental() {}
265 2897 : RenderActionType actionType() const override { return RenderActionType::ACCIDENTAL; }
266 : };
267 :
268 : struct RenderActionStopHAlign : RenderAction
269 : {
270 0 : RenderActionStopHAlign() {}
271 0 : RenderActionType actionType() const override { return RenderActionType::STOPHALIGN; }
272 : };
273 :
274 : struct RenderActionScale : RenderAction
275 : {
276 : RenderActionScale() {}
277 20024 : RenderActionScale(double scale)
278 20024 : : m_scale(scale) {}
279 24 : RenderActionType actionType() const override { return RenderActionType::SCALE; }
280 :
281 24 : double scale() const { return m_scale; }
282 :
283 : void print() const override;
284 :
285 : private:
286 : double m_scale = 1.0;
287 : };
288 :
289 : struct RenderActionParen : RenderAction
290 : {
291 : virtual DirectionH direction() const = 0;
292 64 : RenderActionType actionType() const override { return RenderActionType::PAREN; }
293 :
294 : void print() const override;
295 : };
296 :
297 : struct RenderActionParenLeft : RenderActionParen
298 : {
299 915 : RenderActionParenLeft() {}
300 32 : DirectionH direction() const override { return DirectionH::LEFT; }
301 : };
302 :
303 : struct RenderActionParenRight : RenderActionParen
304 : {
305 915 : RenderActionParenRight() {}
306 32 : DirectionH direction() const override { return DirectionH::RIGHT; }
307 : };
308 :
309 : using RenderActionPtr = std::shared_ptr<RenderAction>;
310 : using RenderActionMovePtr = std::shared_ptr<RenderActionMove>;
311 : using RenderActionMoveXHeightPtr = std::shared_ptr<RenderActionMoveXHeight>;
312 : using RenderActionPopPtr = std::shared_ptr<RenderActionPop>;
313 : using RenderActionScalePtr = std::shared_ptr<RenderActionScale>;
314 : using RenderActionSetPtr = std::shared_ptr<RenderActionSet>;
315 : using RenderActionParenPtr = std::shared_ptr<RenderActionParen>;
316 :
317 : //---------------------------------------------------------
318 : // ChordToken
319 : // Reads/represents the <token> tag in chord XML files
320 : //---------------------------------------------------------
321 :
322 : enum class ChordTokenClass : char {
323 : ALL, QUALITY, EXTENSION, MODIFIER, TYPE, ACCIDENTAL
324 : };
325 :
326 : class ChordToken
327 : {
328 : public:
329 : ChordTokenClass tokenClass;
330 : StringList names;
331 : std::vector<RenderActionPtr > renderList;
332 : void read(XmlReader&, int mscVersion);
333 : void write(XmlWriter&) const;
334 747 : bool isValid() const { return !names.empty(); }
335 : };
336 :
337 : //---------------------------------------------------------
338 : // ParsedChord
339 : // Extracts quality, extension & modifiers from a string eg. "m7#11"
340 : // Generates a list of render instructions to lay this chord out
341 : //---------------------------------------------------------
342 :
343 : class ParsedChord
344 : {
345 : public:
346 17096 : ParsedChord() = default;
347 :
348 : bool parse(const String&, const ChordList*, bool syntaxOnly = false, bool preferMinor = false);
349 : String fromXml(const String&, const String&, const String&, const String&, const std::vector<HDegree>&, const ChordList*);
350 : const std::vector<RenderActionPtr >& renderList(const ChordList* cl, bool stacked);
351 49 : bool parseable() const { return m_parseable; }
352 47 : bool understandable() const { return m_understandable; }
353 571 : const String& name() const { return m_name; }
354 10458 : const String& quality() const { return m_quality; }
355 500 : const String& extension() const { return m_extension; }
356 0 : const String& modifiers() const { return m_modifiers; }
357 492 : const StringList& modifierList() const { return m_modifierList; }
358 436 : const String& xmlKind() const { return m_xmlKind; }
359 9942 : const String& xmlText() const { return m_xmlText; }
360 9942 : const String& xmlSymbols() const { return m_xmlSymbols; }
361 9942 : const String& xmlParens() const { return m_xmlParens; }
362 436 : const StringList& xmlDegrees() const { return m_xmlDegrees; }
363 6702 : int keys() const { return m_chord.getKeys(); }
364 0 : const String& handle() const { return m_handle; }
365 : operator String() const {
366 : return m_handle;
367 : }
368 0 : bool operator==(const ParsedChord& c) const { return this->m_handle == c.m_handle; }
369 : bool operator!=(const ParsedChord& c) const { return !(*this == c); }
370 :
371 : private:
372 : void configure(const ChordList*);
373 : void correctXmlText(const String& s = String());
374 : void addToken(String, ChordTokenClass);
375 :
376 : String m_name;
377 : String m_handle;
378 : String m_quality;
379 : String m_extension;
380 : String m_modifiers;
381 : StringList m_modifierList;
382 : std::vector<ChordToken> m_tokenList;
383 : std::vector<RenderActionPtr > m_renderList;
384 : String m_xmlKind;
385 : String m_xmlText;
386 : String m_xmlSymbols;
387 : String m_xmlParens;
388 : StringList m_xmlDegrees;
389 : StringList m_major, m_minor, m_diminished, m_augmented, m_lower, m_raise, m_mod, m_symbols;
390 : HChord m_chord;
391 : bool m_parseable = false;
392 : bool m_understandable = false;
393 : };
394 :
395 : //---------------------------------------------------------
396 : // ChordDescription
397 : // Describes chord quality, extensions and modifiers. eg. m7#11
398 : //---------------------------------------------------------
399 :
400 : struct ChordDescription {
401 : int id = 0; // Chord id number (Band In A Box Chord Number)
402 : StringList names; // list of alternative chord names
403 : // that will by recognized from keyboard entry (without root/base)
404 : std::vector<ParsedChord> parsedChords;
405 : // parsed forms of primary name (optionally also include parsed forms of other names)
406 : String xmlKind; // MusicXML: kind
407 : String xmlText; // MusicXML: kind text=
408 : String xmlSymbols; // MusicXML: kind use-symbols=
409 : String xmlParens; // MusicXML: kind parentheses-degrees=
410 : StringList xmlDegrees; // MusicXML: list of degrees (if any)
411 : HChord chord; // C based chord
412 : std::vector<RenderActionPtr > renderList;
413 : std::vector<RenderActionPtr > renderListStacked;
414 : bool generated = false;
415 : bool renderListGenerated = false;
416 : bool exportOk = false;
417 :
418 0 : ChordDescription() {}
419 : ChordDescription(int);
420 : ChordDescription(const String&);
421 0 : String quality() const { return m_quality; }
422 : void complete(ParsedChord* pc, const ChordList*);
423 : void read(XmlReader&, int mscVersion);
424 : void write(XmlWriter&) const;
425 :
426 : private:
427 : String m_quality;
428 : };
429 :
430 : //---------------------------------------------------------
431 : // ChordSymbol
432 : // Represents the <sym> tag in chord XML files
433 : //---------------------------------------------------------
434 :
435 : struct ChordSymbol {
436 : int fontIdx = -1;
437 : String name;
438 : String value;
439 : Char code;
440 :
441 24689 : bool isValid() const { return fontIdx != -1; }
442 : };
443 :
444 : //---------------------------------------------------------
445 : // ChordFont
446 : // Represents the <font> tag in chord XML files
447 : //---------------------------------------------------------
448 :
449 : struct ChordFont {
450 : String family;
451 : String fontClass;
452 : double mag = 1.0;
453 : bool musicSymbolText = false;
454 : };
455 :
456 : //---------------------------------------------------------
457 : // ChordList
458 : // Reads chord XML files and stores the list of known chords
459 : //---------------------------------------------------------
460 :
461 : class ChordList : public std::map<int, ChordDescription>
462 : {
463 : OBJECT_ALLOCATOR(engraving, ChordList)
464 :
465 : public:
466 : std::vector<ChordFont> fonts;
467 : std::vector<RenderActionPtr > renderListRoot;
468 : std::vector<RenderActionPtr > renderListFunction;
469 : std::vector<RenderActionPtr > renderListBass;
470 : std::vector<RenderActionPtr > renderListBassOffset;
471 : std::vector<ChordToken> chordTokenList;
472 : static int privateID;
473 :
474 10902 : bool autoAdjust() const { return m_autoAdjust; }
475 142 : double nominalMag() const { return m_nmag; }
476 162 : double nominalAdjust() const { return m_nadjust; }
477 : bool stackModifiers() const { return m_stackModifiers; }
478 29627 : bool excludeModsHAlign() const { return m_excludeModsHAlign; }
479 16364 : double stackedModifierMag() const { return m_stackedmmag; }
480 9133 : const ChordStylePreset& chordPreset() const { return m_chordPreset; }
481 : void configureAutoAdjust(double emag = 1.0, double eadjust = 0.0, double mmag = 1.0, double madjust = 0.0, double stackedmmag = 0.0,
482 : bool stackModifiers = false, bool excludeModsHAlign = false, String symbolFont = u"",
483 : const ChordStylePreset& preset = ChordStylePreset::STANDARD);
484 : double position(const StringList& names, bool stackModifiers, bool superScript, ChordTokenClass ctc, size_t modifierIdx,
485 : size_t nmodifiers) const;
486 :
487 : void checkChordList(const MStyle& style);
488 : bool read(const String& name);
489 : bool read(muse::io::IODevice* device);
490 : bool write(const String&) const;
491 : bool write(muse::io::IODevice* device) const;
492 : bool loaded() const;
493 : void unload();
494 :
495 : const ChordDescription* description(int id) const;
496 : ChordSymbol symbol(const String& s) const;
497 : ChordToken token(const String& s, ChordTokenClass) const;
498 :
499 129 : void setCustomChordList(bool t) { m_customChordList = t; }
500 3 : bool customChordList() const { return m_customChordList; }
501 :
502 : private:
503 :
504 : friend class compat::ReadChordListHook;
505 :
506 : void read(XmlReader& xml, int mscVersion);
507 : void write(XmlWriter& xml) const;
508 :
509 : std::map<String, ChordSymbol> m_symbols;
510 : bool m_autoAdjust = false;
511 : bool m_stackModifiers = false;
512 : bool m_excludeModsHAlign = false;
513 : ChordStylePreset m_chordPreset = ChordStylePreset::STANDARD;
514 : double m_nmag = 1.0, m_nadjust = 0.0; // adjust values are measured in percentage
515 : double m_emag = 1.0, m_eadjust = 0.0; // (which is then applied to the height of the font)
516 : double m_mmag = 1.0, m_madjust = 0.0, m_stackedmmag = 0.0;
517 : String m_symbolTextFont = u"";
518 :
519 : bool m_customChordList = false; // if true, chordlist will be saved as part of score
520 : };
521 : }
|