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 : #include "meiconverter.h"
24 :
25 : #include <sstream>
26 : #include <string>
27 : #include <valarray>
28 :
29 : #include "engraving/iengravingconfiguration.h"
30 :
31 : #include "engraving/types/symnames.h"
32 : #include "engraving/types/typesconv.h"
33 :
34 : #include "engraving/dom/arpeggio.h"
35 : #include "engraving/dom/accidental.h"
36 : #include "engraving/dom/breath.h"
37 : #include "engraving/dom/dynamic.h"
38 : #include "engraving/dom/fermata.h"
39 : #include "engraving/dom/figuredbass.h"
40 : #include "engraving/dom/fingering.h"
41 : #include "engraving/dom/glissando.h"
42 : #include "engraving/dom/hairpin.h"
43 : #include "engraving/dom/harmony.h"
44 : #include "engraving/dom/jump.h"
45 : #include "engraving/dom/laissezvib.h"
46 : #include "engraving/dom/lyrics.h"
47 : #include "engraving/dom/marker.h"
48 : #include "engraving/dom/measure.h"
49 : #include "engraving/dom/note.h"
50 : #include "engraving/dom/ottava.h"
51 : #include "engraving/dom/ornament.h"
52 : #include "engraving/dom/part.h"
53 : #include "engraving/dom/pedal.h"
54 : #include "engraving/dom/pitchspelling.h"
55 : #include "engraving/dom/slurtie.h"
56 : #include "engraving/dom/staff.h"
57 : #include "engraving/dom/stafftype.h"
58 : #include "engraving/dom/tempotext.h"
59 : #include "engraving/dom/text.h"
60 : #include "engraving/dom/textbase.h"
61 : #include "engraving/dom/tuplet.h"
62 : #include "engraving/dom/utils.h"
63 :
64 : using namespace mu::iex::mei;
65 : using namespace mu;
66 : using namespace muse;
67 :
68 : StringList Convert::logs;
69 :
70 : muse::GlobalInject<engraving::IEngravingFontsProvider> Convert::engravingFonts;
71 : muse::GlobalInject<engraving::IEngravingConfiguration> Convert::engravingConfiguration;
72 :
73 5 : engraving::ElementType Convert::elementTypeForDir(const libmei::Element& meiElement)
74 : {
75 5 : engraving::ElementType dirType = engraving::ElementType::EXPRESSION;
76 5 : const libmei::AttTyped* typedAtt = dynamic_cast<const libmei::AttTyped*>(&meiElement);
77 5 : if (typedAtt) {
78 10 : if (Convert::hasTypeValue(typedAtt->GetType(), std::string(DIR_TYPE) + "playtech-annotation")) {
79 2 : dirType = engraving::ElementType::PLAYTECH_ANNOTATION;
80 6 : } else if (Convert::hasTypeValue(typedAtt->GetType(), std::string(DIR_TYPE) + "staff-text")) {
81 1 : dirType = engraving::ElementType::STAFF_TEXT;
82 4 : } else if (Convert::hasTypeValue(typedAtt->GetType(), std::string(DIR_TYPE) + "system-text")) {
83 1 : dirType = engraving::ElementType::SYSTEM_TEXT;
84 : }
85 : }
86 5 : return dirType;
87 : }
88 :
89 3 : engraving::ElementType Convert::elementTypeForDirWithExt(const libmei::Element& meiElement)
90 : {
91 3 : engraving::ElementType dirType = engraving::ElementType::TEXTLINE;
92 3 : const libmei::AttTyped* typedAtt = dynamic_cast<const libmei::AttTyped*>(&meiElement);
93 3 : if (typedAtt) {
94 6 : if (Convert::hasTypeValue(typedAtt->GetType(), std::string(DIR_TYPE) + "hairpin")) {
95 3 : dirType = engraving::ElementType::HAIRPIN;
96 : }
97 : }
98 3 : return dirType;
99 : }
100 :
101 23 : engraving::ElementType Convert::elementTypeFor(const libmei::RepeatMark& meiRepeatMark)
102 : {
103 23 : switch (meiRepeatMark.GetFunc()) {
104 14 : case (libmei::repeatMarkLog_FUNC_daCapo):
105 : case (libmei::repeatMarkLog_FUNC_dalSegno):
106 14 : return engraving::ElementType::JUMP;
107 9 : default:
108 9 : return engraving::ElementType::MARKER;
109 : }
110 : }
111 :
112 8 : bool Convert::isDirWithExt(const libmei::Dir& meiDir)
113 : {
114 8 : return meiDir.HasExtender() && (meiDir.GetExtender() == libmei::BOOLEAN_true);
115 : }
116 :
117 33 : bool Convert::isMordent(const engraving::Ornament* ornament)
118 : {
119 33 : switch (ornament->symId()) {
120 22 : case (engraving::SymId::ornamentMordent):
121 : case (engraving::SymId::ornamentShortTrill):
122 : case (engraving::SymId::ornamentTremblement):
123 : case (engraving::SymId::ornamentPrallMordent):
124 : case (engraving::SymId::ornamentUpPrall):
125 : case (engraving::SymId::ornamentPrecompMordentUpperPrefix):
126 : case (engraving::SymId::ornamentUpMordent):
127 : case (engraving::SymId::ornamentDownMordent):
128 : case (engraving::SymId::ornamentPrallDown):
129 : case (engraving::SymId::ornamentPrallUp):
130 : case (engraving::SymId::ornamentLinePrall):
131 : case (engraving::SymId::ornamentPrecompSlide):
132 : case (engraving::SymId::ornamentTremblementCouperin):
133 : case (engraving::SymId::ornamentPinceCouperin):
134 22 : return true;
135 11 : default:
136 11 : return false;
137 : }
138 : }
139 :
140 11 : bool Convert::isTrill(const engraving::Ornament* ornament)
141 : {
142 11 : switch (ornament->symId()) {
143 5 : case (engraving::SymId::ornamentTrill):
144 : case (engraving::SymId::ornamentShake3):
145 : case (engraving::SymId::ornamentShakeMuffat1):
146 5 : return true;
147 6 : default:
148 6 : return false;
149 : }
150 : }
151 :
152 6 : bool Convert::isTurn(const engraving::Ornament* ornament)
153 : {
154 6 : switch (ornament->symId()) {
155 6 : case (engraving::SymId::ornamentTurnInverted):
156 : case (engraving::SymId::ornamentTurnSlash):
157 : case (engraving::SymId::ornamentTurn):
158 6 : return true;
159 0 : default:
160 0 : return false;
161 : }
162 : }
163 :
164 1824 : engraving::AccidentalType Convert::accidFromMEI(const libmei::data_ACCIDENTAL_WRITTEN meiAccid, bool& warning)
165 : {
166 1824 : warning = false;
167 1824 : switch (meiAccid) {
168 1617 : case (libmei::ACCIDENTAL_WRITTEN_NONE): return engraving::AccidentalType::NONE;
169 59 : case (libmei::ACCIDENTAL_WRITTEN_n): return engraving::AccidentalType::NATURAL;
170 68 : case (libmei::ACCIDENTAL_WRITTEN_f): return engraving::AccidentalType::FLAT;
171 5 : case (libmei::ACCIDENTAL_WRITTEN_ff): return engraving::AccidentalType::FLAT2;
172 0 : case (libmei::ACCIDENTAL_WRITTEN_tf): return engraving::AccidentalType::FLAT3;
173 67 : case (libmei::ACCIDENTAL_WRITTEN_s): return engraving::AccidentalType::SHARP;
174 6 : case (libmei::ACCIDENTAL_WRITTEN_x): return engraving::AccidentalType::SHARP2;
175 0 : case (libmei::ACCIDENTAL_WRITTEN_ts): return engraving::AccidentalType::SHARP3;
176 1 : case (libmei::ACCIDENTAL_WRITTEN_nf): return engraving::AccidentalType::NATURAL_FLAT;
177 0 : case (libmei::ACCIDENTAL_WRITTEN_ns): return engraving::AccidentalType::NATURAL_SHARP;
178 1 : case (libmei::ACCIDENTAL_WRITTEN_ss): return engraving::AccidentalType::SHARP_SHARP;
179 0 : default:
180 0 : warning = true;
181 0 : return engraving::AccidentalType::NATURAL;
182 : }
183 : }
184 :
185 207 : libmei::data_ACCIDENTAL_WRITTEN Convert::accidToMEI(const engraving::AccidentalType accid)
186 : {
187 207 : switch (accid) {
188 0 : case (engraving::AccidentalType::NONE): return libmei::ACCIDENTAL_WRITTEN_NONE;
189 59 : case (engraving::AccidentalType::NATURAL): return libmei::ACCIDENTAL_WRITTEN_n;
190 68 : case (engraving::AccidentalType::FLAT): return libmei::ACCIDENTAL_WRITTEN_f;
191 5 : case (engraving::AccidentalType::FLAT2): return libmei::ACCIDENTAL_WRITTEN_ff;
192 0 : case (engraving::AccidentalType::FLAT3): return libmei::ACCIDENTAL_WRITTEN_tf;
193 67 : case (engraving::AccidentalType::SHARP): return libmei::ACCIDENTAL_WRITTEN_s;
194 6 : case (engraving::AccidentalType::SHARP2): return libmei::ACCIDENTAL_WRITTEN_x;
195 0 : case (engraving::AccidentalType::SHARP3): return libmei::ACCIDENTAL_WRITTEN_ts;
196 1 : case (engraving::AccidentalType::NATURAL_FLAT): return libmei::ACCIDENTAL_WRITTEN_nf;
197 0 : case (engraving::AccidentalType::NATURAL_SHARP): return libmei::ACCIDENTAL_WRITTEN_ns;
198 1 : case (engraving::AccidentalType::SHARP_SHARP): return libmei::ACCIDENTAL_WRITTEN_ss;
199 0 : default:
200 0 : return libmei::ACCIDENTAL_WRITTEN_n;
201 : }
202 : }
203 :
204 310 : engraving::AccidentalVal Convert::accidGesFromMEI(const libmei::data_ACCIDENTAL_GESTURAL meiAccid, bool& warning)
205 : {
206 310 : warning = false;
207 310 : switch (meiAccid) {
208 0 : case (libmei::ACCIDENTAL_GESTURAL_NONE): return engraving::AccidentalVal::NATURAL;
209 58 : case (libmei::ACCIDENTAL_GESTURAL_n): return engraving::AccidentalVal::NATURAL;
210 70 : case (libmei::ACCIDENTAL_GESTURAL_f): return engraving::AccidentalVal::FLAT;
211 5 : case (libmei::ACCIDENTAL_GESTURAL_ff): return engraving::AccidentalVal::FLAT2;
212 0 : case (libmei::ACCIDENTAL_GESTURAL_tf): return engraving::AccidentalVal::FLAT3;
213 170 : case (libmei::ACCIDENTAL_GESTURAL_s): return engraving::AccidentalVal::SHARP;
214 7 : case (libmei::ACCIDENTAL_GESTURAL_ss): return engraving::AccidentalVal::SHARP2;
215 0 : case (libmei::ACCIDENTAL_GESTURAL_ts): return engraving::AccidentalVal::SHARP3;
216 0 : default:
217 0 : warning = true;
218 0 : return engraving::AccidentalVal::NATURAL;
219 : }
220 : }
221 :
222 112 : libmei::data_ACCIDENTAL_GESTURAL Convert::accidGesToMEI(const engraving::AccidentalVal accid)
223 : {
224 112 : switch (accid) {
225 0 : case (engraving::AccidentalVal::NATURAL): return libmei::ACCIDENTAL_GESTURAL_n;
226 4 : case (engraving::AccidentalVal::FLAT): return libmei::ACCIDENTAL_GESTURAL_f;
227 0 : case (engraving::AccidentalVal::FLAT2): return libmei::ACCIDENTAL_GESTURAL_ff;
228 0 : case (engraving::AccidentalVal::FLAT3): return libmei::ACCIDENTAL_GESTURAL_tf;
229 108 : case (engraving::AccidentalVal::SHARP): return libmei::ACCIDENTAL_GESTURAL_s;
230 0 : case (engraving::AccidentalVal::SHARP2): return libmei::ACCIDENTAL_GESTURAL_ss;
231 0 : case (engraving::AccidentalVal::SHARP3): return libmei::ACCIDENTAL_GESTURAL_ts;
232 0 : default:
233 0 : return libmei::ACCIDENTAL_GESTURAL_n;
234 : }
235 : }
236 :
237 13 : engraving::ArticulationAnchor Convert::anchorFromMEI(const libmei::data_STAFFREL meiPlace, bool& warning)
238 : {
239 13 : warning = false;
240 13 : switch (meiPlace) {
241 3 : case (libmei::STAFFREL_above): return engraving::ArticulationAnchor::TOP;
242 10 : case (libmei::STAFFREL_below): return engraving::ArticulationAnchor::BOTTOM;
243 0 : default:
244 0 : return engraving::ArticulationAnchor::AUTO;
245 : }
246 : }
247 :
248 13 : libmei::data_STAFFREL Convert::anchorToMEI(engraving::ArticulationAnchor anchor)
249 : {
250 13 : switch (anchor) {
251 3 : case (engraving::ArticulationAnchor::TOP): return libmei::STAFFREL_above;
252 10 : case (engraving::ArticulationAnchor::BOTTOM): return libmei::STAFFREL_below;
253 0 : default:
254 0 : return libmei::STAFFREL_NONE;
255 : }
256 : }
257 :
258 11 : void Convert::arpegFromMEI(engraving::Arpeggio* arpeggio, const libmei::Arpeg& meiArpeg, bool& warning)
259 : {
260 11 : warning = false;
261 :
262 : // @arrow and @order
263 11 : if (meiArpeg.HasOrder()) {
264 7 : switch (meiArpeg.GetOrder()) {
265 2 : case (libmei::arpegLog_ORDER_down):
266 2 : arpeggio->setArpeggioType(engraving::ArpeggioType::DOWN);
267 2 : break;
268 3 : case (libmei::arpegLog_ORDER_nonarp):
269 3 : arpeggio->setArpeggioType(engraving::ArpeggioType::BRACKET);
270 3 : break;
271 2 : case (libmei::arpegLog_ORDER_up):
272 2 : arpeggio->setArpeggioType(engraving::ArpeggioType::UP);
273 2 : break;
274 0 : default:
275 0 : break;
276 : }
277 : }
278 :
279 : // @color
280 11 : Convert::colorFromMEI(arpeggio, meiArpeg);
281 11 : }
282 :
283 11 : libmei::Arpeg Convert::arpegToMEI(const engraving::Arpeggio* arpeggio)
284 : {
285 11 : libmei::Arpeg meiArpeg;
286 :
287 : // @arrow and @order
288 11 : switch (arpeggio->arpeggioType()) {
289 2 : case (engraving::ArpeggioType::DOWN):
290 2 : meiArpeg.SetOrder(libmei::arpegLog_ORDER_down);
291 2 : meiArpeg.SetArrow(libmei::BOOLEAN_true);
292 2 : break;
293 2 : case (engraving::ArpeggioType::UP):
294 2 : meiArpeg.SetOrder(libmei::arpegLog_ORDER_up);
295 2 : meiArpeg.SetArrow(libmei::BOOLEAN_true);
296 2 : break;
297 3 : case (engraving::ArpeggioType::BRACKET):
298 3 : meiArpeg.SetOrder(libmei::arpegLog_ORDER_nonarp);
299 3 : break;
300 4 : default:
301 4 : break;
302 : }
303 :
304 : // @color
305 11 : Convert::colorToMEI(arpeggio, meiArpeg);
306 :
307 11 : return meiArpeg;
308 0 : }
309 :
310 65 : void Convert::articFromMEI(engraving::Articulation* articulation, const libmei::Artic& meiArtic, bool& warning)
311 : {
312 65 : engraving::SymId symId = engraving::SymId::noSym;
313 :
314 : // @artic
315 65 : if (meiArtic.HasArtic() && (meiArtic.GetArtic().size() == 1)) {
316 56 : switch (meiArtic.GetArtic().at(0)) {
317 19 : case (libmei::ARTICULATION_acc): symId = engraving::SymId::articAccentAbove;
318 19 : break;
319 0 : case (libmei::ARTICULATION_acc_inv): break;
320 0 : case (libmei::ARTICULATION_acc_long): break;
321 1 : case (libmei::ARTICULATION_acc_soft): symId = engraving::SymId::articSoftAccentAbove;
322 1 : break;
323 3 : case (libmei::ARTICULATION_stacc): symId = engraving::SymId::articStaccatoAbove;
324 3 : break;
325 2 : case (libmei::ARTICULATION_ten): symId = engraving::SymId::articTenutoAbove;
326 2 : break;
327 2 : case (libmei::ARTICULATION_stacciss): symId = engraving::SymId::articStaccatissimoAbove;
328 2 : break;
329 2 : case (libmei::ARTICULATION_marc): symId = engraving::SymId::articMarcatoAbove;
330 2 : break;
331 2 : case (libmei::ARTICULATION_spicc): symId = engraving::SymId::articStaccatissimoWedgeAbove;
332 2 : break;
333 0 : case (libmei::ARTICULATION_stress): symId = engraving::SymId::articStressAbove;
334 0 : break;
335 0 : case (libmei::ARTICULATION_unstress): symId = engraving::SymId::articUnstressAbove;
336 0 : break;
337 0 : case (libmei::ARTICULATION_shake): break;
338 4 : case (libmei::ARTICULATION_dnbow): symId = engraving::SymId::stringsDownBow;
339 4 : break;
340 3 : case (libmei::ARTICULATION_upbow): symId = engraving::SymId::stringsUpBow;
341 3 : break;
342 1 : case (libmei::ARTICULATION_harm): symId = engraving::SymId::stringsHarmonic;
343 1 : break;
344 1 : case (libmei::ARTICULATION_snap): symId = engraving::SymId::pluckedSnapPizzicatoAbove;
345 1 : break;
346 0 : case (libmei::ARTICULATION_fingernail): symId = engraving::SymId::pluckedWithFingernails;
347 0 : break;
348 0 : case (libmei::ARTICULATION_damp): symId = engraving::SymId::pluckedDamp;
349 0 : break;
350 0 : case (libmei::ARTICULATION_dampall): symId = engraving::SymId::pluckedDampAll;
351 0 : break;
352 1 : case (libmei::ARTICULATION_open): symId = engraving::SymId::brassMuteOpen;
353 1 : break;
354 1 : case (libmei::ARTICULATION_stop): symId = engraving::SymId::brassMuteClosed;
355 1 : break;
356 0 : case (libmei::ARTICULATION_dbltongue): symId = engraving::SymId::doubleTongueAbove;
357 0 : break;
358 0 : case (libmei::ARTICULATION_trpltongue): symId = engraving::SymId::tripleTongueAbove;
359 0 : break;
360 0 : case (libmei::ARTICULATION_heel): symId = engraving::SymId::keyboardPedalHeel1;
361 0 : break;
362 0 : case (libmei::ARTICULATION_toe): symId = engraving::SymId::keyboardPedalToe1;
363 0 : break;
364 0 : case (libmei::ARTICULATION_tap): symId = engraving::SymId::guitarRightHandTapping;
365 0 : break;
366 0 : case (libmei::ARTICULATION_lhpizz): symId = engraving::SymId::pluckedLeftHandPizzicato;
367 0 : break;
368 0 : case (libmei::ARTICULATION_dot): symId = engraving::SymId::articStaccatoAbove;
369 0 : break;
370 2 : case (libmei::ARTICULATION_stroke): symId = engraving::SymId::articStaccatissimoStrokeAbove;
371 2 : break;
372 12 : default: break;
373 : }
374 : }
375 65 : if (meiArtic.HasArtic() && (meiArtic.GetArtic().size() == 2)) {
376 9 : if (meiArtic.GetArtic().at(0) == libmei::ARTICULATION_stacc) {
377 6 : switch (meiArtic.GetArtic().at(1)) {
378 : // ordered by @artic
379 2 : case (libmei::ARTICULATION_acc): symId = engraving::SymId::articAccentStaccatoAbove;
380 2 : break;
381 2 : case (libmei::ARTICULATION_marc): symId = engraving::SymId::articMarcatoStaccatoAbove;
382 2 : break;
383 2 : case (libmei::ARTICULATION_ten): symId = engraving::SymId::articTenutoStaccatoAbove;
384 2 : break;
385 0 : default: break;
386 : }
387 3 : } else if (meiArtic.GetArtic().at(0) == libmei::ARTICULATION_ten) {
388 3 : switch (meiArtic.GetArtic().at(1)) {
389 : // ordered by @artic
390 1 : case (libmei::ARTICULATION_acc): symId = engraving::SymId::articTenutoAccentAbove;
391 1 : break;
392 2 : case (libmei::ARTICULATION_marc): symId = engraving::SymId::articMarcatoTenutoAbove;
393 2 : break;
394 0 : default: break;
395 : }
396 : }
397 : }
398 65 : articulation->setSymId(symId);
399 :
400 : // @place
401 65 : if (meiArtic.HasPlace()) {
402 7 : bool placeWarning = false;
403 7 : articulation->setAnchor(Convert::anchorFromMEI(meiArtic.GetPlace(), placeWarning));
404 7 : articulation->setPropertyFlags(engraving::Pid::ARTICULATION_ANCHOR, engraving::PropertyFlags::UNSTYLED);
405 7 : warning = (warning || placeWarning);
406 : }
407 :
408 : // @color
409 65 : Convert::colorFromMEI(articulation, meiArtic);
410 65 : }
411 :
412 12 : void Convert::articFromMEI(engraving::ChordLine* chordline, const libmei::Artic& meiArtic, bool& warning)
413 : {
414 : // @artic
415 12 : if (meiArtic.HasArtic() && (meiArtic.GetArtic().size() == 1)) {
416 12 : switch (meiArtic.GetArtic().at(0)) {
417 3 : case (libmei::ARTICULATION_doit): chordline->setChordLineType(engraving::ChordLineType::DOIT);
418 3 : break;
419 3 : case (libmei::ARTICULATION_scoop): chordline->setChordLineType(engraving::ChordLineType::SCOOP);
420 3 : break;
421 0 : case (libmei::ARTICULATION_rip): break;
422 3 : case (libmei::ARTICULATION_plop): chordline->setChordLineType(engraving::ChordLineType::PLOP);
423 3 : break;
424 3 : case (libmei::ARTICULATION_fall): chordline->setChordLineType(engraving::ChordLineType::FALL);
425 3 : break;
426 0 : case (libmei::ARTICULATION_longfall): break;
427 0 : case (libmei::ARTICULATION_bend): break;
428 0 : case (libmei::ARTICULATION_flip): break;
429 0 : case (libmei::ARTICULATION_smear): break;
430 0 : default: break;
431 : }
432 : }
433 :
434 : // @type
435 24 : if (Convert::hasTypeValue(meiArtic.GetType(), std::string(CHORDLINE_TYPE) + "straight")) {
436 4 : chordline->setStraight(true);
437 16 : } else if (Convert::hasTypeValue(meiArtic.GetType(), std::string(CHORDLINE_TYPE) + "wavy")) {
438 4 : chordline->setWavy(true);
439 : }
440 :
441 : // @place
442 12 : if (meiArtic.HasPlace()) {
443 0 : bool placeWarning = true;
444 0 : warning = (warning || placeWarning);
445 : }
446 :
447 : // @color
448 12 : Convert::colorFromMEI(chordline, meiArtic);
449 12 : }
450 :
451 53 : libmei::Artic Convert::articToMEI(const engraving::Articulation* articulation)
452 : {
453 53 : libmei::Artic meiArtic;
454 :
455 : // @artic
456 53 : switch (articulation->symId()) {
457 19 : case (engraving::SymId::articAccentAbove):
458 38 : case (engraving::SymId::articAccentBelow): meiArtic.SetArtic({ libmei::ARTICULATION_acc });
459 19 : break;
460 2 : case (engraving::SymId::articAccentStaccatoAbove):
461 4 : case (engraving::SymId::articAccentStaccatoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stacc, libmei::ARTICULATION_acc });
462 2 : break;
463 2 : case (engraving::SymId::articMarcatoAbove):
464 4 : case (engraving::SymId::articMarcatoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_marc });
465 2 : break;
466 2 : case (engraving::SymId::articMarcatoStaccatoAbove):
467 4 : case (engraving::SymId::articMarcatoStaccatoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stacc, libmei::ARTICULATION_marc });
468 2 : break;
469 2 : case (engraving::SymId::articMarcatoTenutoAbove):
470 4 : case (engraving::SymId::articMarcatoTenutoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_ten, libmei::ARTICULATION_marc });
471 2 : break;
472 1 : case (engraving::SymId::articSoftAccentAbove):
473 2 : case (engraving::SymId::articSoftAccentBelow): meiArtic.SetArtic({ libmei::ARTICULATION_acc_soft });
474 1 : break;
475 2 : case (engraving::SymId::articStaccatissimoAbove):
476 4 : case (engraving::SymId::articStaccatissimoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stacciss });
477 2 : break;
478 2 : case (engraving::SymId::articStaccatissimoStrokeAbove):
479 4 : case (engraving::SymId::articStaccatissimoStrokeBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stroke });
480 2 : break;
481 2 : case (engraving::SymId::articStaccatissimoWedgeAbove):
482 4 : case (engraving::SymId::articStaccatissimoWedgeBelow): meiArtic.SetArtic({ libmei::ARTICULATION_spicc });
483 2 : break;
484 3 : case (engraving::SymId::articStaccatoAbove):
485 6 : case (engraving::SymId::articStaccatoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stacc });
486 3 : break;
487 2 : case (engraving::SymId::articTenutoAbove):
488 4 : case (engraving::SymId::articTenutoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_ten });
489 2 : break;
490 1 : case (engraving::SymId::articTenutoAccentAbove):
491 2 : case (engraving::SymId::articTenutoAccentBelow): meiArtic.SetArtic({ libmei::ARTICULATION_ten, libmei::ARTICULATION_acc });
492 1 : break;
493 2 : case (engraving::SymId::articTenutoStaccatoAbove):
494 4 : case (engraving::SymId::articTenutoStaccatoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stacc, libmei::ARTICULATION_ten });
495 2 : break;
496 1 : case (engraving::SymId::pluckedSnapPizzicatoAbove):
497 2 : case (engraving::SymId::pluckedSnapPizzicatoBelow): meiArtic.SetArtic({ libmei::ARTICULATION_snap });
498 1 : break;
499 4 : case (engraving::SymId::stringsDownBow):
500 8 : case (engraving::SymId::stringsDownBowTurned): meiArtic.SetArtic({ libmei::ARTICULATION_dnbow });
501 4 : break;
502 3 : case (engraving::SymId::stringsUpBow):
503 6 : case (engraving::SymId::stringsUpBowTurned): meiArtic.SetArtic({ libmei::ARTICULATION_upbow });
504 3 : break;
505 0 : case (engraving::SymId::articStressAbove):
506 0 : case (engraving::SymId::articStressBelow): meiArtic.SetArtic({ libmei::ARTICULATION_stress });
507 0 : break;
508 0 : case (engraving::SymId::articUnstressAbove):
509 0 : case (engraving::SymId::articUnstressBelow): meiArtic.SetArtic({ libmei::ARTICULATION_unstress });
510 0 : break;
511 : // Values without down or invert
512 2 : case (engraving::SymId::brassMuteClosed): meiArtic.SetArtic({ libmei::ARTICULATION_stop });
513 1 : break;
514 2 : case (engraving::SymId::brassMuteOpen): meiArtic.SetArtic({ libmei::ARTICULATION_open });
515 1 : break;
516 2 : case (engraving::SymId::stringsHarmonic): meiArtic.SetArtic({ libmei::ARTICULATION_harm });
517 1 : break;
518 0 : case (engraving::SymId::keyboardPedalHeel1):
519 : case (engraving::SymId::keyboardPedalHeel2):
520 0 : case (engraving::SymId::keyboardPedalHeel3): meiArtic.SetArtic({ libmei::ARTICULATION_heel });
521 0 : break;
522 0 : case (engraving::SymId::keyboardPedalToe1):
523 0 : case (engraving::SymId::keyboardPedalToe2): meiArtic.SetArtic({ libmei::ARTICULATION_toe });
524 0 : break;
525 0 : case (engraving::SymId::pluckedWithFingernails): meiArtic.SetArtic({ libmei::ARTICULATION_fingernail });
526 0 : break;
527 0 : case (engraving::SymId::pluckedDamp): meiArtic.SetArtic({ libmei::ARTICULATION_damp });
528 0 : break;
529 0 : case (engraving::SymId::pluckedDampAll): meiArtic.SetArtic({ libmei::ARTICULATION_dampall });
530 0 : break;
531 :
532 0 : default:
533 0 : break;
534 : }
535 :
536 : // @place
537 53 : if (articulation->propertyFlags(engraving::Pid::ARTICULATION_ANCHOR) == engraving::PropertyFlags::UNSTYLED) {
538 7 : meiArtic.SetPlace(Convert::anchorToMEI(articulation->anchor()));
539 : }
540 :
541 : // @color
542 53 : Convert::colorToMEI(articulation, meiArtic);
543 :
544 53 : return meiArtic;
545 0 : }
546 :
547 12 : libmei::Artic Convert::articToMEI(const engraving::ChordLine* chordline)
548 : {
549 12 : libmei::Artic meiArtic;
550 :
551 : // @artic
552 12 : switch (chordline->chordLineType()) {
553 6 : case engraving::ChordLineType::FALL: meiArtic.SetArtic({ libmei::ARTICULATION_fall });
554 3 : break;
555 6 : case engraving::ChordLineType::DOIT: meiArtic.SetArtic({ libmei::ARTICULATION_doit });
556 3 : break;
557 6 : case engraving::ChordLineType::PLOP: meiArtic.SetArtic({ libmei::ARTICULATION_plop });
558 3 : break;
559 6 : case engraving::ChordLineType::SCOOP: meiArtic.SetArtic({ libmei::ARTICULATION_scoop });
560 3 : break;
561 0 : case engraving::ChordLineType::NOTYPE: meiArtic.SetArtic({ libmei::ARTICULATION_NONE });
562 0 : break;
563 : }
564 :
565 : // @type
566 12 : if (chordline->isWavy()) {
567 12 : meiArtic.SetType(std::string(CHORDLINE_TYPE) + "wavy");
568 8 : } else if (chordline->isStraight()) {
569 12 : meiArtic.SetType(std::string(CHORDLINE_TYPE) + "straight");
570 : }
571 :
572 : // @color
573 12 : Convert::colorToMEI(chordline, meiArtic);
574 :
575 12 : return meiArtic;
576 0 : }
577 :
578 77 : engraving::BarLineType Convert::barlineFromMEI(const libmei::data_BARRENDITION meiBarline, bool& warning)
579 : {
580 77 : warning = false;
581 77 : switch (meiBarline) {
582 0 : case (libmei::BARRENDITION_single): return engraving::BarLineType::NORMAL;
583 4 : case (libmei::BARRENDITION_dbl): return engraving::BarLineType::DOUBLE;
584 5 : case (libmei::BARRENDITION_rptstart): return engraving::BarLineType::START_REPEAT;
585 6 : case (libmei::BARRENDITION_rptend): return engraving::BarLineType::END_REPEAT;
586 1 : case (libmei::BARRENDITION_dashed): return engraving::BarLineType::BROKEN;
587 58 : case (libmei::BARRENDITION_end): return engraving::BarLineType::END;
588 0 : case (libmei::BARRENDITION_rptboth): return engraving::BarLineType::END_START_REPEAT;
589 1 : case (libmei::BARRENDITION_dotted): return engraving::BarLineType::DOTTED;
590 1 : case (libmei::BARRENDITION_heavy): return engraving::BarLineType::HEAVY;
591 1 : case (libmei::BARRENDITION_dblheavy): return engraving::BarLineType::DOUBLE_HEAVY;
592 0 : case (libmei::BARRENDITION_dbldashed):
593 : case (libmei::BARRENDITION_dbldotted):
594 0 : warning = true;
595 0 : return engraving::BarLineType::DOUBLE;
596 0 : case (libmei::BARRENDITION_dblsegno):
597 0 : warning = true;
598 0 : return engraving::BarLineType::DOUBLE;
599 0 : case (libmei::BARRENDITION_segno):
600 : case (libmei::BARRENDITION_invis):
601 0 : warning = true;
602 0 : return engraving::BarLineType::SINGLE;
603 0 : default:
604 0 : return engraving::BarLineType::SINGLE;
605 : }
606 : }
607 :
608 404 : libmei::data_BARRENDITION Convert::barlineToMEI(const engraving::BarLineType barline)
609 : {
610 404 : switch (barline) {
611 332 : case (engraving::BarLineType::NORMAL): return libmei::BARRENDITION_NONE;
612 4 : case (engraving::BarLineType::DOUBLE): return libmei::BARRENDITION_dbl;
613 0 : case (engraving::BarLineType::START_REPEAT): return libmei::BARRENDITION_rptstart;
614 6 : case (engraving::BarLineType::END_REPEAT): return libmei::BARRENDITION_rptend;
615 1 : case (engraving::BarLineType::BROKEN): return libmei::BARRENDITION_dashed;
616 58 : case (engraving::BarLineType::END): return libmei::BARRENDITION_end;
617 0 : case (engraving::BarLineType::END_START_REPEAT):
618 0 : return libmei::BARRENDITION_rptboth;
619 1 : case (engraving::BarLineType::DOTTED): return libmei::BARRENDITION_dotted;
620 1 : case (engraving::BarLineType::HEAVY): return libmei::BARRENDITION_heavy;
621 1 : case (engraving::BarLineType::DOUBLE_HEAVY): return libmei::BARRENDITION_dblheavy;
622 0 : case (engraving::BarLineType::REVERSE_END):
623 0 : LOGD() << "Unsupported engraving::BarLineType::REVERSE_END";
624 0 : return libmei::BARRENDITION_dbl;
625 0 : default:
626 0 : return libmei::BARRENDITION_single;
627 : }
628 : }
629 :
630 1643 : engraving::BeamMode Convert::beamFromMEI(const std::string& typeAtt, const std::string& prefix, bool& warning)
631 : {
632 1643 : warning = false;
633 :
634 1643 : engraving::BeamMode beamMode = engraving::BeamMode::AUTO;
635 1643 : if (Convert::hasTypeValue(typeAtt, prefix + "-begin")) {
636 27 : beamMode = engraving::BeamMode::BEGIN;
637 1616 : } else if (Convert::hasTypeValue(typeAtt, prefix + "-mid")) {
638 48 : beamMode = engraving::BeamMode::MID;
639 1568 : } else if (Convert::hasTypeValue(typeAtt, prefix + "-none")) {
640 41 : beamMode = engraving::BeamMode::NONE;
641 : }
642 :
643 1643 : return beamMode;
644 : }
645 :
646 116 : std::string Convert::beamToMEI(engraving::BeamMode beamMode, const std::string& prefix)
647 : {
648 116 : std::string beamType;
649 :
650 116 : switch (beamMode) {
651 27 : case (engraving::BeamMode::BEGIN):
652 27 : beamType = prefix + "-begin";
653 27 : break;
654 48 : case (engraving::BeamMode::MID):
655 48 : beamType = prefix + "-mid";
656 48 : break;
657 41 : case (engraving::BeamMode::NONE):
658 41 : beamType = prefix + "-none";
659 41 : break;
660 0 : default: break;
661 : }
662 :
663 116 : return beamType;
664 0 : }
665 :
666 1643 : engraving::BeamMode Convert::breaksecFromMEI(int breaksec, bool& warning)
667 : {
668 1643 : warning = false;
669 :
670 1643 : switch (breaksec) {
671 22 : case (1): return engraving::BeamMode::BEGIN16;
672 7 : case (2): return engraving::BeamMode::BEGIN32;
673 1614 : default:
674 1614 : warning = true;
675 1614 : break;
676 : }
677 :
678 1614 : return engraving::BeamMode::AUTO;
679 : }
680 :
681 29 : int Convert::breaksecToMEI(engraving::BeamMode beamMode)
682 : {
683 29 : int breaksec = MEI_UNSET;
684 :
685 29 : switch (beamMode) {
686 22 : case (engraving::BeamMode::BEGIN16): breaksec = 1;
687 22 : break;
688 7 : case (engraving::BeamMode::BEGIN32): breaksec = 2;
689 7 : break;
690 0 : default: break;
691 : }
692 :
693 29 : return breaksec;
694 : }
695 :
696 4 : void Convert::breathFromMEI(engraving::Breath* breath, const libmei::Breath& meiBreath, bool& warning)
697 : {
698 4 : warning = false;
699 :
700 : // @glyph.name
701 4 : bool smufl = (meiBreath.HasGlyphAuth() && (meiBreath.GetGlyphAuth() == SMUFL_AUTH));
702 :
703 4 : engraving::SymId symId = engraving::SymId::breathMarkComma;
704 :
705 4 : if (smufl && meiBreath.HasGlyphName()) {
706 1 : symId = engraving::SymNames::symIdByName(String(meiBreath.GetGlyphName().c_str()));
707 1 : if (symId == engraving::SymId::noSym) {
708 0 : warning = true;
709 : }
710 : }
711 : // This is for loading MEI files not written by MuseScore and that use @glyph.num instead of @glyph.name
712 3 : else if (smufl && meiBreath.HasGlyphNum()) {
713 0 : symId = engravingFonts()->fallbackFont()->fromCode(meiBreath.GetGlyphNum());
714 0 : if (symId == engraving::SymId::noSym) {
715 0 : warning = true;
716 : }
717 : }
718 :
719 : // breath doesn't support @place, so we set default placement
720 4 : breath->setPlacement(breath->track() & 1 ? engraving::PlacementV::BELOW : engraving::PlacementV::ABOVE);
721 :
722 : // @color
723 4 : Convert::colorFromMEI(breath, meiBreath);
724 :
725 4 : breath->setSymId(symId);
726 4 : }
727 :
728 4 : libmei::Breath Convert::breathToMEI(const engraving::Breath* breath)
729 : {
730 4 : libmei::Breath meiBreath;
731 :
732 4 : bool smufl = false;
733 : // @glyph.name
734 4 : switch (breath->symId()) {
735 1 : case (engraving::SymId::breathMarkTick):
736 : case (engraving::SymId::breathMarkSalzedo):
737 1 : case (engraving::SymId::breathMarkUpbow): smufl = true;
738 4 : default:
739 4 : break;
740 : }
741 : // @glyph.name
742 4 : if (smufl) {
743 1 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(breath->symId());
744 2 : meiBreath.SetGlyphName(glyphName.ascii());
745 3 : meiBreath.SetGlyphAuth(SMUFL_AUTH);
746 : }
747 :
748 : // @color
749 4 : Convert::colorToMEI(breath, meiBreath);
750 :
751 4 : return meiBreath;
752 0 : }
753 :
754 13 : void Convert::caesuraFromMEI(engraving::Breath* breath, const libmei::Caesura& meiCeasura, bool& warning)
755 : {
756 13 : warning = false;
757 :
758 : // @glyph.name
759 13 : bool smufl = (meiCeasura.HasGlyphAuth() && (meiCeasura.GetGlyphAuth() == SMUFL_AUTH));
760 :
761 13 : engraving::SymId symId = engraving::SymId::caesura;
762 :
763 13 : if (smufl && meiCeasura.HasGlyphName()) {
764 8 : symId = engraving::SymNames::symIdByName(String(meiCeasura.GetGlyphName().c_str()));
765 8 : if (symId == engraving::SymId::noSym) {
766 0 : warning = true;
767 : }
768 : }
769 : // This is for loading MEI files not written by MuseScore and that use @glyph.num instead of @glyph.name
770 5 : else if (smufl && meiCeasura.HasGlyphNum()) {
771 0 : symId = engravingFonts()->fallbackFont()->fromCode(meiCeasura.GetGlyphNum());
772 0 : if (symId == engraving::SymId::noSym) {
773 0 : warning = true;
774 : }
775 : }
776 :
777 : // caesura doesn't support @place, so we set default placement
778 13 : breath->setPlacement(breath->track() & 1 ? engraving::PlacementV::BELOW : engraving::PlacementV::ABOVE);
779 :
780 : // @color
781 13 : Convert::colorFromMEI(breath, meiCeasura);
782 :
783 13 : breath->setSymId(symId);
784 13 : }
785 :
786 13 : libmei::Caesura Convert::caesuraToMEI(const engraving::Breath* breath)
787 : {
788 13 : libmei::Caesura meiCaesura;
789 :
790 13 : bool smufl = false;
791 : // @glyph.name
792 13 : switch (breath->symId()) {
793 8 : case (engraving::SymId::caesuraCurved):
794 : case (engraving::SymId::caesuraShort):
795 : case (engraving::SymId::caesuraThick):
796 : case (engraving::SymId::chantCaesura):
797 8 : case (engraving::SymId::caesuraSingleStroke): smufl = true;
798 13 : default:
799 13 : break;
800 : }
801 : // @glyph.name
802 13 : if (smufl) {
803 8 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(breath->symId());
804 16 : meiCaesura.SetGlyphName(glyphName.ascii());
805 24 : meiCaesura.SetGlyphAuth(SMUFL_AUTH);
806 : }
807 :
808 : // @color
809 13 : Convert::colorToMEI(breath, meiCaesura);
810 :
811 13 : return meiCaesura;
812 0 : }
813 :
814 156 : engraving::ClefType Convert::clefFromMEI(const libmei::Clef& meiClef, bool& warning)
815 : {
816 156 : warning = false;
817 :
818 : // @glyph.name
819 156 : bool smufl = (meiClef.HasGlyphAuth() && (meiClef.GetGlyphAuth() == SMUFL_AUTH));
820 :
821 : // We give @glyph.name priority over @shape
822 156 : if (smufl && meiClef.HasGlyphName()) {
823 11 : if (meiClef.GetGlyphName() == "cClefFrench") {
824 3 : switch (meiClef.GetLine()) {
825 1 : case 1: return engraving::ClefType::C1_F18C;
826 1 : case 3: return engraving::ClefType::C3_F18C;
827 1 : case 4: return engraving::ClefType::C4_F18C;
828 0 : default:
829 0 : break;
830 : }
831 8 : } else if (meiClef.GetGlyphName() == "cClefFrench20C") {
832 3 : switch (meiClef.GetLine()) {
833 1 : case 1: return engraving::ClefType::C1_F20C;
834 1 : case 3: return engraving::ClefType::C3_F20C;
835 1 : case 4: return engraving::ClefType::C4_F20C;
836 0 : default:
837 0 : break;
838 : }
839 5 : } else if (meiClef.GetGlyphName() == "cClefSquare") {
840 1 : switch (meiClef.GetLine()) {
841 1 : case 2: return engraving::ClefType::C_19C;
842 0 : default:
843 0 : break;
844 : }
845 4 : } else if (meiClef.GetGlyphName() == "fClefFrench") {
846 1 : switch (meiClef.GetLine()) {
847 1 : case 4: return engraving::ClefType::F_F18C;
848 0 : default:
849 0 : break;
850 : }
851 3 : } else if (meiClef.GetGlyphName() == "fClef19thCentury") {
852 1 : switch (meiClef.GetLine()) {
853 1 : case 4: return engraving::ClefType::F_19C;
854 0 : default:
855 0 : break;
856 : }
857 2 : } else if (meiClef.GetGlyphName() == "gClef8vbParens") {
858 2 : switch (meiClef.GetLine()) {
859 2 : case 2: return engraving::ClefType::G8_VB_P;
860 0 : default:
861 0 : break;
862 : }
863 : } else {
864 0 : LOGD() << "Unsupported clef@glyph.name";
865 : // try to find a proper replacement from other attributes
866 : }
867 : }
868 :
869 : // @shape
870 145 : if (meiClef.GetShape() == libmei::CLEFSHAPE_G) {
871 82 : if (meiClef.GetDisPlace() == libmei::STAFFREL_basic_below) {
872 4 : switch (meiClef.GetDis()) {
873 3 : case (libmei::OCTAVE_DIS_8): return engraving::ClefType::G8_VB;
874 1 : case (libmei::OCTAVE_DIS_15): return engraving::ClefType::G15_MB;
875 0 : default:
876 0 : break;
877 : }
878 78 : } else if (meiClef.GetDisPlace() == libmei::STAFFREL_basic_above) {
879 2 : switch (meiClef.GetDis()) {
880 1 : case (libmei::OCTAVE_DIS_8): return engraving::ClefType::G8_VA;
881 1 : case (libmei::OCTAVE_DIS_15): return engraving::ClefType::G15_MA;
882 0 : default:
883 0 : break;
884 : }
885 : }
886 76 : if (meiClef.GetLine() == 2) {
887 75 : return engraving::ClefType::G;
888 1 : } else if (meiClef.GetLine() == 1) {
889 1 : return engraving::ClefType::G_1;
890 : }
891 63 : } else if (meiClef.GetShape() == libmei::CLEFSHAPE_C) {
892 14 : switch (meiClef.GetLine()) {
893 2 : case (1): return engraving::ClefType::C1;
894 1 : case (2): return engraving::ClefType::C2;
895 8 : case (3): return engraving::ClefType::C3;
896 2 : case (4):
897 2 : if (meiClef.GetDisPlace() == libmei::STAFFREL_basic_below && meiClef.GetDis() == libmei::OCTAVE_DIS_8) {
898 1 : return engraving::ClefType::C4_8VB;
899 : }
900 1 : return engraving::ClefType::C4;
901 1 : case (5): return engraving::ClefType::C5;
902 0 : default:
903 0 : break;
904 : }
905 49 : } else if (meiClef.GetShape() == libmei::CLEFSHAPE_F) {
906 48 : if (meiClef.GetDisPlace() == libmei::STAFFREL_basic_below) {
907 2 : switch (meiClef.GetDis()) {
908 1 : case (libmei::OCTAVE_DIS_8): return engraving::ClefType::F8_VB;
909 1 : case (libmei::OCTAVE_DIS_15): return engraving::ClefType::F15_MB;
910 0 : default:
911 0 : break;
912 : }
913 46 : } else if (meiClef.GetDisPlace() == libmei::STAFFREL_basic_above) {
914 2 : switch (meiClef.GetDis()) {
915 1 : case (libmei::OCTAVE_DIS_8): return engraving::ClefType::F_8VA;
916 1 : case (libmei::OCTAVE_DIS_15): return engraving::ClefType::F_15MA;
917 0 : default:
918 0 : break;
919 : }
920 : }
921 44 : switch (meiClef.GetLine()) {
922 1 : case (3): return engraving::ClefType::F_B;
923 42 : case (4): return engraving::ClefType::F;
924 1 : case (5): return engraving::ClefType::F_C;
925 0 : default:
926 0 : break;
927 : }
928 1 : } else if (meiClef.GetShape() == libmei::CLEFSHAPE_perc) {
929 0 : return engraving::ClefType::PERC;
930 1 : } else if (meiClef.GetShape() == libmei::CLEFSHAPE_GG && meiClef.GetLine() == 2) {
931 1 : return engraving::ClefType::G8_VB_O;
932 : }
933 0 : warning = true;
934 0 : return engraving::ClefType::G;
935 : }
936 :
937 156 : libmei::Clef Convert::clefToMEI(engraving::ClefType clef)
938 : {
939 156 : libmei::Clef meiClef;
940 : // @shape
941 156 : switch (clef) {
942 82 : case (engraving::ClefType::G):
943 : case (engraving::ClefType::G15_MB):
944 : case (engraving::ClefType::G8_VB):
945 : case (engraving::ClefType::G8_VA):
946 : case (engraving::ClefType::G15_MA):
947 : case (engraving::ClefType::G_1):
948 82 : meiClef.SetShape(libmei::CLEFSHAPE_G);
949 145 : break;
950 14 : case (engraving::ClefType::C1):
951 : case (engraving::ClefType::C2):
952 : case (engraving::ClefType::C3):
953 : case (engraving::ClefType::C4):
954 : case (engraving::ClefType::C4_8VB):
955 : case (engraving::ClefType::C5):
956 14 : meiClef.SetShape(libmei::CLEFSHAPE_C);
957 14 : break;
958 48 : case (engraving::ClefType::F):
959 : case (engraving::ClefType::F15_MB):
960 : case (engraving::ClefType::F8_VB):
961 : case (engraving::ClefType::F_8VA):
962 : case (engraving::ClefType::F_15MA):
963 : case (engraving::ClefType::F_B):
964 : case (engraving::ClefType::F_C):
965 48 : meiClef.SetShape(libmei::CLEFSHAPE_F);
966 48 : break;
967 1 : case (engraving::ClefType::G8_VB_O):
968 1 : meiClef.SetShape(libmei::CLEFSHAPE_GG);
969 1 : break;
970 0 : case (engraving::ClefType::PERC):
971 : case (engraving::ClefType::PERC2):
972 0 : meiClef.SetShape(libmei::CLEFSHAPE_perc);
973 0 : break;
974 11 : default:
975 11 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(engraving::ClefInfo::symId(clef));
976 22 : meiClef.SetGlyphName(glyphName.ascii());
977 22 : meiClef.SetGlyphAuth(SMUFL_AUTH);
978 11 : switch (glyphName.at(0).unicode()) {
979 7 : case 'c':
980 7 : meiClef.SetShape(libmei::CLEFSHAPE_C);
981 7 : break;
982 2 : case 'f':
983 2 : meiClef.SetShape(libmei::CLEFSHAPE_F);
984 2 : break;
985 2 : case 'g':
986 2 : meiClef.SetShape(libmei::CLEFSHAPE_G);
987 2 : break;
988 0 : default:
989 0 : LOGD() << "Unsupported engraving::ClefType";
990 0 : meiClef.SetShape(libmei::CLEFSHAPE_NONE);
991 0 : break;
992 : }
993 : }
994 :
995 156 : if (meiClef.GetShape() != libmei::CLEFSHAPE_perc) {
996 156 : const int line = engraving::ClefInfo::line(clef);
997 156 : meiClef.SetLine(line);
998 : }
999 :
1000 : // @dis and @dis.place
1001 156 : switch (clef) {
1002 7 : case (engraving::ClefType::G8_VB):
1003 : case (engraving::ClefType::G8_VA):
1004 : case (engraving::ClefType::G8_VB_C):
1005 : case (engraving::ClefType::F8_VB):
1006 : case (engraving::ClefType::F_8VA):
1007 : case (engraving::ClefType::C4_8VB):
1008 7 : meiClef.SetDis(libmei::OCTAVE_DIS_8);
1009 7 : break;
1010 4 : case (engraving::ClefType::G15_MB):
1011 : case (engraving::ClefType::G15_MA):
1012 : case (engraving::ClefType::F15_MB):
1013 : case (engraving::ClefType::F_15MA):
1014 4 : meiClef.SetDis(libmei::OCTAVE_DIS_15);
1015 4 : break;
1016 145 : default:
1017 145 : break;
1018 : }
1019 :
1020 : // @dis.place
1021 156 : switch (clef) {
1022 7 : case (engraving::ClefType::G8_VB):
1023 : case (engraving::ClefType::F8_VB):
1024 : case (engraving::ClefType::C4_8VB):
1025 : case (engraving::ClefType::G15_MB):
1026 : case (engraving::ClefType::F15_MB):
1027 7 : meiClef.SetDisPlace(libmei::STAFFREL_basic_below);
1028 7 : break;
1029 4 : case (engraving::ClefType::G8_VA):
1030 : case (engraving::ClefType::F_8VA):
1031 : case (engraving::ClefType::G15_MA):
1032 : case (engraving::ClefType::F_15MA):
1033 4 : meiClef.SetDisPlace(libmei::STAFFREL_basic_above);
1034 4 : break;
1035 145 : default:
1036 145 : break;
1037 : }
1038 :
1039 156 : return meiClef;
1040 0 : }
1041 :
1042 0 : engraving::ClefType Convert::clefFromMEI(const libmei::StaffDef& meiStaffDef, bool& warning)
1043 : {
1044 0 : libmei::Clef meiClef;
1045 0 : meiClef.SetLine(meiStaffDef.GetClefLine());
1046 0 : meiClef.SetShape(meiStaffDef.GetClefShape());
1047 0 : meiClef.SetDis(meiStaffDef.GetClefDis());
1048 0 : meiClef.SetDisPlace(meiStaffDef.GetClefDisPlace());
1049 0 : return Convert::clefFromMEI(meiClef, warning);
1050 0 : }
1051 :
1052 4581 : void Convert::colorFromMEI(engraving::EngravingItem* item, const libmei::Element& meiElement)
1053 : {
1054 4581 : const libmei::AttColor* colorAtt = dynamic_cast<const libmei::AttColor*>(&meiElement);
1055 :
1056 4581 : IF_ASSERT_FAILED(colorAtt) {
1057 0 : return;
1058 : }
1059 :
1060 : // @color
1061 4581 : if (colorAtt->HasColor()) {
1062 41 : engraving::Color color = engraving::Color::fromString(colorAtt->GetColor());
1063 41 : if (color.isValid()) {
1064 41 : item->setColor(color);
1065 41 : item->setPropertyFlags(engraving::Pid::COLOR, engraving::PropertyFlags::UNSTYLED);
1066 : }
1067 : }
1068 : }
1069 :
1070 3077 : void Convert::colorToMEI(const engraving::EngravingItem* item, libmei::Element& meiElement)
1071 : {
1072 3077 : libmei::AttColor* colorAtt = dynamic_cast<libmei::AttColor*>(&meiElement);
1073 :
1074 3077 : IF_ASSERT_FAILED(colorAtt) {
1075 0 : return;
1076 : }
1077 :
1078 : // @color
1079 3077 : if (item->color() != engravingConfiguration()->defaultColor()) {
1080 35 : colorAtt->SetColor(item->color().toString());
1081 : }
1082 : }
1083 :
1084 44 : void Convert::colorlineFromMEI(engraving::SLine* line, const libmei::Element& meiElement)
1085 : {
1086 44 : const libmei::AttColor* colorAtt = dynamic_cast<const libmei::AttColor*>(&meiElement);
1087 :
1088 44 : IF_ASSERT_FAILED(colorAtt) {
1089 0 : return;
1090 : }
1091 :
1092 : // @color
1093 44 : if (colorAtt->HasColor()) {
1094 8 : engraving::Color color = engraving::Color::fromString(colorAtt->GetColor());
1095 8 : if (color.isValid()) {
1096 8 : line->setLineColor(color);
1097 8 : line->setPropertyFlags(engraving::Pid::COLOR, engraving::PropertyFlags::UNSTYLED);
1098 : }
1099 : }
1100 : }
1101 :
1102 44 : void Convert::colorlineToMEI(const engraving::SLine* line, libmei::Element& meiElement)
1103 : {
1104 44 : libmei::AttColor* colorAtt = dynamic_cast<libmei::AttColor*>(&meiElement);
1105 :
1106 44 : IF_ASSERT_FAILED(colorAtt) {
1107 0 : return;
1108 : }
1109 :
1110 : // @color
1111 44 : if (line->lineColor() != engravingConfiguration()->defaultColor()) {
1112 8 : colorAtt->SetColor(line->lineColor().toString());
1113 : }
1114 : }
1115 :
1116 23 : engraving::DirectionV Convert::curvedirFromMEI(const libmei::curvature_CURVEDIR meiCurvedir, bool& warning)
1117 : {
1118 23 : warning = false;
1119 23 : switch (meiCurvedir) {
1120 12 : case (libmei::curvature_CURVEDIR_above): return engraving::DirectionV::UP;
1121 11 : case (libmei::curvature_CURVEDIR_below): return engraving::DirectionV::DOWN;
1122 0 : default:
1123 0 : return engraving::DirectionV::AUTO;
1124 : }
1125 : }
1126 :
1127 23 : libmei::curvature_CURVEDIR Convert::curvedirToMEI(engraving::DirectionV curvedir)
1128 : {
1129 23 : switch (curvedir) {
1130 12 : case (engraving::DirectionV::UP): return libmei::curvature_CURVEDIR_above;
1131 11 : case (engraving::DirectionV::DOWN): return libmei::curvature_CURVEDIR_below;
1132 0 : default:
1133 0 : return libmei::curvature_CURVEDIR_NONE;
1134 : }
1135 : }
1136 :
1137 5 : void Convert::dirFromMEI(engraving::TextBase* textBase, const StringList& meiLines, const libmei::Dir& meiDir, bool& warning)
1138 : {
1139 5 : IF_ASSERT_FAILED(textBase) {
1140 0 : return;
1141 : }
1142 :
1143 5 : warning = false;
1144 :
1145 : // @place
1146 5 : if (meiDir.HasPlace()) {
1147 1 : textBase->setPlacement(meiDir.GetPlace()
1148 1 : == libmei::STAFFREL_above ? engraving::PlacementV::ABOVE : engraving::PlacementV::BELOW);
1149 1 : textBase->setPropertyFlags(engraving::Pid::PLACEMENT, engraving::PropertyFlags::UNSTYLED);
1150 : }
1151 :
1152 : // @type
1153 : // already process in Convert::elementTypeFor called for determining the factory to call in MeiImporter
1154 :
1155 : // @color
1156 5 : Convert::colorFromMEI(textBase, meiDir);
1157 :
1158 : // text
1159 5 : textBase->setXmlText(meiLines.join(u"\n"));
1160 : }
1161 :
1162 3 : void Convert::dirFromMEI(engraving::TextLineBase* textLineBase, const StringList& meiLines, const libmei::Dir& meiDir, bool& warning)
1163 : {
1164 3 : IF_ASSERT_FAILED(textLineBase) {
1165 0 : return;
1166 : }
1167 :
1168 3 : warning = false;
1169 :
1170 : // @place
1171 3 : if (meiDir.HasPlace()) {
1172 0 : textLineBase->setPlacement(meiDir.GetPlace()
1173 0 : == libmei::STAFFREL_above ? engraving::PlacementV::ABOVE : engraving::PlacementV::BELOW);
1174 0 : textLineBase->setPropertyFlags(engraving::Pid::PLACEMENT, engraving::PropertyFlags::UNSTYLED);
1175 : }
1176 :
1177 : // @type
1178 3 : if (textLineBase->isHairpin()) {
1179 3 : engraving::Hairpin* hairpin = engraving::toHairpin(textLineBase);
1180 3 : engraving::HairpinType hairpinType = engraving::HairpinType::DIM_LINE;
1181 6 : if (Convert::hasTypeValue(meiDir.GetType(), std::string(DIR_TYPE) + "cresc")) {
1182 1 : hairpinType = engraving::HairpinType::CRESC_LINE;
1183 : }
1184 3 : hairpin->setHairpinType(hairpinType);
1185 : }
1186 :
1187 : // @lform
1188 3 : if (meiDir.HasLform()) {
1189 1 : bool lformWarning = false;
1190 1 : textLineBase->setLineStyle(Convert::lineFromMEI(meiDir.GetLform(), lformWarning));
1191 1 : textLineBase->setPropertyFlags(engraving::Pid::LINE_STYLE, engraving::PropertyFlags::UNSTYLED);
1192 1 : warning = (warning || lformWarning);
1193 : }
1194 :
1195 : // @color
1196 3 : Convert::colorlineFromMEI(textLineBase, meiDir);
1197 :
1198 : // text
1199 3 : textLineBase->setBeginText(meiLines.join(u"\n"));
1200 3 : textLineBase->setPropertyFlags(engraving::Pid::BEGIN_TEXT, engraving::PropertyFlags::UNSTYLED);
1201 : }
1202 :
1203 5 : libmei::Dir Convert::dirToMEI(const engraving::TextBase* textBase, StringList& meiLines)
1204 : {
1205 5 : libmei::Dir meiDir;
1206 :
1207 : // @place
1208 5 : if (textBase->propertyFlags(engraving::Pid::PLACEMENT) == engraving::PropertyFlags::UNSTYLED) {
1209 1 : meiDir.SetPlace(Convert::placeToMEI(textBase->placement()));
1210 : }
1211 :
1212 : // @type
1213 5 : if (textBase->type() != engraving::ElementType::EXPRESSION) {
1214 4 : std::string dirType = DIR_TYPE;
1215 4 : switch (textBase->type()) {
1216 2 : case (engraving::ElementType::PLAYTECH_ANNOTATION):
1217 2 : dirType = std::string(DIR_TYPE) + "playtech-annotation";
1218 2 : break;
1219 1 : case (engraving::ElementType::STAFF_TEXT):
1220 1 : dirType = std::string(DIR_TYPE) + "staff-text";
1221 1 : break;
1222 1 : case (engraving::ElementType::SYSTEM_TEXT):
1223 1 : dirType = std::string(DIR_TYPE) + "system-text";
1224 1 : break;
1225 0 : default: break;
1226 : }
1227 4 : meiDir.SetType(dirType);
1228 4 : }
1229 :
1230 : // @color
1231 5 : Convert::colorToMEI(textBase, meiDir);
1232 :
1233 : // text content - only split lines
1234 5 : meiLines = String(textBase->plainText()).split(u"\n");
1235 :
1236 5 : return meiDir;
1237 0 : }
1238 :
1239 3 : libmei::Dir Convert::dirToMEI(const engraving::TextLineBase* textLineBase, StringList& meiLines)
1240 : {
1241 3 : libmei::Dir meiDir;
1242 :
1243 : // @place
1244 3 : if (textLineBase->propertyFlags(engraving::Pid::PLACEMENT) == engraving::PropertyFlags::UNSTYLED) {
1245 0 : meiDir.SetPlace(Convert::placeToMEI(textLineBase->placement()));
1246 : }
1247 :
1248 : // @type
1249 3 : std::string dirType;
1250 3 : if (textLineBase->isHairpin()) {
1251 : // Two type values: one for hairpin, one for the hairpin type
1252 9 : dirType = std::string(DIR_TYPE) + "hairpin " + std::string(DIR_TYPE);
1253 3 : const engraving::Hairpin* hairpin = engraving::toHairpin(textLineBase);
1254 3 : if (hairpin->hairpinType() == engraving::HairpinType::CRESC_LINE) {
1255 1 : dirType += "cresc";
1256 : } else {
1257 2 : dirType += "dim";
1258 : }
1259 : }
1260 3 : meiDir.SetType(dirType);
1261 :
1262 : // @extender
1263 3 : meiDir.SetExtender(libmei::BOOLEAN_true);
1264 :
1265 : // @lform
1266 3 : if (textLineBase->propertyFlags(engraving::Pid::LINE_STYLE) == engraving::PropertyFlags::UNSTYLED) {
1267 1 : meiDir.SetLform(Convert::lineToMEI(textLineBase->lineStyle()));
1268 : }
1269 :
1270 : // @color
1271 3 : Convert::colorlineToMEI(textLineBase, meiDir);
1272 :
1273 : // text content - only split lines
1274 3 : meiLines = String(textLineBase->beginText()).split(u"\n");
1275 :
1276 3 : return meiDir;
1277 3 : }
1278 :
1279 10 : void Convert::dynamFromMEI(engraving::Dynamic* dynamic, const StringList& meiLines, const libmei::Dynam& meiDynam, bool& warning)
1280 : {
1281 : // The letters in the MEI to be mapped to SMuFL symbols in the xmlText
1282 : static const std::map<Char, engraving::SymId> DYN_MAP = {
1283 : { 'p', engraving::SymId::dynamicPiano },
1284 : { 'm', engraving::SymId::dynamicMezzo },
1285 : { 'f', engraving::SymId::dynamicForte },
1286 : { 'r', engraving::SymId::dynamicRinforzando },
1287 : { 's', engraving::SymId::dynamicSforzando },
1288 : { 'z', engraving::SymId::dynamicZ },
1289 : { 'n', engraving::SymId::dynamicNiente },
1290 12 : };
1291 :
1292 10 : IF_ASSERT_FAILED(dynamic) {
1293 0 : return;
1294 : }
1295 :
1296 10 : warning = false;
1297 :
1298 : // @place
1299 10 : dynamic->setProperty(engraving::Pid::DIRECTION, Convert::directionFromMEI(meiDynam.GetPlace()));
1300 :
1301 : // @label
1302 10 : if (meiDynam.HasLabel()) {
1303 10 : dynamic->setDynamicType(String::fromStdString(meiDynam.GetLabel()));
1304 : }
1305 : // If no @label, try to use the text
1306 0 : else if (meiLines.size() > 0 && !meiLines.at(0).contains(' ')) {
1307 0 : dynamic->setDynamicType(meiLines.at(0));
1308 : }
1309 :
1310 : // @layer
1311 10 : Convert::layerIdentFromMEI(dynamic, meiDynam);
1312 :
1313 : // text content
1314 10 : StringList lines;
1315 : // For each line in the dynamic text
1316 22 : for (const String& meiline : meiLines) {
1317 12 : String line;
1318 12 : StringList words = meiline.split(u" ");
1319 12 : bool isFirst = true;
1320 : // For each word in the line
1321 30 : for (const String& word : words) {
1322 18 : if (!isFirst) {
1323 6 : line += u" ";
1324 : }
1325 : // If the word is only dynamic letters, convert them to SMuFL symbols one by one
1326 18 : if (word.toStdString().find_first_not_of("fpmrszn") == std::string::npos) {
1327 30 : for (size_t i = 0; i < word.size(); i++) {
1328 19 : line += u"<sym>" + String::fromAscii(engraving::SymNames::nameForSymId(DYN_MAP.at(word.at(i))).ascii()) + u"</sym>";
1329 : }
1330 : }
1331 : // Otherwise keep it as is
1332 : else {
1333 7 : line += word;
1334 : }
1335 18 : isFirst = false;
1336 : }
1337 12 : lines.push_back(line);
1338 12 : }
1339 10 : dynamic->setXmlText(lines.join(u"\n"));
1340 :
1341 : // @color
1342 10 : Convert::colorFromMEI(dynamic, meiDynam);
1343 10 : }
1344 :
1345 10 : libmei::Dynam Convert::dynamToMEI(const engraving::Dynamic* dynamic, StringList& meiLines)
1346 : {
1347 : // The SMuFL unicode points in the plainText to be mapped to letters in the MEI
1348 : static const std::map<char16_t, Char> DYN_MAP = {
1349 : { u'\uE520', 'p' },
1350 : { u'\uE521', 'm' },
1351 : { u'\uE522', 'f' },
1352 : { u'\uE523', 'z' },
1353 : { u'\uE524', 's' },
1354 : { u'\uE525', 'z' },
1355 : { u'\uE526', 'n' }
1356 12 : };
1357 :
1358 10 : libmei::Dynam meiDynam;
1359 :
1360 : // @place
1361 10 : meiDynam.SetPlace(Convert::directionToMEI(dynamic->direction()));
1362 :
1363 : // @layer
1364 10 : Convert::layerIdentToMEI(dynamic, meiDynam);
1365 :
1366 : // @staff
1367 10 : Convert::staffIdentToMEI(dynamic, meiDynam);
1368 :
1369 : // @label
1370 10 : if (dynamic->dynamicType() != engraving::DynamicType::OTHER) {
1371 20 : meiDynam.SetLabel(engraving::TConv::toXml(dynamic->dynamicType()).ascii());
1372 : }
1373 :
1374 : // text content
1375 10 : String meiText;
1376 10 : String plainText = dynamic->plainText();
1377 66 : for (size_t i = 0; i < plainText.size(); i++) {
1378 56 : char16_t c = plainText.at(i).unicode();
1379 56 : if (c < u'\uE000' || c > u'\uF8FF' || !DYN_MAP.count(c)) {
1380 37 : meiText += c;
1381 37 : continue;
1382 : }
1383 19 : meiText += DYN_MAP.at(c);
1384 :
1385 : /*
1386 : char16_t c = plainText.at(i).unicode();
1387 : if (c < u'\uE000' || c > u'\uF8FF') {
1388 : meiText += c;
1389 : continue;
1390 : }
1391 : SymId symId = m_score->engravingFont()->fromCode(c);
1392 : if (symId == SymId::noSym) continue;
1393 : String letter = u"<sym>" + String::fromAscii(SymNames::nameForSymId(symId).ascii()) + u"</sym>";
1394 : for (auto dyn : Dynamic::dynamicList()) {
1395 : if ((dyn.text == letter) && (dyn.type != DynamicType::OTHER)) {
1396 : meiText += String::fromAscii(TConv::toXml(dyn.type).ascii());
1397 : break;
1398 : }
1399 : }
1400 : */
1401 : }
1402 10 : meiLines = String(meiText).split(u"\n");
1403 :
1404 : // @color
1405 10 : Convert::colorToMEI(dynamic, meiDynam);
1406 :
1407 10 : return meiDynam;
1408 10 : }
1409 :
1410 4 : void Convert::endingFromMEI(engraving::Volta* volta, const libmei::Ending& meiEnding, bool& warning)
1411 : {
1412 4 : IF_ASSERT_FAILED(volta) {
1413 0 : return;
1414 : }
1415 :
1416 4 : warning = false;
1417 : // @type used for storing endings
1418 4 : std::list<std::string> endings = Convert::getTypeValuesWithPrefix(meiEnding.GetType(), ENDING_REPEAT_TYPE);
1419 12 : for (std::string ending : endings) {
1420 8 : volta->endings().push_back(String(ending.c_str()).toInt());
1421 8 : }
1422 :
1423 : // @label
1424 4 : if (meiEnding.HasLabel()) {
1425 4 : volta->setText(String(meiEnding.GetLabel().c_str()));
1426 : }
1427 :
1428 : // @lform
1429 4 : if (meiEnding.HasLform() && meiEnding.GetLform() != libmei::LINEFORM_solid) {
1430 : bool lineWarning;
1431 2 : engraving::LineType lineType = Convert::lineFromMEI(meiEnding.GetLform(), lineWarning);
1432 2 : if (!lineWarning) {
1433 2 : volta->setLineStyle(lineType);
1434 2 : volta->setPropertyFlags(engraving::Pid::LINE_STYLE, engraving::PropertyFlags::UNSTYLED);
1435 : }
1436 2 : warning = (warning || lineWarning);
1437 : }
1438 :
1439 : // @lendsym
1440 4 : if (meiEnding.HasLendsym() && (meiEnding.GetLendsym() == libmei::LINESTARTENDSYMBOL_none)) {
1441 1 : volta->setVoltaType(engraving::Volta::Type::OPEN);
1442 1 : volta->setPropertyFlags(engraving::Pid::VOLTA_ENDING, engraving::PropertyFlags::UNSTYLED);
1443 : } else {
1444 3 : volta->setVoltaType(engraving::Volta::Type::CLOSED);
1445 : }
1446 4 : }
1447 :
1448 4 : libmei::Ending Convert::endingToMEI(const engraving::Volta* volta)
1449 : {
1450 4 : libmei::Ending meiEnding;
1451 :
1452 : // @type used for storing endings
1453 4 : StringList endings;
1454 12 : for (int ending : volta->endings()) {
1455 8 : endings << String("%1%2").arg(String(ENDING_REPEAT_TYPE)).arg(ending);
1456 4 : }
1457 4 : meiEnding.SetType(endings.join(u" ").toStdString());
1458 :
1459 : // @label used for text
1460 4 : meiEnding.SetLabel(volta->text().toStdString());
1461 :
1462 : // @lform
1463 4 : if (volta->lineStyle() != engraving::LineType::SOLID) {
1464 2 : meiEnding.SetLform(Convert::lineToMEI(volta->lineStyle()));
1465 : }
1466 :
1467 : // @lendsym
1468 4 : if (volta->voltaType() == engraving::Volta::Type::OPEN) {
1469 1 : meiEnding.SetLendsym(libmei::LINESTARTENDSYMBOL_none);
1470 : }
1471 :
1472 4 : return meiEnding;
1473 4 : }
1474 :
1475 8 : void Convert::fFromMEI(engraving::FiguredBassItem* figuredBassItem, const StringList& meiLines, const libmei::F& meiF, bool& warning)
1476 : {
1477 8 : warning = false;
1478 :
1479 : // content
1480 8 : String text = meiLines.join(u"\n");
1481 8 : figuredBassItem->parse(text);
1482 :
1483 : UNUSED(meiF);
1484 8 : }
1485 :
1486 8 : libmei::F Convert::fToMEI(const engraving::FiguredBassItem* figuredBassItem, StringList& meiLines)
1487 : {
1488 8 : libmei::F meiF;
1489 :
1490 : // content - to be improved
1491 8 : String plainText = figuredBassItem->normalizedText();
1492 8 : meiLines = plainText.split(u"\n");
1493 :
1494 8 : return meiF;
1495 8 : }
1496 :
1497 7 : void Convert::fbFromMEI(engraving::FiguredBass* figuredBass, const libmei::Harm& meiHarm, const libmei::Fb& meiFb, bool& warning)
1498 : {
1499 7 : warning = false;
1500 :
1501 : UNUSED(meiFb);
1502 :
1503 : // @color
1504 7 : Convert::colorFromMEI(figuredBass, meiHarm);
1505 7 : }
1506 :
1507 7 : std::pair<libmei::Harm, libmei::Fb> Convert::fbToMEI(const engraving::FiguredBass* figuredBass)
1508 : {
1509 7 : libmei::Harm meiHarm;
1510 7 : libmei::Fb meiFb;
1511 :
1512 : // @staff
1513 7 : Convert::staffIdentToMEI(figuredBass, meiHarm);
1514 :
1515 : // @color
1516 7 : Convert::colorToMEI(figuredBass, meiHarm);
1517 :
1518 14 : return { meiHarm, meiFb };
1519 7 : }
1520 :
1521 38 : void Convert::fermataFromMEI(engraving::Fermata* fermata, const libmei::Fermata& meiFermata, bool& warning)
1522 : {
1523 38 : warning = false;
1524 :
1525 : // @place
1526 38 : bool below = (meiFermata.HasPlace() && (meiFermata.GetPlace() == libmei::STAFFREL_below));
1527 :
1528 : // @glyph.name
1529 38 : bool smufl = (meiFermata.HasGlyphAuth() && (meiFermata.GetGlyphAuth() == SMUFL_AUTH));
1530 :
1531 38 : engraving::SymId symId = engraving::SymId::fermataAbove;
1532 :
1533 38 : if (smufl && meiFermata.HasGlyphName()) {
1534 4 : symId = engraving::SymNames::symIdByName(String(meiFermata.GetGlyphName().c_str()));
1535 4 : if (symId == engraving::SymId::noSym) {
1536 0 : warning = true;
1537 : }
1538 34 : } else if (meiFermata.HasShape()) {
1539 5 : if (meiFermata.GetShape() == libmei::fermataVis_SHAPE_square) {
1540 2 : symId = (below) ? engraving::SymId::fermataLongBelow : engraving::SymId::fermataLongAbove;
1541 3 : } else if (meiFermata.GetShape() == libmei::fermataVis_SHAPE_angular) {
1542 3 : symId = (below) ? engraving::SymId::fermataShortBelow : engraving::SymId::fermataShortAbove;
1543 0 : } else if (meiFermata.GetShape() == libmei::fermataVis_SHAPE_curved) {
1544 0 : symId = (below) ? engraving::SymId::fermataBelow : engraving::SymId::fermataAbove;
1545 : }
1546 : }
1547 : // This is for loading MEI files not written by MuseScore and that use @glyph.num instead of @glyph.name
1548 29 : else if (smufl && meiFermata.HasGlyphNum()) {
1549 0 : symId = engravingFonts()->fallbackFont()->fromCode(meiFermata.GetGlyphNum());
1550 0 : if (symId == engraving::SymId::noSym) {
1551 0 : warning = true;
1552 : }
1553 29 : } else if (below) {
1554 4 : symId = engraving::SymId::fermataBelow;
1555 : }
1556 :
1557 38 : fermata->setSymId(symId);
1558 38 : if (below) {
1559 5 : fermata->setPlacement(engraving::PlacementV::BELOW);
1560 : }
1561 :
1562 : // @color
1563 38 : Convert::colorFromMEI(fermata, meiFermata);
1564 38 : }
1565 :
1566 38 : libmei::Fermata Convert::fermataToMEI(const engraving::Fermata* fermata)
1567 : {
1568 38 : libmei::Fermata meiFermata;
1569 :
1570 38 : bool below = false;
1571 38 : bool smufl = false;
1572 : // @shape and @glyph.name
1573 38 : switch (fermata->symId()) {
1574 25 : case (engraving::SymId::fermataAbove): break;
1575 4 : case (engraving::SymId::fermataBelow): below = true;
1576 4 : break;
1577 2 : case (engraving::SymId::fermataLongAbove): meiFermata.SetShape(libmei::fermataVis_SHAPE_square);
1578 2 : break;
1579 0 : case (engraving::SymId::fermataLongBelow): meiFermata.SetShape(libmei::fermataVis_SHAPE_square);
1580 0 : below = true;
1581 0 : break;
1582 2 : case (engraving::SymId::fermataShortAbove): meiFermata.SetShape(libmei::fermataVis_SHAPE_angular);
1583 2 : break;
1584 1 : case (engraving::SymId::fermataShortBelow): meiFermata.SetShape(libmei::fermataVis_SHAPE_angular);
1585 1 : below = true;
1586 1 : break;
1587 4 : case (engraving::SymId::fermataLongHenzeAbove):
1588 : case (engraving::SymId::fermataVeryLongAbove):
1589 : case (engraving::SymId::fermataShortHenzeAbove):
1590 4 : case (engraving::SymId::fermataVeryShortAbove): smufl = true;
1591 4 : break;
1592 0 : case (engraving::SymId::fermataLongHenzeBelow):
1593 : case (engraving::SymId::fermataVeryLongBelow):
1594 : case (engraving::SymId::fermataShortHenzeBelow):
1595 0 : case (engraving::SymId::fermataVeryShortBelow): smufl = true;
1596 0 : below = true;
1597 0 : break;
1598 0 : default:
1599 0 : break;
1600 : }
1601 : // @place
1602 38 : if (below) {
1603 5 : meiFermata.SetPlace(libmei::STAFFREL_below);
1604 : }
1605 : // @glyph.name
1606 38 : if (smufl) {
1607 4 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(fermata->symId());
1608 8 : meiFermata.SetGlyphName(glyphName.ascii());
1609 12 : meiFermata.SetGlyphAuth(SMUFL_AUTH);
1610 : }
1611 :
1612 : // @color
1613 38 : Convert::colorToMEI(fermata, meiFermata);
1614 :
1615 38 : return meiFermata;
1616 0 : }
1617 :
1618 50 : void Convert::fingFromMEI(engraving::Fingering* fing, const StringList& meiLines, const libmei::Fing& meiFing, bool& warning)
1619 : {
1620 50 : IF_ASSERT_FAILED(fing) {
1621 0 : return;
1622 : }
1623 :
1624 50 : warning = false;
1625 :
1626 : // text content
1627 50 : fing->setPlainText(meiLines.join(u"\n"));
1628 :
1629 : // @place
1630 50 : if (meiFing.HasPlace()) {
1631 0 : fing->setPlacement(meiFing.GetPlace() == libmei::STAFFREL_above ? engraving::PlacementV::ABOVE : engraving::PlacementV::BELOW);
1632 0 : fing->setPropertyFlags(engraving::Pid::PLACEMENT, engraving::PropertyFlags::UNSTYLED);
1633 : }
1634 :
1635 : // @color
1636 50 : Convert::colorFromMEI(fing, meiFing);
1637 : }
1638 :
1639 50 : libmei::Fing Convert::fingToMEI(const engraving::Fingering* fing, StringList& meiLines)
1640 : {
1641 50 : libmei::Fing meiFing;
1642 :
1643 : // content
1644 50 : String plainText = fing->plainText();
1645 50 : meiLines = plainText.split(u"\n");
1646 :
1647 : // @place
1648 50 : if (fing->propertyFlags(engraving::Pid::PLACEMENT) == engraving::PropertyFlags::UNSTYLED) {
1649 0 : meiFing.SetPlace(Convert::placeToMEI(fing->placement()));
1650 : }
1651 :
1652 : // @color
1653 50 : Convert::colorToMEI(fing, meiFing);
1654 :
1655 50 : return meiFing;
1656 50 : }
1657 :
1658 19 : void Convert::glissFromMEI(engraving::Glissando* gliss, const libmei::Gliss& meiGliss, bool& warning)
1659 : {
1660 19 : warning = false;
1661 :
1662 : // @lform
1663 : bool lineWarning;
1664 19 : switch (meiGliss.GetLform()) {
1665 15 : case libmei::LINEFORM_dotted:
1666 : case libmei::LINEFORM_dashed:
1667 : case libmei::LINEFORM_solid:
1668 15 : gliss->setGlissandoType(engraving::GlissandoType::STRAIGHT);
1669 15 : gliss->setLineStyle(Convert::lineFromMEI(meiGliss.GetLform(), lineWarning));
1670 15 : break;
1671 4 : case libmei::LINEFORM_wavy:
1672 : default:
1673 4 : gliss->setGlissandoType(engraving::GlissandoType::WAVY);
1674 4 : break;
1675 : }
1676 :
1677 : // @color
1678 19 : Convert::colorlineFromMEI(gliss, meiGliss);
1679 19 : }
1680 :
1681 19 : libmei::Gliss Convert::glissToMEI(const engraving::Glissando* gliss)
1682 : {
1683 19 : libmei::Gliss meiGliss;
1684 :
1685 : // @lform
1686 19 : switch (gliss->glissandoType()) {
1687 15 : case engraving::GlissandoType::STRAIGHT:
1688 15 : meiGliss.SetLform(Convert::lineToMEI(gliss->lineStyle()));
1689 15 : break;
1690 4 : case engraving::GlissandoType::WAVY:
1691 4 : meiGliss.SetLform(libmei::LINEFORM_wavy);
1692 4 : break;
1693 0 : default:
1694 0 : meiGliss.SetLform(libmei::LINEFORM_NONE);
1695 0 : break;
1696 : }
1697 :
1698 : // @color
1699 19 : Convert::colorlineToMEI(gliss, meiGliss);
1700 :
1701 19 : return meiGliss;
1702 0 : }
1703 :
1704 25 : std::pair<bool, engraving::NoteType> Convert::gracegrpFromMEI(const libmei::graceGrpLog_ATTACH meiAttach, const libmei::data_GRACE meiGrace,
1705 : bool& warning)
1706 : {
1707 25 : warning = false;
1708 25 : bool isAfter = (meiAttach == libmei::graceGrpLog_ATTACH_pre);
1709 25 : engraving::NoteType noteType = engraving::NoteType::APPOGGIATURA;
1710 :
1711 25 : if (isAfter) {
1712 1 : noteType = engraving::NoteType::GRACE8_AFTER;
1713 24 : } else if (meiGrace == libmei::GRACE_unacc) {
1714 5 : noteType = engraving::NoteType::ACCIACCATURA;
1715 : }
1716 :
1717 25 : return { isAfter, noteType };
1718 : }
1719 :
1720 25 : std::pair<libmei::graceGrpLog_ATTACH, libmei::data_GRACE> Convert::gracegrpToMEI(bool isAfter, engraving::NoteType noteType)
1721 : {
1722 25 : libmei::graceGrpLog_ATTACH meiAttach = (isAfter) ? libmei::graceGrpLog_ATTACH_pre : libmei::graceGrpLog_ATTACH_NONE;
1723 25 : libmei::data_GRACE meiGrace = libmei::GRACE_acc;
1724 :
1725 25 : if (isAfter) {
1726 1 : meiGrace = libmei::GRACE_unknown;
1727 24 : } else if (noteType == engraving::NoteType::ACCIACCATURA) {
1728 5 : meiGrace = libmei::GRACE_unacc;
1729 : }
1730 :
1731 25 : return { meiAttach, meiGrace };
1732 : }
1733 :
1734 6 : void Convert::hairpinFromMEI(engraving::Hairpin* hairpin, const libmei::Hairpin& meiHairpin, bool& warning)
1735 : {
1736 6 : warning = false;
1737 :
1738 : // @place
1739 6 : hairpin->setProperty(engraving::Pid::DIRECTION, Convert::directionFromMEI(meiHairpin.GetPlace()));
1740 :
1741 : // @form
1742 6 : if (meiHairpin.GetForm() == libmei::hairpinLog_FORM_cres) {
1743 4 : hairpin->setHairpinType(engraving::HairpinType::CRESC_HAIRPIN);
1744 : } else {
1745 2 : hairpin->setHairpinType(engraving::HairpinType::DIM_HAIRPIN);
1746 : }
1747 :
1748 : // @lform
1749 6 : if (meiHairpin.HasLform()) {
1750 2 : bool lformWarning = false;
1751 2 : hairpin->setLineStyle(Convert::lineFromMEI(meiHairpin.GetLform(), lformWarning));
1752 2 : hairpin->setPropertyFlags(engraving::Pid::LINE_STYLE, engraving::PropertyFlags::UNSTYLED);
1753 2 : warning = (warning || lformWarning);
1754 : }
1755 :
1756 : // @niente
1757 6 : if (meiHairpin.HasNiente()) {
1758 1 : hairpin->setHairpinCircledTip(meiHairpin.GetNiente() == libmei::BOOLEAN_true);
1759 : }
1760 :
1761 : // @color
1762 6 : Convert::colorlineFromMEI(hairpin, meiHairpin);
1763 :
1764 : // @layer
1765 6 : Convert::layerIdentFromMEI(hairpin, meiHairpin);
1766 6 : }
1767 :
1768 6 : libmei::Hairpin Convert::hairpinToMEI(const engraving::Hairpin* hairpin)
1769 : {
1770 6 : libmei::Hairpin meiHairpin;
1771 :
1772 : // @place
1773 6 : meiHairpin.SetPlace(Convert::directionToMEI(hairpin->direction()));
1774 :
1775 : // @form
1776 6 : if (hairpin->hairpinType() == engraving::HairpinType::CRESC_HAIRPIN) {
1777 4 : meiHairpin.SetForm(libmei::hairpinLog_FORM_cres);
1778 : } else {
1779 2 : meiHairpin.SetForm(libmei::hairpinLog_FORM_dim);
1780 : }
1781 :
1782 : // @lform
1783 6 : if (hairpin->lineStyle() != engraving::LineType::SOLID) {
1784 2 : meiHairpin.SetLform(Convert::lineToMEI(hairpin->lineStyle()));
1785 : }
1786 :
1787 : // @niente
1788 6 : if (hairpin->hairpinCircledTip()) {
1789 1 : meiHairpin.SetNiente(libmei::BOOLEAN_true);
1790 : }
1791 :
1792 : // @color
1793 6 : Convert::colorlineToMEI(hairpin, meiHairpin);
1794 :
1795 : // @layer
1796 6 : Convert::layerIdentToMEI(hairpin, meiHairpin);
1797 :
1798 : // @staff
1799 6 : Convert::staffIdentToMEI(hairpin, meiHairpin);
1800 :
1801 6 : return meiHairpin;
1802 0 : }
1803 :
1804 26 : void Convert::harmFromMEI(engraving::Harmony* harmony, const StringList& meiLines, const libmei::Harm& meiHarm, bool& warning)
1805 : {
1806 26 : IF_ASSERT_FAILED(harmony) {
1807 0 : return;
1808 : }
1809 :
1810 26 : warning = false;
1811 :
1812 : // @type
1813 26 : engraving::HarmonyType harmonyType = engraving::HarmonyType::STANDARD;
1814 52 : if (Convert::hasTypeValue(meiHarm.GetType(), std::string(HARMONY_TYPE) + "roman")) {
1815 15 : harmonyType = engraving::HarmonyType::ROMAN;
1816 : }
1817 :
1818 : // text content
1819 26 : harmony->setHarmonyType(harmonyType);
1820 26 : harmony->setHarmony(meiLines.join(u"\n"));
1821 26 : harmony->setPlainText(harmony->harmonyName());
1822 :
1823 : // @place
1824 26 : if (meiHarm.HasPlace()) {
1825 2 : harmony->setPlacement(meiHarm.GetPlace() == libmei::STAFFREL_above ? engraving::PlacementV::ABOVE : engraving::PlacementV::BELOW);
1826 2 : harmony->setPropertyFlags(engraving::Pid::PLACEMENT, engraving::PropertyFlags::UNSTYLED);
1827 : }
1828 :
1829 : // @color
1830 26 : Convert::colorFromMEI(harmony, meiHarm);
1831 : }
1832 :
1833 26 : libmei::Harm Convert::harmToMEI(const engraving::Harmony* harmony, StringList& meiLines)
1834 : {
1835 26 : libmei::Harm meiHarm;
1836 :
1837 : // @type
1838 26 : if (harmony->harmonyType() != engraving::HarmonyType::STANDARD) {
1839 15 : std::string harmonyType = HARMONY_TYPE;
1840 :
1841 15 : switch (harmony->harmonyType()) {
1842 15 : case (engraving::HarmonyType::ROMAN):
1843 15 : harmonyType = std::string(HARMONY_TYPE) + "roman";
1844 15 : break;
1845 0 : default: break;
1846 : }
1847 15 : meiHarm.SetType(harmonyType);
1848 15 : }
1849 :
1850 : // content
1851 26 : String plainText = harmony->plainText();
1852 26 : meiLines = plainText.split(u"\n");
1853 :
1854 : // @place
1855 26 : if (harmony->propertyFlags(engraving::Pid::PLACEMENT) == engraving::PropertyFlags::UNSTYLED) {
1856 2 : meiHarm.SetPlace(Convert::placeToMEI(harmony->placement()));
1857 : }
1858 :
1859 : // @staff
1860 26 : Convert::staffIdentToMEI(harmony, meiHarm);
1861 :
1862 : // @color
1863 26 : Convert::colorToMEI(harmony, meiHarm);
1864 :
1865 52 : return meiHarm;
1866 0 : }
1867 :
1868 3 : void Convert::harpPedalFromMEI(engraving::HarpPedalDiagram* harpPedalDiagram, const libmei::HarpPedal& meiHarpPedal, bool& warning)
1869 : {
1870 3 : IF_ASSERT_FAILED(harpPedalDiagram) {
1871 0 : return;
1872 : }
1873 :
1874 3 : warning = false;
1875 :
1876 3 : harpPedalDiagram->setIsDiagram(true);
1877 :
1878 : // @d
1879 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::D, harpPedalPositionFromMEI(meiHarpPedal.GetD()));
1880 : // @c
1881 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::C, harpPedalPositionFromMEI(meiHarpPedal.GetC()));
1882 : // @b
1883 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::B, harpPedalPositionFromMEI(meiHarpPedal.GetB()));
1884 : // @e
1885 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::E, harpPedalPositionFromMEI(meiHarpPedal.GetE()));
1886 : // @f
1887 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::F, harpPedalPositionFromMEI(meiHarpPedal.GetF()));
1888 : // @g
1889 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::G, harpPedalPositionFromMEI(meiHarpPedal.GetG()));
1890 : // @a
1891 3 : harpPedalDiagram->setPedal(engraving::HarpStringType::A, harpPedalPositionFromMEI(meiHarpPedal.GetA()));
1892 :
1893 : // @place
1894 3 : if (meiHarpPedal.HasPlace()) {
1895 1 : harpPedalDiagram->setPlacement(meiHarpPedal.GetPlace()
1896 1 : == libmei::STAFFREL_above ? engraving::PlacementV::ABOVE : engraving::PlacementV::BELOW);
1897 1 : harpPedalDiagram->setPropertyFlags(engraving::Pid::PLACEMENT, engraving::PropertyFlags::UNSTYLED);
1898 : }
1899 :
1900 : // @color
1901 3 : Convert::colorFromMEI(harpPedalDiagram, meiHarpPedal);
1902 : }
1903 :
1904 3 : libmei::HarpPedal Convert::harpPedalToMEI(const engraving::HarpPedalDiagram* harpPedalDiagram)
1905 : {
1906 3 : libmei::HarpPedal meiHarpPedal;
1907 :
1908 : // @d
1909 3 : meiHarpPedal.SetD(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(0)));
1910 : // @c
1911 3 : meiHarpPedal.SetC(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(1)));
1912 : // @b
1913 3 : meiHarpPedal.SetB(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(2)));
1914 : // @e
1915 3 : meiHarpPedal.SetE(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(3)));
1916 : // @f
1917 3 : meiHarpPedal.SetF(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(4)));
1918 : // @g
1919 3 : meiHarpPedal.SetG(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(5)));
1920 : // @a
1921 3 : meiHarpPedal.SetA(harpPedalPositionToMEI(harpPedalDiagram->getPedalState().at(6)));
1922 :
1923 : // @place
1924 3 : if (harpPedalDiagram->propertyFlags(engraving::Pid::PLACEMENT) == engraving::PropertyFlags::UNSTYLED) {
1925 1 : meiHarpPedal.SetPlace(Convert::placeToMEI(harpPedalDiagram->placement()));
1926 : }
1927 :
1928 : // @color
1929 3 : Convert::colorToMEI(harpPedalDiagram, meiHarpPedal);
1930 :
1931 : // @staff
1932 3 : Convert::staffIdentToMEI(harpPedalDiagram, meiHarpPedal);
1933 :
1934 3 : return meiHarpPedal;
1935 0 : }
1936 :
1937 21 : libmei::data_HARPPEDALPOSITION Convert::harpPedalPositionToMEI(const engraving::PedalPosition& pedalPosition)
1938 : {
1939 21 : switch (pedalPosition) {
1940 4 : case engraving::PedalPosition::FLAT:
1941 4 : return libmei::HARPPEDALPOSITION_f;
1942 12 : case engraving::PedalPosition::NATURAL:
1943 12 : return libmei::HARPPEDALPOSITION_n;
1944 5 : case engraving::PedalPosition::SHARP:
1945 5 : return libmei::HARPPEDALPOSITION_s;
1946 0 : case engraving::PedalPosition::UNSET:
1947 : default:
1948 0 : return libmei::HARPPEDALPOSITION_NONE;
1949 : }
1950 : }
1951 :
1952 21 : engraving::PedalPosition Convert::harpPedalPositionFromMEI(const libmei::data_HARPPEDALPOSITION& pedalPosition)
1953 : {
1954 21 : switch (pedalPosition) {
1955 4 : case libmei::HARPPEDALPOSITION_f:
1956 4 : return engraving::PedalPosition::FLAT;
1957 12 : case libmei::HARPPEDALPOSITION_n:
1958 12 : return engraving::PedalPosition::NATURAL;
1959 5 : case libmei::HARPPEDALPOSITION_s:
1960 5 : return engraving::PedalPosition::SHARP;
1961 0 : default:
1962 0 : return engraving::PedalPosition::UNSET;
1963 : }
1964 : }
1965 :
1966 6 : void Convert::lvFromMEI(engraving::LaissezVib* lv, const libmei::Lv& meiLv, bool& warning)
1967 : {
1968 6 : warning = false;
1969 :
1970 : // @curvedir
1971 6 : if (meiLv.HasCurvedir()) {
1972 2 : lv->setSlurDirection(Convert::curvedirFromMEI(meiLv.GetCurvedir(), warning));
1973 : }
1974 :
1975 : // @lform
1976 6 : if (meiLv.HasLform()) {
1977 2 : bool typeWarning = false;
1978 2 : lv->setStyleType(Convert::slurstyleFromMEI(meiLv.GetLform(), typeWarning));
1979 2 : warning = (warning || typeWarning);
1980 : }
1981 :
1982 : // @color
1983 6 : Convert::colorFromMEI(lv, meiLv);
1984 6 : }
1985 :
1986 14 : void Convert::jumpFromMEI(engraving::Jump* jump, const libmei::RepeatMark& meiRepeatMark, bool& warning)
1987 : {
1988 14 : warning = false;
1989 :
1990 : engraving::JumpType jumpType;
1991 :
1992 : // @func
1993 14 : switch (meiRepeatMark.GetFunc()) {
1994 5 : case (libmei::repeatMarkLog_FUNC_daCapo): jumpType = engraving::JumpType::DC;
1995 5 : break;
1996 9 : case (libmei::repeatMarkLog_FUNC_dalSegno): jumpType = engraving::JumpType::DS;
1997 9 : break;
1998 0 : default:
1999 0 : jumpType = engraving::JumpType::DC;
2000 : }
2001 :
2002 : // @type
2003 14 : if (meiRepeatMark.HasType()) {
2004 12 : std::list<std::string> jumpTypes = Convert::getTypeValuesWithPrefix(meiRepeatMark.GetType(), JUMP_TYPE);
2005 12 : if (jumpTypes.size() > 0) {
2006 12 : std::string value = jumpTypes.front();
2007 12 : auto result = std::find_if(Convert::s_jumpTypes.begin(), Convert::s_jumpTypes.end(),
2008 87 : [value](const auto& entry) { return entry.second == value; });
2009 :
2010 12 : if (result != Convert::s_jumpTypes.end()) {
2011 12 : jumpType = result->first;
2012 : } else {
2013 0 : warning = true;
2014 : }
2015 12 : }
2016 12 : }
2017 :
2018 : // @color
2019 14 : Convert::colorFromMEI(jump, meiRepeatMark);
2020 :
2021 14 : jump->setJumpType(jumpType);
2022 14 : }
2023 :
2024 14 : libmei::RepeatMark Convert::jumpToMEI(const engraving::Jump* jump, String& text)
2025 : {
2026 14 : libmei::RepeatMark meiRepeatMark;
2027 :
2028 : // @func
2029 14 : switch (jump->jumpType()) {
2030 3 : case (engraving::JumpType::DC):
2031 : case (engraving::JumpType::DC_AL_FINE):
2032 3 : case (engraving::JumpType::DC_AL_CODA): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_daCapo);
2033 3 : break;
2034 4 : case (engraving::JumpType::DS_AL_CODA):
2035 : case (engraving::JumpType::DS_AL_FINE):
2036 4 : case (engraving::JumpType::DS): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_dalSegno);
2037 4 : break;
2038 2 : case (engraving::JumpType::DC_AL_DBLCODA): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_daCapo);
2039 2 : break;
2040 5 : case (engraving::JumpType::DS_AL_DBLCODA):
2041 : case (engraving::JumpType::DSS):
2042 : case (engraving::JumpType::DSS_AL_CODA):
2043 : case (engraving::JumpType::DSS_AL_DBLCODA):
2044 5 : case (engraving::JumpType::DSS_AL_FINE): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_dalSegno);
2045 5 : break;
2046 0 : default:
2047 0 : meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_daCapo);
2048 : }
2049 :
2050 : // @type
2051 14 : if (Convert::s_jumpTypes.count(jump->jumpType())) {
2052 12 : meiRepeatMark.SetType(JUMP_TYPE + Convert::s_jumpTypes.at(jump->jumpType()));
2053 : }
2054 :
2055 14 : switch (jump->jumpType()) {
2056 : // No text for the default symbols
2057 2 : case (engraving::JumpType::DC):
2058 : case (engraving::JumpType::DS):
2059 2 : break;
2060 12 : default:
2061 12 : text = jump->plainText();
2062 : }
2063 :
2064 : // @color
2065 14 : Convert::colorToMEI(jump, meiRepeatMark);
2066 :
2067 14 : return meiRepeatMark;
2068 0 : }
2069 :
2070 21 : engraving::Key Convert::keyFromMEI(const libmei::data_KEYSIGNATURE& meiKeysig, bool& warning)
2071 : {
2072 21 : warning = false;
2073 21 : if (meiKeysig.second == libmei::ACCIDENTAL_WRITTEN_s) {
2074 16 : return engraving::Key(meiKeysig.first);
2075 5 : } else if (meiKeysig.second == libmei::ACCIDENTAL_WRITTEN_f) {
2076 3 : return engraving::Key(-meiKeysig.first);
2077 2 : } else if (meiKeysig.second == libmei::ACCIDENTAL_WRITTEN_n) {
2078 2 : return engraving::Key(0);
2079 : }
2080 0 : warning = true;
2081 0 : return engraving::Key(0);
2082 : }
2083 :
2084 21 : libmei::data_KEYSIGNATURE Convert::keyToMEI(const engraving::Key key)
2085 : {
2086 21 : if (key > 0) {
2087 16 : return std::make_pair(std::min(static_cast<int>(key), 7), libmei::ACCIDENTAL_WRITTEN_s);
2088 5 : } else if (key < 0) {
2089 3 : return std::make_pair(std::abs(std::max(static_cast<int>(key), -7)), libmei::ACCIDENTAL_WRITTEN_f);
2090 : } else {
2091 2 : return std::make_pair(0, libmei::ACCIDENTAL_WRITTEN_n);
2092 : }
2093 : }
2094 :
2095 22 : engraving::LineType Convert::lineFromMEI(const libmei::data_LINEFORM meiLine, bool& warning)
2096 : {
2097 22 : warning = false;
2098 22 : switch (meiLine) {
2099 16 : case (libmei::LINEFORM_solid): return engraving::LineType::SOLID;
2100 2 : case (libmei::LINEFORM_dashed): return engraving::LineType::DASHED;
2101 4 : case (libmei::LINEFORM_dotted): return engraving::LineType::DOTTED;
2102 0 : case (libmei::LINEFORM_wavy):
2103 0 : warning = true;
2104 0 : return engraving::LineType::SOLID;
2105 0 : default:
2106 0 : return engraving::LineType::SOLID;
2107 : }
2108 : }
2109 :
2110 22 : libmei::data_LINEFORM Convert::lineToMEI(engraving::LineType line)
2111 : {
2112 22 : switch (line) {
2113 16 : case (engraving::LineType::SOLID): return libmei::LINEFORM_solid;
2114 2 : case (engraving::LineType::DASHED): return libmei::LINEFORM_dashed;
2115 4 : case (engraving::LineType::DOTTED): return libmei::LINEFORM_dotted;
2116 0 : default:
2117 0 : return libmei::LINEFORM_NONE;
2118 : }
2119 : }
2120 :
2121 9 : void Convert::markerFromMEI(engraving::Marker* marker, const libmei::RepeatMark& meiRepeatMark, bool& warning)
2122 : {
2123 9 : warning = false;
2124 :
2125 : engraving::MarkerType markerType;
2126 :
2127 : // @func
2128 9 : switch (meiRepeatMark.GetFunc()) {
2129 3 : case (libmei::repeatMarkLog_FUNC_segno): markerType = engraving::MarkerType::SEGNO;
2130 3 : break;
2131 5 : case (libmei::repeatMarkLog_FUNC_coda): markerType = engraving::MarkerType::CODA;
2132 5 : break;
2133 1 : case (libmei::repeatMarkLog_FUNC_fine): markerType = engraving::MarkerType::FINE;
2134 1 : break;
2135 0 : default:
2136 0 : markerType = engraving::MarkerType::SEGNO;
2137 : }
2138 :
2139 : // @type
2140 9 : if (meiRepeatMark.HasType()) {
2141 4 : std::list<std::string> markerTypes = Convert::getTypeValuesWithPrefix(meiRepeatMark.GetType(), MARKER_TYPE);
2142 4 : if (markerTypes.size() > 0) {
2143 4 : std::string value = markerTypes.front();
2144 4 : auto result = std::find_if(Convert::s_markerTypes.begin(), Convert::s_markerTypes.end(),
2145 17 : [value](const auto& entry) { return entry.second == value; });
2146 :
2147 4 : if (result != Convert::s_markerTypes.end()) {
2148 4 : markerType = result->first;
2149 : } else {
2150 0 : warning = true;
2151 : }
2152 4 : }
2153 4 : }
2154 :
2155 9 : marker->setMarkerType(markerType);
2156 9 : marker->resetProperty(engraving::Pid::LABEL);
2157 :
2158 : // @color
2159 9 : Convert::colorFromMEI(marker, meiRepeatMark);
2160 9 : }
2161 :
2162 9 : libmei::RepeatMark Convert::markerToMEI(const engraving::Marker* marker, String& text)
2163 : {
2164 9 : libmei::RepeatMark meiRepeatMark;
2165 :
2166 : // @func
2167 9 : switch (marker->markerType()) {
2168 3 : case (engraving::MarkerType::SEGNO):
2169 3 : case (engraving::MarkerType::VARSEGNO): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_segno);
2170 3 : break;
2171 3 : case (engraving::MarkerType::CODA):
2172 : case (engraving::MarkerType::VARCODA):
2173 3 : case (engraving::MarkerType::CODETTA): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_coda);
2174 3 : break;
2175 1 : case (engraving::MarkerType::FINE): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_fine);
2176 1 : break;
2177 2 : case (engraving::MarkerType::TOCODA):
2178 : case (engraving::MarkerType::TOCODASYM):
2179 : case (engraving::MarkerType::DA_CODA):
2180 2 : case (engraving::MarkerType::DA_DBLCODA): meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_coda);
2181 2 : break;
2182 0 : default:
2183 0 : meiRepeatMark.SetFunc(libmei::repeatMarkLog_FUNC_segno);
2184 : }
2185 :
2186 : // @type
2187 9 : if (Convert::s_markerTypes.count(marker->markerType())) {
2188 4 : meiRepeatMark.SetType(MARKER_TYPE + Convert::s_markerTypes.at(marker->markerType()));
2189 : }
2190 :
2191 9 : switch (marker->markerType()) {
2192 : // No text for the default symbols
2193 5 : case (engraving::MarkerType::SEGNO):
2194 : case (engraving::MarkerType::CODA):
2195 : case (engraving::MarkerType::CODETTA):
2196 : case (engraving::MarkerType::FINE):
2197 5 : break;
2198 2 : case (engraving::MarkerType::VARCODA):
2199 : case (engraving::MarkerType::VARSEGNO):
2200 : // Here we could use @glyph.auth and @glyph.name, but they are not included in MEI Basic
2201 2 : break;
2202 0 : case (engraving::MarkerType::TOCODASYM):
2203 0 : text = "To 𝄌";
2204 0 : break;
2205 2 : default:
2206 2 : text = marker->plainText();
2207 : }
2208 :
2209 : // @color
2210 9 : Convert::colorToMEI(marker, meiRepeatMark);
2211 :
2212 9 : return meiRepeatMark;
2213 0 : }
2214 :
2215 404 : Convert::MeasureStruct Convert::measureFromMEI(const libmei::Measure& meiMeasure, bool& warning)
2216 : {
2217 404 : warning = false;
2218 404 : MeasureStruct measureSt;
2219 :
2220 : // for now only rely on the presence of @n
2221 404 : measureSt.irregular = (!meiMeasure.HasN());
2222 :
2223 404 : if (meiMeasure.HasN() && std::isdigit(meiMeasure.GetN().at(0))) {
2224 400 : measureSt.n = std::stoi(meiMeasure.GetN());
2225 : // Make sure we have no measure number below 0;
2226 400 : measureSt.n = std::max(0, measureSt.n);
2227 : }
2228 :
2229 404 : if (meiMeasure.HasLeft()) {
2230 5 : bool barlineWarning = false;
2231 5 : engraving::BarLineType leftBarlineType = Convert::barlineFromMEI(meiMeasure.GetLeft(), barlineWarning);
2232 5 : measureSt.repeatStart = (leftBarlineType == engraving::BarLineType::START_REPEAT);
2233 5 : warning = (warning || barlineWarning);
2234 : }
2235 :
2236 404 : if (meiMeasure.HasRight()) {
2237 72 : bool barlineWarning = false;
2238 72 : measureSt.endBarLineType = Convert::barlineFromMEI(meiMeasure.GetRight(), barlineWarning);
2239 72 : warning = (warning || barlineWarning);
2240 : // the measure will be flagged as repeatEnd and the BarLineType will not have to be set
2241 : measureSt.repeatEnd
2242 216 : = (std::set<engraving::BarLineType> { engraving::BarLineType::END_REPEAT, engraving::BarLineType::END_START_REPEAT }).count(
2243 72 : measureSt.endBarLineType) > 0;
2244 : }
2245 :
2246 404 : if (meiMeasure.HasType()) {
2247 6 : std::list<std::string> repeats = Convert::getTypeValuesWithPrefix(meiMeasure.GetType(), MEASURE_REPEAT_TYPE);
2248 6 : if (repeats.size() > 0) {
2249 6 : measureSt.repeatCount = String(repeats.front().c_str()).toInt();
2250 : // make sure it is not smaller than 0
2251 6 : measureSt.repeatCount = std::max(0, measureSt.repeatCount);
2252 : }
2253 6 : }
2254 :
2255 404 : return measureSt;
2256 : }
2257 :
2258 404 : libmei::Measure Convert::measureToMEI(const engraving::Measure* measure, int& measureN, bool& isLastExcludedFromNumbering)
2259 : {
2260 404 : libmei::Measure meiMeasure;
2261 :
2262 : // @metcon
2263 404 : if (measure->ticks() != measure->timesig()) {
2264 10 : meiMeasure.SetMetcon(libmei::BOOLEAN_false);
2265 : }
2266 : // @n
2267 404 : if (!measure->excludeFromNumbering()) {
2268 400 : measureN++;
2269 400 : meiMeasure.SetN(String::number(measure->measureNumber() + 1).toStdString());
2270 : }
2271 : // @left
2272 404 : if (measure->repeatStart()) {
2273 5 : meiMeasure.SetLeft(libmei::BARRENDITION_rptstart);
2274 : }
2275 :
2276 : // @type used for storing measure repeat count
2277 404 : if (measure->repeatEnd() && (measure->repeatCount() != 0)) {
2278 6 : meiMeasure.SetType(String(u"%1%2").arg(String(MEASURE_REPEAT_TYPE)).arg(measure->repeatCount()).toStdString());
2279 : }
2280 :
2281 : // @right
2282 404 : meiMeasure.SetRight(Convert::barlineToMEI(measure->endBarLineType()));
2283 :
2284 : // update the flag for the next measure
2285 404 : isLastExcludedFromNumbering = (measure->excludeFromNumbering());
2286 :
2287 404 : return meiMeasure;
2288 0 : }
2289 :
2290 14 : std::pair<engraving::Fraction, engraving::TimeSigType> Convert::meterFromMEI(const libmei::ScoreDef& meiScoreDef, bool& warning)
2291 : {
2292 14 : libmei::StaffDef meiStaffDef;
2293 14 : meiStaffDef.SetMeterSym(meiScoreDef.GetMeterSym());
2294 14 : meiStaffDef.SetMeterUnit(meiScoreDef.GetMeterUnit());
2295 14 : meiStaffDef.SetMeterCount(meiScoreDef.GetMeterCount());
2296 28 : return meterFromMEI(meiStaffDef, warning);
2297 14 : }
2298 :
2299 143 : std::pair<engraving::Fraction, engraving::TimeSigType> Convert::meterFromMEI(const libmei::StaffDef& meiStaffDef, bool& warning)
2300 : {
2301 143 : warning = false;
2302 143 : engraving::Fraction fraction;
2303 143 : engraving::TimeSigType tsType = engraving::TimeSigType::NORMAL;
2304 143 : if (meiStaffDef.HasMeterCount() && meiStaffDef.HasMeterUnit()) {
2305 137 : auto [counts, sign] = meiStaffDef.GetMeterCount();
2306 137 : int numerator = !counts.empty() ? counts.front() : (meiStaffDef.GetMeterSym() == libmei::METERSIGN_common) ? 4 : 2;
2307 137 : fraction.set(numerator, meiStaffDef.GetMeterUnit());
2308 137 : }
2309 143 : if (meiStaffDef.HasMeterSym()) {
2310 6 : if (meiStaffDef.GetMeterSym() == libmei::METERSIGN_common) {
2311 4 : tsType = engraving::TimeSigType::FOUR_FOUR;
2312 4 : fraction.set(4, 4);
2313 : } else {
2314 2 : tsType = engraving::TimeSigType::ALLA_BREVE;
2315 2 : fraction.set(2, 2);
2316 : }
2317 : }
2318 143 : if (fraction.isZero()) {
2319 0 : fraction.set(4, 4);
2320 0 : warning = true;
2321 : }
2322 286 : return { fraction, tsType };
2323 : }
2324 :
2325 143 : libmei::StaffDef Convert::meterToMEI(const engraving::Fraction& fraction, engraving::TimeSigType tsType)
2326 : {
2327 143 : libmei::StaffDef meiStaffDef;
2328 143 : if (tsType == engraving::TimeSigType::FOUR_FOUR) {
2329 4 : meiStaffDef.SetMeterSym(libmei::METERSIGN_common);
2330 139 : } else if (tsType == engraving::TimeSigType::ALLA_BREVE) {
2331 2 : meiStaffDef.SetMeterSym(libmei::METERSIGN_cut);
2332 : } else {
2333 274 : meiStaffDef.SetMeterCount({ { fraction.numerator() }, libmei::MeterCountSign::None });
2334 137 : meiStaffDef.SetMeterUnit(fraction.denominator());
2335 : }
2336 143 : return meiStaffDef;
2337 0 : }
2338 :
2339 22 : Convert::OrnamStruct Convert::mordentFromMEI(engraving::Ornament* ornament, const libmei::Mordent& meiMordent, bool& warning)
2340 : {
2341 : // @glyph.name
2342 22 : bool smufl = (meiMordent.HasGlyphAuth() && (meiMordent.GetGlyphAuth() == SMUFL_AUTH));
2343 :
2344 22 : engraving::SymId symId = engraving::SymId::ornamentMordent;
2345 :
2346 : // We give @glyph.name (or @glyph.num) priority over @form and @long
2347 22 : if (smufl && meiMordent.HasGlyphName()) {
2348 : // Check if the @glyph.name needs to be mapped to a composite glyph
2349 10 : std::string value = meiMordent.GetGlyphName();
2350 10 : auto result = std::find_if(Convert::s_mordentGlyphs.begin(), Convert::s_mordentGlyphs.end(),
2351 78 : [value](const auto& entry) { return entry.second == value; });
2352 10 : if (result != Convert::s_mordentGlyphs.end()) {
2353 7 : symId = result->first;
2354 : // Otherwise get the symId from the @glyph.name
2355 : } else {
2356 3 : symId = engraving::SymNames::symIdByName(String(meiMordent.GetGlyphName().c_str()));
2357 : }
2358 10 : if (symId == engraving::SymId::noSym) {
2359 0 : warning = true;
2360 : }
2361 10 : }
2362 : // This is for loading MEI files not written by MuseScore and that use @glyph.num instead of @glyph.name
2363 12 : else if (smufl && meiMordent.HasGlyphNum()) {
2364 0 : symId = engravingFonts()->fallbackFont()->fromCode(meiMordent.GetGlyphNum());
2365 0 : if (symId == engraving::SymId::noSym) {
2366 0 : warning = true;
2367 : }
2368 : }
2369 : // @form and @long only
2370 : else {
2371 12 : bool isLower = (meiMordent.HasForm() && (meiMordent.GetForm() == libmei::mordentLog_FORM_lower));
2372 12 : bool isLong = (meiMordent.HasLong() && (meiMordent.GetLong() == libmei::BOOLEAN_true));
2373 12 : if (isLower && isLong) {
2374 2 : symId = engraving::SymId::ornamentPrallMordent;
2375 10 : } else if (isLower && !isLong) {
2376 3 : symId = engraving::SymId::ornamentMordent;
2377 7 : } else if (!isLower && isLong) {
2378 2 : symId = engraving::SymId::ornamentTremblement;
2379 : } else {
2380 5 : symId = engraving::SymId::ornamentShortTrill;
2381 : }
2382 : }
2383 :
2384 22 : ornament->setSymId(symId);
2385 :
2386 : // @color
2387 22 : Convert::colorFromMEI(ornament, meiMordent);
2388 :
2389 : // Other attributes
2390 22 : return Convert::ornamFromMEI(ornament, meiMordent, warning);
2391 : }
2392 :
2393 22 : libmei::Mordent Convert::mordentToMEI(const engraving::Ornament* ornament)
2394 : {
2395 22 : libmei::Mordent meiMordent;
2396 :
2397 22 : Convert::ornamToMEI(ornament, meiMordent);
2398 :
2399 : // @form
2400 22 : switch (ornament->symId()) {
2401 7 : case (engraving::SymId::ornamentMordent):
2402 : case (engraving::SymId::ornamentPrallMordent):
2403 : case (engraving::SymId::ornamentUpMordent):
2404 : case (engraving::SymId::ornamentDownMordent):
2405 7 : meiMordent.SetForm(libmei::mordentLog_FORM_lower);
2406 7 : break;
2407 12 : case (engraving::SymId::ornamentShortTrill):
2408 : case (engraving::SymId::ornamentTremblement):
2409 : case (engraving::SymId::ornamentUpPrall):
2410 : case (engraving::SymId::ornamentPrecompMordentUpperPrefix):
2411 : case (engraving::SymId::ornamentPrallDown):
2412 : case (engraving::SymId::ornamentPrallUp):
2413 : case (engraving::SymId::ornamentLinePrall):
2414 12 : meiMordent.SetForm(libmei::mordentLog_FORM_upper);
2415 12 : break;
2416 3 : default:
2417 3 : break;
2418 : }
2419 :
2420 : // @long
2421 22 : switch (ornament->symId()) {
2422 11 : case (engraving::SymId::ornamentTremblement):
2423 : case (engraving::SymId::ornamentPrallMordent):
2424 : case (engraving::SymId::ornamentUpPrall):
2425 : case (engraving::SymId::ornamentPrecompMordentUpperPrefix):
2426 : case (engraving::SymId::ornamentUpMordent):
2427 : case (engraving::SymId::ornamentDownMordent):
2428 : case (engraving::SymId::ornamentPrallDown):
2429 : case (engraving::SymId::ornamentPrallUp):
2430 : case (engraving::SymId::ornamentLinePrall):
2431 11 : meiMordent.SetLong(libmei::BOOLEAN_true);
2432 11 : break;
2433 11 : default:
2434 11 : break;
2435 : }
2436 :
2437 : // glyph.name
2438 22 : bool smufl = true;
2439 22 : switch (ornament->symId()) {
2440 12 : case (engraving::SymId::ornamentMordent):
2441 : case (engraving::SymId::ornamentShortTrill):
2442 : case (engraving::SymId::ornamentTremblement):
2443 : case (engraving::SymId::ornamentPrallMordent):
2444 12 : smufl = false;
2445 12 : break;
2446 10 : default:
2447 10 : break;
2448 : }
2449 22 : if (smufl) {
2450 : // For glyph with composite glyphs in MuseScore use the values in the Convert map
2451 10 : if (s_mordentGlyphs.count(ornament->symId())) {
2452 7 : meiMordent.SetGlyphName(s_mordentGlyphs.at(ornament->symId()));
2453 : } else {
2454 3 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(ornament->symId());
2455 9 : meiMordent.SetGlyphName(glyphName.ascii());
2456 : }
2457 30 : meiMordent.SetGlyphAuth(SMUFL_AUTH);
2458 : }
2459 :
2460 : // @color
2461 22 : Convert::colorToMEI(ornament, meiMordent);
2462 :
2463 22 : return meiMordent;
2464 0 : }
2465 :
2466 7 : void Convert::octaveFromMEI(engraving::Ottava* ottava, const libmei::Octave& meiOctave, bool& warning)
2467 : {
2468 7 : warning = false;
2469 :
2470 : engraving::OttavaType ottavaType;
2471 7 : if (meiOctave.GetDisPlace() == libmei::STAFFREL_basic_below) {
2472 3 : switch (meiOctave.GetDis()) {
2473 1 : case (libmei::OCTAVE_DIS_22): ottavaType = engraving::OttavaType::OTTAVA_22MB;
2474 1 : break;
2475 1 : case (libmei::OCTAVE_DIS_15): ottavaType = engraving::OttavaType::OTTAVA_15MB;
2476 1 : break;
2477 1 : default:
2478 1 : ottavaType = engraving::OttavaType::OTTAVA_8VB;
2479 : }
2480 : } else {
2481 4 : switch (meiOctave.GetDis()) {
2482 1 : case (libmei::OCTAVE_DIS_22): ottavaType = engraving::OttavaType::OTTAVA_22MA;
2483 1 : break;
2484 1 : case (libmei::OCTAVE_DIS_15): ottavaType = engraving::OttavaType::OTTAVA_15MA;
2485 1 : break;
2486 2 : default:
2487 2 : ottavaType = engraving::OttavaType::OTTAVA_8VA;
2488 : }
2489 : }
2490 7 : ottava->setOttavaType(ottavaType);
2491 :
2492 : // @extender
2493 7 : if (meiOctave.HasExtender() && (meiOctave.GetExtender() == libmei::BOOLEAN_false)) {
2494 1 : ottava->setLineVisible(false);
2495 : }
2496 :
2497 : // @lform
2498 7 : if (meiOctave.HasLform()) {
2499 2 : bool lformWarning = false;
2500 2 : ottava->setLineStyle(Convert::lineFromMEI(meiOctave.GetLform(), lformWarning));
2501 2 : ottava->setPropertyFlags(engraving::Pid::LINE_STYLE, engraving::PropertyFlags::UNSTYLED);
2502 2 : warning = (warning || lformWarning);
2503 : }
2504 :
2505 : // @lendsym
2506 7 : if (meiOctave.HasLendsym() && (meiOctave.GetLendsym() == libmei::LINESTARTENDSYMBOL_none)) {
2507 1 : ottava->setEndHookType(engraving::HookType::NONE);
2508 : }
2509 :
2510 : // @color
2511 7 : Convert::colorlineFromMEI(ottava, meiOctave);
2512 7 : }
2513 :
2514 7 : libmei::Octave Convert::octaveToMEI(const engraving::Ottava* ottava)
2515 : {
2516 7 : libmei::Octave meiOctave;
2517 :
2518 : // @dis
2519 7 : switch (ottava->ottavaType()) {
2520 3 : case (engraving::OttavaType::OTTAVA_8VA):
2521 : case (engraving::OttavaType::OTTAVA_8VB):
2522 3 : meiOctave.SetDis(libmei::OCTAVE_DIS_8);
2523 3 : break;
2524 2 : case (engraving::OttavaType::OTTAVA_15MA):
2525 : case (engraving::OttavaType::OTTAVA_15MB):
2526 2 : meiOctave.SetDis(libmei::OCTAVE_DIS_15);
2527 2 : break;
2528 2 : case (engraving::OttavaType::OTTAVA_22MA):
2529 : case (engraving::OttavaType::OTTAVA_22MB):
2530 2 : meiOctave.SetDis(libmei::OCTAVE_DIS_22);
2531 2 : break;
2532 : }
2533 :
2534 : // @dis.place
2535 7 : switch (ottava->ottavaType()) {
2536 4 : case (engraving::OttavaType::OTTAVA_8VA):
2537 : case (engraving::OttavaType::OTTAVA_15MA):
2538 : case (engraving::OttavaType::OTTAVA_22MA):
2539 4 : meiOctave.SetDisPlace(libmei::STAFFREL_basic_above);
2540 4 : break;
2541 3 : case (engraving::OttavaType::OTTAVA_8VB):
2542 : case (engraving::OttavaType::OTTAVA_15MB):
2543 : case (engraving::OttavaType::OTTAVA_22MB):
2544 3 : meiOctave.SetDisPlace(libmei::STAFFREL_basic_below);
2545 3 : break;
2546 : }
2547 :
2548 : // @extender
2549 7 : if (!ottava->lineVisible()) {
2550 1 : meiOctave.SetExtender(libmei::BOOLEAN_false);
2551 : }
2552 :
2553 : // @lform
2554 7 : if (ottava->lineStyle() != engraving::LineType::DASHED) {
2555 2 : meiOctave.SetLform(Convert::lineToMEI(ottava->lineStyle()));
2556 : }
2557 :
2558 : // @lendsym
2559 7 : if (ottava->endHookType() == engraving::HookType::NONE) {
2560 1 : meiOctave.SetLendsym(libmei::LINESTARTENDSYMBOL_none);
2561 : }
2562 :
2563 : // @color
2564 7 : Convert::colorlineToMEI(ottava, meiOctave);
2565 :
2566 : // @staff
2567 7 : Convert::staffIdentToMEI(ottava, meiOctave);
2568 :
2569 7 : return meiOctave;
2570 0 : }
2571 :
2572 37 : Convert::OrnamStruct Convert::ornamFromMEI(engraving::Ornament* ornament, const libmei::Element& meiElement, bool& warning)
2573 : {
2574 37 : OrnamStruct ornamSt;
2575 :
2576 37 : const libmei::AttOrnamentAccid* ornamAccidAtt = dynamic_cast<const libmei::AttOrnamentAccid*>(&meiElement);
2577 37 : const libmei::AttPlacementRelStaff* placementRelStaffAtt = dynamic_cast<const libmei::AttPlacementRelStaff*>(&meiElement);
2578 37 : const libmei::AttTyped* typedAtt = dynamic_cast<const libmei::AttTyped*>(&meiElement);
2579 :
2580 37 : IF_ASSERT_FAILED(ornamAccidAtt && placementRelStaffAtt && typedAtt) {
2581 0 : return ornamSt;
2582 : }
2583 :
2584 : // @accidlower
2585 37 : if (ornamAccidAtt->HasAccidlower()) {
2586 2 : bool accidWarning = false;
2587 2 : ornamSt.accidTypeBelow = Convert::accidFromMEI(ornamAccidAtt->GetAccidlower(), accidWarning);
2588 2 : warning = (warning || accidWarning);
2589 : }
2590 :
2591 : // @accidupper
2592 37 : if (ornamAccidAtt->HasAccidupper()) {
2593 7 : bool accidWarning = false;
2594 7 : ornamSt.accidTypeAbove = Convert::accidFromMEI(ornamAccidAtt->GetAccidupper(), accidWarning);
2595 7 : warning = (warning || accidWarning);
2596 : }
2597 :
2598 : // @place
2599 37 : if (placementRelStaffAtt->HasPlace()) {
2600 6 : bool placeWarning = false;
2601 6 : ornament->setAnchor(Convert::anchorFromMEI(placementRelStaffAtt->GetPlace(), placeWarning));
2602 6 : ornament->setPropertyFlags(engraving::Pid::ARTICULATION_ANCHOR, engraving::PropertyFlags::UNSTYLED);
2603 6 : warning = (warning || placeWarning);
2604 : }
2605 :
2606 : // @type
2607 37 : if (typedAtt->HasType()) {
2608 9 : Convert::ornamintervaleFromMEI(ornament, typedAtt->GetType());
2609 : }
2610 :
2611 : // @color
2612 37 : Convert::colorFromMEI(ornament, meiElement);
2613 :
2614 37 : return ornamSt;
2615 : }
2616 :
2617 0 : libmei::Ornam Convert::ornamToMEI(const engraving::Ornament* ornament)
2618 : {
2619 0 : libmei::Ornam meiOrnam;
2620 :
2621 0 : Convert::ornamToMEI(ornament, meiOrnam);
2622 :
2623 0 : return meiOrnam;
2624 0 : }
2625 :
2626 37 : void Convert::ornamToMEI(const engraving::Ornament* ornament, libmei::Element& meiElement)
2627 : {
2628 37 : libmei::AttOrnamentAccid* ornamAccidAtt = dynamic_cast<libmei::AttOrnamentAccid*>(&meiElement);
2629 37 : libmei::AttPlacementRelStaff* placementRelStaffAtt = dynamic_cast<libmei::AttPlacementRelStaff*>(&meiElement);
2630 37 : libmei::AttTyped* typedAtt = dynamic_cast<libmei::AttTyped*>(&meiElement);
2631 :
2632 37 : IF_ASSERT_FAILED(ornamAccidAtt && placementRelStaffAtt && typedAtt) {
2633 0 : return;
2634 : }
2635 :
2636 : // @accidlower
2637 37 : if (ornament->accidentalBelow()) {
2638 2 : ornamAccidAtt->SetAccidlower(Convert::accidToMEI(ornament->accidentalBelow()->accidentalType()));
2639 : }
2640 :
2641 : // @accidupper
2642 37 : if (ornament->accidentalAbove()) {
2643 7 : ornamAccidAtt->SetAccidupper(Convert::accidToMEI(ornament->accidentalAbove()->accidentalType()));
2644 : }
2645 :
2646 : // @place
2647 37 : if (ornament->propertyFlags(engraving::Pid::ARTICULATION_ANCHOR) == engraving::PropertyFlags::UNSTYLED) {
2648 6 : placementRelStaffAtt->SetPlace(Convert::anchorToMEI(ornament->anchor()));
2649 : }
2650 :
2651 : // @type
2652 37 : typedAtt->SetType(Convert::ornamintervalToMEI(ornament).toStdString());
2653 :
2654 : // @color
2655 37 : Convert::colorToMEI(ornament, meiElement);
2656 : }
2657 :
2658 9 : void Convert::ornamintervaleFromMEI(engraving::Ornament* ornament, const std::string& meiType)
2659 : {
2660 : // @type
2661 9 : std::string value;
2662 :
2663 18 : if (Convert::getTypeValueWithPrefix(meiType, INTERVAL_ABOVE, value)) {
2664 8 : engraving::OrnamentInterval interval = engraving::TConv::fromXml(String(value.c_str()).replace(u':',
2665 : u','),
2666 : engraving::DEFAULT_ORNAMENT_INTERVAL);
2667 8 : ornament->setIntervalAbove(interval);
2668 : }
2669 :
2670 18 : if (Convert::getTypeValueWithPrefix(meiType, INTERVAL_BELOW, value)) {
2671 2 : engraving::OrnamentInterval interval = engraving::TConv::fromXml(String(value.c_str()).replace(u':',
2672 : u','),
2673 : engraving::DEFAULT_ORNAMENT_INTERVAL);
2674 2 : ornament->setIntervalBelow(interval);
2675 : }
2676 9 : }
2677 :
2678 37 : String Convert::ornamintervalToMEI(const engraving::Ornament* ornament)
2679 : {
2680 : // @type
2681 37 : StringList typeList;
2682 :
2683 37 : if (ornament->hasIntervalAbove() && (ornament->intervalAbove().type != engraving::IntervalType::AUTO)) {
2684 : // Since a , is not valid in a type attribute, replace with :
2685 8 : String intervalStr = engraving::TConv::toXml(ornament->intervalAbove()).replace(u',', u':');
2686 8 : typeList << String("%1%2").arg(String(INTERVAL_ABOVE)).arg(intervalStr);
2687 8 : }
2688 :
2689 37 : if (ornament->hasIntervalBelow() && (ornament->intervalBelow().type != engraving::IntervalType::AUTO)) {
2690 2 : String intervalStr = engraving::TConv::toXml(ornament->intervalBelow()).replace(u',', u':');
2691 2 : typeList << String("%1%2").arg(String(INTERVAL_BELOW)).arg(intervalStr);
2692 2 : }
2693 :
2694 74 : return typeList.join(u" ");
2695 37 : }
2696 :
2697 5 : void Convert::pedalFromMEI(engraving::Pedal* pedal, const libmei::Pedal& meiPedal, bool& warning)
2698 : {
2699 5 : warning = false;
2700 :
2701 : // @dir - ignore, dealing with "down" only
2702 :
2703 : // @form
2704 5 : if (meiPedal.GetForm() == libmei::PEDALSTYLE_pedstar) {
2705 2 : pedal->setBeginText(engraving::Pedal::PEDAL_SYMBOL);
2706 2 : pedal->setPropertyFlags(engraving::Pid::BEGIN_TEXT, engraving::PropertyFlags::UNSTYLED);
2707 2 : pedal->setEndText(engraving::Pedal::STAR_SYMBOL);
2708 2 : pedal->setPropertyFlags(engraving::Pid::END_TEXT, engraving::PropertyFlags::UNSTYLED);
2709 2 : pedal->setLineVisible(false);
2710 3 : } else if (meiPedal.GetForm() == libmei::PEDALSTYLE_pedline) {
2711 2 : pedal->setBeginText(engraving::Pedal::PEDAL_SYMBOL);
2712 2 : pedal->setPropertyFlags(engraving::Pid::BEGIN_TEXT, engraving::PropertyFlags::UNSTYLED);
2713 2 : pedal->setEndHookType(engraving::HookType::HOOK_90);
2714 : } else {
2715 1 : pedal->setBeginHookType(engraving::HookType::HOOK_90);
2716 1 : pedal->setBeginText(String());
2717 1 : pedal->setContinueText(String());
2718 1 : pedal->setEndHookType(engraving::HookType::HOOK_90);
2719 : }
2720 :
2721 : // @func
2722 5 : if (meiPedal.GetFunc() == "soft") {
2723 : // This is just for importing MEI files and will not be exported
2724 0 : if (pedal->beginText() != "") {
2725 0 : pedal->setBeginText(u"una corda");
2726 0 : pedal->setContinueText(u"");
2727 : }
2728 5 : } else if (meiPedal.GetFunc() == "sostenuto") {
2729 1 : if (pedal->beginText() != "") {
2730 1 : pedal->setBeginText(u"<sym>keyboardPedalSost</sym>");
2731 1 : pedal->setContinueText(u"(<sym>keyboardPedalSost</sym>)");
2732 : }
2733 : }
2734 :
2735 : // @color
2736 5 : Convert::colorlineFromMEI(pedal, meiPedal);
2737 5 : }
2738 :
2739 5 : libmei::Pedal Convert::pedalToMEI(const engraving::Pedal* pedal)
2740 : {
2741 5 : libmei::Pedal meiPedal;
2742 :
2743 : // @dir
2744 5 : meiPedal.SetDir(libmei::pedalLog_DIR_down);
2745 :
2746 5 : bool symbol = (!pedal->beginText().isEmpty());
2747 5 : bool star = (pedal->endText() == engraving::Pedal::STAR_SYMBOL);
2748 :
2749 : // @form
2750 5 : if (symbol && star) {
2751 2 : meiPedal.SetForm(libmei::PEDALSTYLE_pedstar);
2752 3 : } else if (symbol && !star) {
2753 2 : meiPedal.SetForm(libmei::PEDALSTYLE_pedline);
2754 : } else {
2755 1 : meiPedal.SetForm(libmei::PEDALSTYLE_line);
2756 : }
2757 :
2758 : // @func
2759 5 : if (pedal->beginText() == u"<sym>keyboardPedalSost</sym>" || pedal->beginText() == u"<sym>keyboardPedalS</sym>") {
2760 3 : meiPedal.SetFunc("sostenuto");
2761 : }
2762 :
2763 : // @color
2764 5 : Convert::colorlineToMEI(pedal, meiPedal);
2765 :
2766 5 : return meiPedal;
2767 0 : }
2768 :
2769 1815 : Convert::PitchStruct Convert::pitchFromMEI(const libmei::Note& meiNote, const libmei::Accid& meiAccid,
2770 : const engraving::Interval& interval,
2771 : bool& warning)
2772 : {
2773 : // The mapping from pitch name to step
2774 : static int pitchMap[7] = { 0, 2, 4, 5, 7, 9, 11 };
2775 : // c d e f g a b
2776 :
2777 1815 : warning = false;
2778 1815 : PitchStruct pitchSt;
2779 :
2780 1815 : int step = meiNote.HasPname() ? meiNote.GetPname() - 1 : 0;
2781 : // It should never be necessary, but just in case
2782 1815 : step = std::clamp(step, 0, 6);
2783 :
2784 1815 : int oct = meiNote.HasOct() ? meiNote.GetOct() : 3;
2785 :
2786 1815 : engraving::AccidentalVal alter = engraving::AccidentalVal::NATURAL;
2787 1815 : if (meiAccid.HasAccid() || meiAccid.HasAccidGes()) {
2788 310 : bool accidWarning = false;
2789 : libmei::data_ACCIDENTAL_GESTURAL meiAccidGes
2790 310 : = (meiAccid.HasAccidGes()) ? meiAccid.GetAccidGes() : libmei::Att::AccidentalWrittenToGestural(meiAccid.GetAccid());
2791 310 : alter = Convert::accidGesFromMEI(meiAccidGes, accidWarning);
2792 310 : warning = (warning || accidWarning);
2793 : }
2794 1815 : int alterInt = static_cast<int>(alter);
2795 :
2796 1815 : if (meiAccid.HasEnclose()) {
2797 0 : switch (meiAccid.GetEnclose()) {
2798 0 : case libmei::ENCLOSURE_brack:
2799 0 : pitchSt.accidBracket = engraving::AccidentalBracket::BRACKET;
2800 0 : break;
2801 0 : case libmei::ENCLOSURE_paren:
2802 0 : pitchSt.accidBracket = engraving::AccidentalBracket::PARENTHESIS;
2803 0 : break;
2804 0 : default:
2805 0 : pitchSt.accidBracket = engraving::AccidentalBracket::NONE;
2806 0 : break;
2807 : }
2808 : }
2809 :
2810 1815 : bool accidWarning = false;
2811 1815 : if (meiAccid.HasAccid()) {
2812 198 : pitchSt.accidRole = engraving::AccidentalRole::USER;
2813 : }
2814 1815 : pitchSt.accidType = Convert::accidFromMEI(meiAccid.GetAccid(), accidWarning);
2815 1815 : warning = (warning || accidWarning);
2816 1815 : pitchSt.pitch = pitchMap[step] + alterInt + (oct + 1) * 12;
2817 1815 : pitchSt.tpc2 = engraving::step2tpc(step, alter);
2818 : // The pitch retrieved from the MEI is the written pitch and we need to transpose it
2819 1815 : pitchSt.pitch += interval.chromatic;
2820 :
2821 1815 : return pitchSt;
2822 : }
2823 :
2824 1815 : std::pair<libmei::Note, libmei::Accid> Convert::pitchToMEI(const engraving::Note* note, const engraving::Accidental* accid,
2825 : const engraving::Interval& interval)
2826 : {
2827 1815 : libmei::Note meiNote;
2828 1815 : libmei::Accid meiAccid;
2829 :
2830 1815 : IF_ASSERT_FAILED(note) {
2831 0 : return { meiNote, meiAccid };
2832 : }
2833 :
2834 1815 : Convert::PitchStruct pitch;
2835 1815 : pitch.pitch = note->pitch();
2836 1815 : pitch.tpc2 = note->tpc2();
2837 1815 : if (accid) {
2838 198 : pitch.accidType = accid->accidentalType();
2839 198 : pitch.accidBracket = accid->bracket();
2840 : // Not needed because relying on accidType
2841 : // pitch.accidRole = accid->role();
2842 : }
2843 :
2844 : // @pname
2845 1815 : meiNote.SetPname(static_cast<libmei::data_PITCHNAME>(engraving::tpc2step(pitch.tpc2) + 1));
2846 :
2847 1815 : int writtenAlterInt = static_cast<int>(engraving::Accidental::subtype2value(pitch.accidType));
2848 1815 : int alterInt = tpc2alterByKey(pitch.tpc2, engraving::Key::C);
2849 :
2850 : // @oct
2851 : // We need to adjust the pitch to its transposed value for the octave calculation
2852 1815 : int oct = ((pitch.pitch - interval.chromatic - alterInt) / 12) - 1;
2853 1815 : meiNote.SetOct(oct);
2854 :
2855 : // @oct.ges
2856 1815 : int octGes = ((note->ppitch() - interval.chromatic - alterInt) / 12) - 1;
2857 1815 : if (octGes != oct) {
2858 22 : meiNote.SetOctGes(octGes);
2859 : }
2860 :
2861 : // @accid
2862 1815 : if (pitch.accidType != engraving::AccidentalType::NONE) {
2863 198 : meiAccid.SetAccid(Convert::accidToMEI(pitch.accidType));
2864 198 : if (pitch.accidBracket == engraving::AccidentalBracket::BRACKET) {
2865 0 : meiAccid.SetEnclose(libmei::ENCLOSURE_brack);
2866 198 : } else if (pitch.accidBracket == engraving::AccidentalBracket::PARENTHESIS) {
2867 0 : meiAccid.SetEnclose(libmei::ENCLOSURE_paren);
2868 : }
2869 : }
2870 :
2871 : // @accid.ges
2872 1815 : if (alterInt && (alterInt != writtenAlterInt)) {
2873 112 : meiAccid.SetAccidGes(Convert::accidGesToMEI(static_cast<engraving::AccidentalVal>(alterInt)));
2874 : }
2875 :
2876 1815 : return { meiNote, meiAccid };
2877 1815 : }
2878 :
2879 0 : engraving::PlacementV Convert::placeFromMEI(const libmei::data_STAFFREL meiPlace, bool& warning)
2880 : {
2881 0 : warning = false;
2882 0 : switch (meiPlace) {
2883 0 : case (libmei::STAFFREL_above): return engraving::PlacementV::ABOVE;
2884 0 : case (libmei::STAFFREL_below): return engraving::PlacementV::BELOW;
2885 0 : default:
2886 0 : return engraving::PlacementV::ABOVE;
2887 : }
2888 : }
2889 :
2890 4 : libmei::data_STAFFREL Convert::placeToMEI(engraving::PlacementV place)
2891 : {
2892 4 : switch (place) {
2893 0 : case (engraving::PlacementV::ABOVE): return libmei::STAFFREL_above;
2894 4 : case (engraving::PlacementV::BELOW): return libmei::STAFFREL_below;
2895 0 : default:
2896 0 : return libmei::STAFFREL_above;
2897 : }
2898 : }
2899 :
2900 16 : engraving::DirectionV Convert::directionFromMEI(const libmei::data_STAFFREL meiPlace)
2901 : {
2902 16 : switch (meiPlace) {
2903 4 : case (libmei::STAFFREL_above): return engraving::DirectionV::UP;
2904 1 : case (libmei::STAFFREL_below): return engraving::DirectionV::DOWN;
2905 11 : default:
2906 11 : return engraving::DirectionV::AUTO;
2907 : }
2908 : }
2909 :
2910 16 : libmei::data_STAFFREL Convert::directionToMEI(engraving::DirectionV direction)
2911 : {
2912 16 : switch (direction) {
2913 4 : case (engraving::DirectionV::UP): return libmei::STAFFREL_above;
2914 1 : case (engraving::DirectionV::DOWN): return libmei::STAFFREL_below;
2915 11 : default:
2916 11 : return libmei::STAFFREL_NONE;
2917 : }
2918 : }
2919 :
2920 1667 : engraving::DurationType Convert::durFromMEI(const libmei::data_DURATION meiDuration, bool& warning)
2921 : {
2922 1667 : warning = false;
2923 1667 : switch (meiDuration) {
2924 0 : case (libmei::DURATION_long): return engraving::DurationType::V_LONG;
2925 0 : case (libmei::DURATION_breve): return engraving::DurationType::V_BREVE;
2926 103 : case (libmei::DURATION_1): return engraving::DurationType::V_WHOLE;
2927 285 : case (libmei::DURATION_2): return engraving::DurationType::V_HALF;
2928 592 : case (libmei::DURATION_4): return engraving::DurationType::V_QUARTER;
2929 263 : case (libmei::DURATION_8): return engraving::DurationType::V_EIGHTH;
2930 212 : case (libmei::DURATION_16): return engraving::DurationType::V_16TH;
2931 148 : case (libmei::DURATION_32): return engraving::DurationType::V_32ND;
2932 64 : case (libmei::DURATION_64): return engraving::DurationType::V_64TH;
2933 0 : case (libmei::DURATION_128): return engraving::DurationType::V_128TH;
2934 0 : case (libmei::DURATION_256): return engraving::DurationType::V_256TH;
2935 0 : case (libmei::DURATION_512): return engraving::DurationType::V_512TH;
2936 0 : case (libmei::DURATION_1024): return engraving::DurationType::V_1024TH;
2937 0 : default:
2938 0 : warning = true;
2939 0 : return engraving::DurationType::V_QUARTER;
2940 : }
2941 : }
2942 :
2943 1655 : libmei::data_DURATION Convert::durToMEI(const engraving::DurationType duration)
2944 : {
2945 1655 : switch (duration) {
2946 0 : case (engraving::DurationType::V_LONG): return libmei::DURATION_long;
2947 0 : case (engraving::DurationType::V_BREVE): return libmei::DURATION_breve;
2948 107 : case (engraving::DurationType::V_WHOLE): return libmei::DURATION_1;
2949 281 : case (engraving::DurationType::V_HALF): return libmei::DURATION_2;
2950 588 : case (engraving::DurationType::V_QUARTER): return libmei::DURATION_4;
2951 255 : case (engraving::DurationType::V_EIGHTH): return libmei::DURATION_8;
2952 212 : case (engraving::DurationType::V_16TH): return libmei::DURATION_16;
2953 148 : case (engraving::DurationType::V_32ND): return libmei::DURATION_32;
2954 64 : case (engraving::DurationType::V_64TH): return libmei::DURATION_64;
2955 0 : case (engraving::DurationType::V_128TH): return libmei::DURATION_128;
2956 0 : case (engraving::DurationType::V_256TH): return libmei::DURATION_256;
2957 0 : case (engraving::DurationType::V_512TH): return libmei::DURATION_512;
2958 0 : case (engraving::DurationType::V_1024TH): return libmei::DURATION_1024;
2959 0 : default:
2960 0 : return libmei::DURATION_4;
2961 : }
2962 : }
2963 :
2964 12 : engraving::TremoloType Convert::unitdurFromMEI(const libmei::FTrem& meiFTrem, bool& warning)
2965 : {
2966 12 : warning = false;
2967 12 : switch (meiFTrem.GetUnitdur()) {
2968 3 : case (libmei::DURATION_8): return engraving::TremoloType::C8;
2969 3 : case (libmei::DURATION_16): return engraving::TremoloType::C16;
2970 3 : case (libmei::DURATION_32): return engraving::TremoloType::C32;
2971 3 : case (libmei::DURATION_64): return engraving::TremoloType::C64;
2972 0 : default:
2973 0 : warning = true;
2974 0 : return engraving::TremoloType::INVALID_TREMOLO;
2975 : }
2976 : }
2977 :
2978 12 : libmei::data_DURATION Convert::unitdurToMEI(const engraving::TremoloTwoChord* tremolo)
2979 : {
2980 12 : const libmei::data_DURATION dur = Convert::durToMEI(tremolo->durationType().type());
2981 12 : int unitdur = 0;
2982 12 : if (dur > libmei::DURATION_4) {
2983 0 : unitdur = dur - libmei::DURATION_4;
2984 : }
2985 12 : switch (tremolo->tremoloType()) {
2986 3 : case (engraving::TremoloType::C8): unitdur += libmei::DURATION_8;
2987 3 : break;
2988 3 : case (engraving::TremoloType::C16): unitdur += libmei::DURATION_16;
2989 3 : break;
2990 3 : case (engraving::TremoloType::C32): unitdur += libmei::DURATION_32;
2991 3 : break;
2992 3 : case (engraving::TremoloType::C64): unitdur += libmei::DURATION_64;
2993 3 : break;
2994 0 : default:
2995 0 : unitdur = libmei::DURATION_NONE;
2996 : }
2997 :
2998 12 : return static_cast<libmei::data_DURATION>(unitdur);
2999 : }
3000 :
3001 63 : void Convert::slurFromMEI(engraving::SlurTie* slur, const libmei::Slur& meiSlur, bool& warning)
3002 : {
3003 63 : warning = false;
3004 :
3005 : // @curvedir
3006 63 : if (meiSlur.HasCurvedir()) {
3007 21 : slur->setSlurDirection(Convert::curvedirFromMEI(meiSlur.GetCurvedir(), warning));
3008 : }
3009 :
3010 : // @lform
3011 63 : if (meiSlur.HasLform()) {
3012 22 : bool typeWarning = false;
3013 22 : slur->setStyleType(Convert::slurstyleFromMEI(meiSlur.GetLform(), typeWarning));
3014 22 : warning = (warning || typeWarning);
3015 : }
3016 :
3017 : // @color
3018 63 : Convert::colorFromMEI(slur, meiSlur);
3019 63 : }
3020 :
3021 69 : libmei::Slur Convert::slurToMEI(const engraving::SlurTie* slur)
3022 : {
3023 69 : libmei::Slur meiSlur;
3024 :
3025 : // @place
3026 69 : if (slur->slurDirection() != engraving::DirectionV::AUTO) {
3027 23 : meiSlur.SetCurvedir(Convert::curvedirToMEI(slur->slurDirection()));
3028 : }
3029 :
3030 : // @lform
3031 69 : if (slur->styleType() != engraving::SlurStyleType::Solid) {
3032 24 : meiSlur.SetLform(Convert::slurstyleToMEI(slur->styleType()));
3033 : }
3034 :
3035 : // @color
3036 69 : Convert::colorToMEI(slur, meiSlur);
3037 :
3038 69 : return meiSlur;
3039 0 : }
3040 :
3041 24 : engraving::SlurStyleType Convert::slurstyleFromMEI(const libmei::data_LINEFORM meiLine, bool& warning)
3042 : {
3043 24 : warning = false;
3044 24 : switch (meiLine) {
3045 0 : case (libmei::LINEFORM_solid): return engraving::SlurStyleType::Solid;
3046 16 : case (libmei::LINEFORM_dashed): return engraving::SlurStyleType::Dashed;
3047 8 : case (libmei::LINEFORM_dotted): return engraving::SlurStyleType::Dotted;
3048 0 : case (libmei::LINEFORM_wavy):
3049 0 : warning = true;
3050 0 : return engraving::SlurStyleType::Solid;
3051 0 : default:
3052 0 : return engraving::SlurStyleType::Solid;
3053 : }
3054 : }
3055 :
3056 24 : libmei::data_LINEFORM Convert::slurstyleToMEI(engraving::SlurStyleType slurstyle)
3057 : {
3058 24 : switch (slurstyle) {
3059 0 : case (engraving::SlurStyleType::Solid): return libmei::LINEFORM_solid;
3060 16 : case (engraving::SlurStyleType::Dashed): return libmei::LINEFORM_dashed;
3061 0 : case (engraving::SlurStyleType::WideDashed): return libmei::LINEFORM_dashed;
3062 8 : case (engraving::SlurStyleType::Dotted): return libmei::LINEFORM_dotted;
3063 0 : default:
3064 0 : return libmei::LINEFORM_NONE;
3065 : }
3066 : }
3067 :
3068 125 : Convert::StaffStruct Convert::staffFromMEI(const libmei::StaffDef& meiStaffDef, bool& warning)
3069 : {
3070 125 : warning = false;
3071 125 : StaffStruct staffSt;
3072 :
3073 125 : if (meiStaffDef.HasLines()) {
3074 125 : staffSt.lines = meiStaffDef.GetLines();
3075 : }
3076 125 : staffSt.invisible = meiStaffDef.GetLinesVisible() == libmei::BOOLEAN_false;
3077 125 : staffSt.scale = meiStaffDef.HasScale() ? meiStaffDef.GetScale() : 100;
3078 125 : staffSt.color = engraving::Color::fromString(meiStaffDef.GetLinesColor());
3079 :
3080 : // Set it only if both are given
3081 125 : if (meiStaffDef.HasTransDiat() && meiStaffDef.HasTransSemi()) {
3082 14 : staffSt.interval.diatonic = meiStaffDef.GetTransDiat();
3083 14 : staffSt.interval.chromatic = meiStaffDef.GetTransSemi();
3084 : }
3085 :
3086 125 : return staffSt;
3087 : }
3088 :
3089 125 : libmei::StaffDef Convert::staffToMEI(const engraving::Staff* staff)
3090 : {
3091 125 : libmei::StaffDef meiStaffDef;
3092 :
3093 125 : IF_ASSERT_FAILED(staff) {
3094 0 : return meiStaffDef;
3095 : }
3096 :
3097 : // @n
3098 125 : meiStaffDef.SetN(static_cast<int>(staff->idx() + 1));
3099 : // @trans.*
3100 125 : const engraving::Interval& interval = staff->part()->instrument()->transpose();
3101 125 : if (!interval.isZero()) {
3102 14 : meiStaffDef.SetTransDiat(interval.diatonic);
3103 14 : meiStaffDef.SetTransSemi(interval.chromatic);
3104 : }
3105 : // @lines
3106 125 : const engraving::StaffType* staffType = staff->staffType(engraving::Fraction(0, 1));
3107 125 : if (staffType) {
3108 125 : meiStaffDef.SetLines(staffType->lines());
3109 : }
3110 : // @lines.color
3111 125 : if (staffType->color() != engravingConfiguration()->defaultColor()) {
3112 1 : meiStaffDef.SetLinesColor(staffType->color().toString());
3113 : }
3114 : // @lines.visible
3115 125 : if (staff->isLinesInvisible(engraving::Fraction(0, 1))) {
3116 1 : meiStaffDef.SetLinesVisible(libmei::BOOLEAN_false);
3117 : }
3118 : // @scale
3119 125 : const double scale = staff->staffMag(engraving::Fraction(0, 1));
3120 125 : if (!muse::RealIsEqual(scale, 1.0)) {
3121 1 : meiStaffDef.SetScale(scale * 100);
3122 : }
3123 125 : return meiStaffDef;
3124 0 : }
3125 :
3126 35 : Convert::BracketStruct Convert::staffGrpFromMEI(const libmei::StaffGrp& meiStaffGrp)
3127 : {
3128 35 : Convert::BracketStruct bracketSt;
3129 :
3130 35 : bracketSt.bracketType = symbolFromMEI(meiStaffGrp.GetSymbol());
3131 :
3132 35 : if (meiStaffGrp.HasBarThru() && meiStaffGrp.GetBarThru() == libmei::BOOLEAN_true) {
3133 31 : bracketSt.barLineSpan = 1;
3134 : }
3135 :
3136 35 : return bracketSt;
3137 : }
3138 :
3139 35 : libmei::StaffGrp Convert::staffGrpToMEI(const engraving::BracketType bracket, const bool barLineSpan)
3140 : {
3141 35 : libmei::StaffGrp meiStaffGrp;
3142 :
3143 : // @symbol
3144 35 : meiStaffGrp.SetSymbol(symbolToMEI(bracket));
3145 :
3146 : // @bar.thru
3147 35 : if (barLineSpan) {
3148 31 : meiStaffGrp.SetBarThru(libmei::BOOLEAN_true);
3149 : }
3150 :
3151 35 : return meiStaffGrp;
3152 0 : }
3153 :
3154 1578 : std::pair<engraving::DirectionV, bool> Convert::stemFromMEI(const libmei::AttStems& meiStemsAtt, bool& warning)
3155 : {
3156 1578 : warning = false;
3157 :
3158 1578 : engraving::DirectionV direction = engraving::DirectionV::AUTO;
3159 1578 : bool noStem = false;
3160 :
3161 1578 : switch (meiStemsAtt.GetStemDir()) {
3162 25 : case (libmei::STEMDIRECTION_up): direction = engraving::DirectionV::UP;
3163 25 : break;
3164 25 : case (libmei::STEMDIRECTION_down): direction = engraving::DirectionV::DOWN;
3165 25 : break;
3166 1528 : default:
3167 1528 : break;
3168 : }
3169 1578 : if (RealIsNull(meiStemsAtt.GetStemLen())) {
3170 2 : noStem = true;
3171 : }
3172 :
3173 1578 : return { direction, noStem };
3174 : }
3175 :
3176 1578 : std::pair<libmei::data_STEMDIRECTION, double> Convert::stemToMEI(const engraving::DirectionV direction, bool noStem)
3177 : {
3178 1578 : libmei::data_STEMDIRECTION meiStemDir = libmei::STEMDIRECTION_NONE;
3179 1578 : double meiStemLen = -1.0;
3180 :
3181 1578 : switch (direction) {
3182 25 : case (engraving::DirectionV::UP): meiStemDir = libmei::STEMDIRECTION_up;
3183 25 : break;
3184 25 : case (engraving::DirectionV::DOWN): meiStemDir = libmei::STEMDIRECTION_down;
3185 25 : break;
3186 1528 : default:
3187 1528 : break;
3188 : }
3189 1578 : if (noStem) {
3190 2 : meiStemDir = libmei::STEMDIRECTION_NONE;
3191 2 : meiStemLen = 0.0;
3192 : }
3193 :
3194 1578 : return { meiStemDir, meiStemLen };
3195 : }
3196 :
3197 22 : engraving::TremoloType Convert::stemModFromMEI(const libmei::data_STEMMODIFIER meiStemMod)
3198 : {
3199 22 : switch (meiStemMod) {
3200 5 : case (libmei::STEMMODIFIER_1slash): return engraving::TremoloType::R8;
3201 5 : case (libmei::STEMMODIFIER_2slash): return engraving::TremoloType::R16;
3202 5 : case (libmei::STEMMODIFIER_3slash): return engraving::TremoloType::R32;
3203 5 : case (libmei::STEMMODIFIER_4slash): return engraving::TremoloType::R64;
3204 0 : case (libmei::STEMMODIFIER_5slash): return engraving::TremoloType::R128;
3205 0 : case (libmei::STEMMODIFIER_6slash): return engraving::TremoloType::R256;
3206 2 : case (libmei::STEMMODIFIER_z): return engraving::TremoloType::BUZZ_ROLL;
3207 0 : default:
3208 0 : return engraving::TremoloType::INVALID_TREMOLO;
3209 : }
3210 : }
3211 :
3212 22 : libmei::data_STEMMODIFIER Convert::stemModToMEI(const engraving::TremoloSingleChord* tremolo)
3213 : {
3214 22 : switch (tremolo->tremoloType()) {
3215 5 : case (engraving::TremoloType::R8): return libmei::STEMMODIFIER_1slash;
3216 5 : case (engraving::TremoloType::R16): return libmei::STEMMODIFIER_2slash;
3217 5 : case (engraving::TremoloType::R32): return libmei::STEMMODIFIER_3slash;
3218 5 : case (engraving::TremoloType::R64): return libmei::STEMMODIFIER_4slash;
3219 0 : case (engraving::TremoloType::R128): return libmei::STEMMODIFIER_5slash;
3220 0 : case (engraving::TremoloType::R256): return libmei::STEMMODIFIER_6slash;
3221 2 : case (engraving::TremoloType::BUZZ_ROLL): return libmei::STEMMODIFIER_z;
3222 0 : default:
3223 0 : return libmei::STEMMODIFIER_NONE;
3224 : }
3225 : }
3226 :
3227 211 : void Convert::sylFromMEI(engraving::Lyrics* lyrics, const libmei::Syl& meiSyl, ElisionType elision, bool& warning)
3228 : {
3229 211 : warning = false;
3230 :
3231 211 : if (elision == ElisionLast) {
3232 9 : if (meiSyl.GetWordpos() == libmei::sylLog_WORDPOS_i) {
3233 : // We had previous (the first) syl with a @wordpos terminal
3234 5 : if (lyrics->syllabic() == engraving::LyricsSyllabic::END) {
3235 3 : lyrics->setSyllabic(engraving::LyricsSyllabic::MIDDLE);
3236 : } else {
3237 2 : lyrics->setSyllabic(engraving::LyricsSyllabic::BEGIN);
3238 : }
3239 : }
3240 202 : } else if ((elision == ElisionFirst) || (elision == ElisionNone)) {
3241 199 : switch (meiSyl.GetWordpos()) {
3242 44 : case (libmei::sylLog_WORDPOS_i): lyrics->setSyllabic(engraving::LyricsSyllabic::BEGIN);
3243 44 : break;
3244 17 : case (libmei::sylLog_WORDPOS_m): lyrics->setSyllabic(engraving::LyricsSyllabic::MIDDLE);
3245 17 : break;
3246 49 : case (libmei::sylLog_WORDPOS_t): lyrics->setSyllabic(engraving::LyricsSyllabic::END);
3247 49 : break;
3248 89 : default: break;
3249 : }
3250 : }
3251 211 : }
3252 :
3253 211 : libmei::Syl Convert::sylToMEI(const engraving::Lyrics* lyrics, ElisionType elision)
3254 : {
3255 211 : libmei::Syl meiSyl;
3256 :
3257 211 : switch (lyrics->syllabic()) {
3258 48 : case (engraving::LyricsSyllabic::BEGIN):
3259 48 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_i);
3260 48 : meiSyl.SetCon(libmei::sylLog_CON_d);
3261 48 : break;
3262 26 : case (engraving::LyricsSyllabic::MIDDLE):
3263 26 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_m);
3264 26 : meiSyl.SetCon(libmei::sylLog_CON_d);
3265 26 : break;
3266 49 : case (engraving::LyricsSyllabic::END):
3267 49 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_t);
3268 49 : break;
3269 88 : default:
3270 88 : break;
3271 : }
3272 :
3273 : // Adjust @wordpos and @con with elisions
3274 211 : if (elision == ElisionFirst) {
3275 : // Set the elision connector
3276 9 : meiSyl.SetCon(libmei::sylLog_CON_b);
3277 : // Make middle a terminal and remove initial word position
3278 9 : if (meiSyl.GetWordpos() == libmei::sylLog_WORDPOS_m) {
3279 3 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_t);
3280 6 : } else if (meiSyl.GetWordpos() == libmei::sylLog_WORDPOS_i) {
3281 2 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_NONE);
3282 : }
3283 202 : } else if (elision == ElisionMiddle) {
3284 : // Set the elision connector and remove any word postion
3285 3 : meiSyl.SetCon(libmei::sylLog_CON_b);
3286 3 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_NONE);
3287 199 : } else if (elision == ElisionLast) {
3288 : // Make middle an initial and remove terminal word position
3289 9 : if (meiSyl.GetWordpos() == libmei::sylLog_WORDPOS_m) {
3290 3 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_i);
3291 6 : } else if (meiSyl.GetWordpos() == libmei::sylLog_WORDPOS_t) {
3292 3 : meiSyl.SetWordpos(libmei::sylLog_WORDPOS_NONE);
3293 : }
3294 : }
3295 :
3296 : // Add extender connector
3297 211 : if ((elision == ElisionNone) || (elision == ElisionLast)) {
3298 199 : if ((meiSyl.GetCon() == libmei::sylLog_CON_NONE) && (lyrics->ticks() != engraving::Fraction(0, 1))) {
3299 7 : meiSyl.SetCon(libmei::sylLog_CON_u);
3300 : }
3301 : }
3302 :
3303 211 : return meiSyl;
3304 : }
3305 :
3306 35 : engraving::BracketType Convert::symbolFromMEI(const libmei::staffGroupingSym_SYMBOL meiGrpSym)
3307 : {
3308 35 : switch (meiGrpSym) {
3309 15 : case (libmei::staffGroupingSym_SYMBOL_bracket): return engraving::BracketType::NORMAL;
3310 18 : case (libmei::staffGroupingSym_SYMBOL_brace): return engraving::BracketType::BRACE;
3311 1 : case (libmei::staffGroupingSym_SYMBOL_bracketsq): return engraving::BracketType::SQUARE;
3312 1 : case (libmei::staffGroupingSym_SYMBOL_line): return engraving::BracketType::LINE;
3313 0 : case (libmei::staffGroupingSym_SYMBOL_none): return engraving::BracketType::NO_BRACKET;
3314 0 : default: return engraving::BracketType::NO_BRACKET;
3315 : }
3316 : }
3317 :
3318 35 : libmei::staffGroupingSym_SYMBOL Convert::symbolToMEI(const engraving::BracketType bracket)
3319 : {
3320 35 : switch (bracket) {
3321 15 : case (engraving::BracketType::NORMAL): return libmei::staffGroupingSym_SYMBOL_bracket;
3322 : break;
3323 18 : case (engraving::BracketType::BRACE): return libmei::staffGroupingSym_SYMBOL_brace;
3324 : break;
3325 1 : case (engraving::BracketType::SQUARE): return libmei::staffGroupingSym_SYMBOL_bracketsq;
3326 : break;
3327 1 : case (engraving::BracketType::LINE): return libmei::staffGroupingSym_SYMBOL_line;
3328 : break;
3329 0 : case (engraving::BracketType::NO_BRACKET): return libmei::staffGroupingSym_SYMBOL_none;
3330 : break;
3331 0 : default: return libmei::staffGroupingSym_SYMBOL_NONE;
3332 : }
3333 : }
3334 :
3335 11 : void Convert::tempoFromMEI(engraving::TempoText* tempoText, const StringList& meiLines, const libmei::Tempo& meiTempo, bool& warning)
3336 : {
3337 11 : IF_ASSERT_FAILED(tempoText) {
3338 0 : return;
3339 : }
3340 :
3341 11 : warning = false;
3342 :
3343 : // @place
3344 11 : if (meiTempo.HasPlace()) {
3345 0 : tempoText->setPlacement(meiTempo.GetPlace()
3346 0 : == libmei::STAFFREL_above ? engraving::PlacementV::ABOVE : engraving::PlacementV::BELOW);
3347 0 : tempoText->setPropertyFlags(engraving::Pid::PLACEMENT, engraving::PropertyFlags::UNSTYLED);
3348 : }
3349 :
3350 : // @bmp.midi
3351 11 : if (meiTempo.HasMidiBpm()) {
3352 11 : double tempoValue = meiTempo.GetMidiBpm() / 60;
3353 11 : tempoText->setTempo(tempoValue);
3354 : }
3355 :
3356 : // @type
3357 23 : if (meiTempo.HasType() && Convert::hasTypeValue(meiTempo.GetType(), TEMPO_INFER_FROM_TEXT)) {
3358 6 : tempoText->setFollowText(true);
3359 : }
3360 :
3361 : // @color
3362 11 : Convert::colorFromMEI(tempoText, meiTempo);
3363 :
3364 : // text
3365 11 : tempoText->setXmlText(meiLines.join(u"\n"));
3366 : }
3367 :
3368 11 : libmei::Tempo Convert::tempoToMEI(const engraving::TempoText* tempoText, StringList& meiLines)
3369 : {
3370 11 : libmei::Tempo meiTempo;
3371 :
3372 : // @midi.bpm
3373 11 : engraving::BeatsPerMinute bpm = tempoText->tempo().toBPM();
3374 11 : double bpmRounded = round(bpm.val * 100) / 100;
3375 11 : meiTempo.SetMidiBpm(bpmRounded);
3376 :
3377 : // @place
3378 11 : if (tempoText->propertyFlags(engraving::Pid::PLACEMENT) == engraving::PropertyFlags::UNSTYLED) {
3379 0 : meiTempo.SetPlace(Convert::placeToMEI(tempoText->placement()));
3380 : }
3381 :
3382 : // @type
3383 11 : if (tempoText->followText()) {
3384 18 : meiTempo.SetType(TEMPO_INFER_FROM_TEXT);
3385 : }
3386 :
3387 : // text content - only split lines
3388 11 : meiLines = String(tempoText->plainText()).split(u"\n");
3389 :
3390 : // @staff
3391 11 : Convert::staffIdentToMEI(tempoText, meiTempo);
3392 :
3393 : // @color
3394 11 : Convert::colorToMEI(tempoText, meiTempo);
3395 :
3396 11 : return meiTempo;
3397 0 : }
3398 :
3399 161 : engraving::TextStyleType Convert::textFromMEI(const libmei::Rend& meiRend, bool& warning)
3400 : {
3401 161 : warning = false;
3402 :
3403 161 : std::string rendType = meiRend.GetType();
3404 161 : engraving::TextStyleType textStyle = engraving::TextStyleType::DEFAULT;
3405 161 : if (rendType.size() > 0) {
3406 161 : textStyle = engraving::TConv::fromXml(rendType, engraving::TextStyleType::DEFAULT);
3407 : }
3408 :
3409 161 : if (textStyle == engraving::TextStyleType::DEFAULT) {
3410 0 : warning = true;
3411 0 : textStyle = engraving::TextStyleType::TITLE;
3412 : }
3413 :
3414 161 : return textStyle;
3415 161 : }
3416 :
3417 161 : std::tuple<libmei::Rend, TextCell, String> Convert::textToMEI(const engraving::Text* text)
3418 : {
3419 161 : libmei::Rend meiRend;
3420 161 : TextCell cell = MiddleCenter;
3421 161 : String string = text->plainText();
3422 :
3423 161 : libmei::data_FONTSIZE fontsize;
3424 :
3425 : /**
3426 : Use default style placements.
3427 : We could use at the style actual values eventually, even though that would be more complicated to get back in
3428 : */
3429 161 : switch (text->textStyleType()) {
3430 64 : case (engraving::TextStyleType::TITLE):
3431 64 : cell = TopCenter;
3432 64 : fontsize.SetTerm(libmei::FONTSIZETERM_x_large);
3433 64 : break;
3434 42 : case (engraving::TextStyleType::SUBTITLE):
3435 42 : cell = TopCenter;
3436 42 : fontsize.SetTerm(libmei::FONTSIZETERM_large);
3437 42 : break;
3438 53 : case (engraving::TextStyleType::COMPOSER):
3439 53 : cell = BottomRight;
3440 53 : break;
3441 1 : case (engraving::TextStyleType::LYRICIST):
3442 1 : cell = BottomLeft;
3443 1 : break;
3444 1 : case (engraving::TextStyleType::INSTRUMENT_EXCERPT):
3445 1 : cell = TopLeft;
3446 1 : break;
3447 0 : default: cell = MiddleCenter;
3448 : }
3449 :
3450 161 : meiRend.SetFontsize(fontsize);
3451 :
3452 : // @label (@lang because not available in MEI Basic
3453 : // This is what allows for reading pgHead back as VBox
3454 161 : AsciiStringView rendType = engraving::TConv::toXml(text->textStyleType());
3455 161 : meiRend.SetType(rendType.ascii());
3456 :
3457 322 : return { meiRend, cell, string };
3458 161 : }
3459 :
3460 : /**
3461 : * Convert the segmented text block into MuseScore xmlText (with <sym>)
3462 : * The text block are {bool, string} pairs with true for smufl and false for plain text
3463 : */
3464 :
3465 214 : void Convert::textFromMEI(String& text, const textWithSmufl& textBlocks)
3466 : {
3467 214 : text.clear();
3468 :
3469 462 : for (auto& block : textBlocks) {
3470 248 : if (!block.first) {
3471 227 : text += block.second;
3472 : } else {
3473 42 : for (size_t i = 0; i < block.second.size(); i++) {
3474 21 : char16_t c = block.second.at(i).unicode();
3475 21 : if (c < u'\uE000' || c > u'\uF8FF') {
3476 0 : continue; // this should not happen because the char should be smufl
3477 : }
3478 21 : engraving::SymId symId = engravingFonts()->fallbackFont()->fromCode(c);
3479 21 : if (symId == engraving::SymId::noSym) {
3480 0 : continue; // smufl code not found
3481 : }
3482 21 : text += u"<sym>" + String::fromAscii(engraving::SymNames::nameForSymId(symId).ascii()) + u"</sym>";
3483 : }
3484 : }
3485 : }
3486 214 : }
3487 :
3488 : /**
3489 : * Convert a MuseScore plainText (without <sym>) into text blocks
3490 : * The text block are {bool, string} pairs with true for smufl and false for plain text
3491 : */
3492 :
3493 211 : void Convert::textToMEI(textWithSmufl& textBlocks, const String& text)
3494 : {
3495 : // Status of what is being parsed
3496 211 : bool isSmufl = false;
3497 :
3498 211 : String smuflBlock;
3499 211 : String textBlock;
3500 :
3501 : // Go through the text char by char and build blocks of plain text / smufl text
3502 884 : for (size_t i = 0; i < text.size(); i++) {
3503 673 : char16_t c = text.at(i).unicode();
3504 : // Not SMuFL
3505 673 : if (c < u'\uE000' || c > u'\uF8FF') {
3506 : // Changing to plain text, add the current smufl block if something in it
3507 652 : if (isSmufl && smuflBlock.size() > 0) {
3508 19 : textBlocks.push_back(std::make_pair(true, smuflBlock));
3509 19 : smuflBlock.clear();
3510 : }
3511 652 : textBlock += c;
3512 652 : isSmufl = false;
3513 : }
3514 : // SMuFL
3515 : else {
3516 : // Changing to smufl, add the current plain text block if something is in it
3517 21 : if (!isSmufl && textBlock.size() > 0) {
3518 15 : textBlocks.push_back(std::make_pair(false, textBlock));
3519 15 : textBlock.clear();
3520 : }
3521 21 : smuflBlock += c;
3522 21 : isSmufl = true;
3523 : }
3524 : }
3525 : // Add the last block
3526 211 : if (textBlock.size() > 0) {
3527 209 : textBlocks.push_back(std::make_pair(false, textBlock));
3528 : }
3529 211 : if (smuflBlock.size() > 0) {
3530 2 : textBlocks.push_back(std::make_pair(true, smuflBlock));
3531 : }
3532 211 : }
3533 :
3534 30 : void Convert::tieFromMEI(engraving::SlurTie* tie, const libmei::Tie& meiTie, bool& warning)
3535 : {
3536 30 : libmei::Slur meiSlur;
3537 30 : meiSlur.SetCurvedir(meiTie.GetCurvedir());
3538 30 : meiSlur.SetLform(meiTie.GetLform());
3539 30 : meiSlur.SetColor(meiTie.GetColor());
3540 30 : Convert::slurFromMEI(tie, meiSlur, warning);
3541 30 : }
3542 :
3543 36 : libmei::Tie Convert::tieToMEI(const engraving::SlurTie* tie)
3544 : {
3545 36 : libmei::Slur meiSlur = Convert::slurToMEI(tie);
3546 36 : libmei::Tie meiTie;
3547 36 : meiTie.SetCurvedir(meiSlur.GetCurvedir());
3548 36 : meiTie.SetLform(meiSlur.GetLform());
3549 36 : meiTie.SetColor(meiSlur.GetColor());
3550 36 : return meiTie;
3551 36 : }
3552 :
3553 9 : Convert::OrnamStruct Convert::trillFromMEI(engraving::Ornament* ornament, const libmei::Trill& meiTrill, bool& warning)
3554 : {
3555 : // @glyph.name
3556 9 : bool smufl = (meiTrill.HasGlyphAuth() && (meiTrill.GetGlyphAuth() == SMUFL_AUTH));
3557 :
3558 9 : engraving::SymId symId = engraving::SymId::ornamentTrill;
3559 :
3560 : // We give @glyph.name (or @glyph.num) priority over @form and @long
3561 9 : if (smufl && meiTrill.HasGlyphName()) {
3562 2 : symId = engraving::SymNames::symIdByName(String(meiTrill.GetGlyphName().c_str()));
3563 2 : if (symId == engraving::SymId::noSym) {
3564 0 : warning = true;
3565 : }
3566 : }
3567 : // This is for loading MEI files not written by MuseScore and that use @glyph.num instead of @glyph.name
3568 7 : else if (smufl && meiTrill.HasGlyphNum()) {
3569 0 : symId = engravingFonts()->fallbackFont()->fromCode(meiTrill.GetGlyphNum());
3570 0 : if (symId == engraving::SymId::noSym) {
3571 0 : warning = true;
3572 : }
3573 : }
3574 :
3575 9 : ornament->setSymId(symId);
3576 :
3577 : // @color
3578 9 : Convert::colorFromMEI(ornament, meiTrill);
3579 :
3580 : // Other attributes
3581 9 : return Convert::ornamFromMEI(ornament, meiTrill, warning);
3582 : }
3583 :
3584 9 : libmei::Trill Convert::trillToMEI(const engraving::Ornament* ornament)
3585 : {
3586 9 : libmei::Trill meiTrill;
3587 :
3588 9 : Convert::ornamToMEI(ornament, meiTrill);
3589 :
3590 : // @glyph.name
3591 9 : if (ornament->symId() != engraving::SymId::ornamentTrill) {
3592 2 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(ornament->symId());
3593 4 : meiTrill.SetGlyphName(glyphName.ascii());
3594 6 : meiTrill.SetGlyphAuth(SMUFL_AUTH);
3595 : }
3596 :
3597 : // @color
3598 9 : Convert::colorToMEI(ornament, meiTrill);
3599 :
3600 9 : return meiTrill;
3601 0 : }
3602 :
3603 41 : void Convert::tupletFromMEI(engraving::Tuplet* tuplet, const libmei::Tuplet& meiTuplet, bool& warning)
3604 : {
3605 41 : IF_ASSERT_FAILED(tuplet) {
3606 0 : return;
3607 : }
3608 :
3609 41 : warning = false;
3610 41 : if (!meiTuplet.HasNum() || !meiTuplet.HasNumbase()) {
3611 0 : warning = true;
3612 : } else {
3613 41 : tuplet->setRatio(engraving::Fraction(meiTuplet.GetNum(), meiTuplet.GetNumbase()));
3614 : }
3615 :
3616 41 : if (meiTuplet.GetNumFormat() == libmei::tupletVis_NUMFORMAT_ratio) {
3617 3 : tuplet->setNumberType(engraving::TupletNumberType::SHOW_RELATION);
3618 3 : tuplet->setPropertyFlags(engraving::Pid::NUMBER_TYPE, engraving::PropertyFlags::UNSTYLED);
3619 38 : } else if (meiTuplet.GetNumVisible() == libmei::BOOLEAN_false) {
3620 2 : tuplet->setNumberType(engraving::TupletNumberType::NO_TEXT);
3621 2 : tuplet->setPropertyFlags(engraving::Pid::NUMBER_TYPE, engraving::PropertyFlags::UNSTYLED);
3622 : }
3623 :
3624 41 : if (meiTuplet.GetBracketVisible() == libmei::BOOLEAN_true) {
3625 3 : tuplet->setBracketType(engraving::TupletBracketType::SHOW_BRACKET);
3626 3 : tuplet->setPropertyFlags(engraving::Pid::BRACKET_TYPE, engraving::PropertyFlags::UNSTYLED);
3627 38 : } else if (meiTuplet.GetBracketVisible() == libmei::BOOLEAN_false) {
3628 2 : tuplet->setBracketType(engraving::TupletBracketType::SHOW_NO_BRACKET);
3629 2 : tuplet->setPropertyFlags(engraving::Pid::BRACKET_TYPE, engraving::PropertyFlags::UNSTYLED);
3630 : }
3631 :
3632 41 : libmei::data_STAFFREL_basic bracketPlace = meiTuplet.GetBracketPlace();
3633 41 : libmei::data_STAFFREL_basic numPlace = meiTuplet.GetNumPlace();
3634 41 : if ((bracketPlace == libmei::STAFFREL_basic_above) || (numPlace == libmei::STAFFREL_basic_above)) {
3635 2 : tuplet->setDirection(engraving::DirectionV::UP);
3636 2 : tuplet->setPropertyFlags(engraving::Pid::DIRECTION, engraving::PropertyFlags::UNSTYLED);
3637 39 : } else if ((bracketPlace == libmei::STAFFREL_basic_below) || (numPlace == libmei::STAFFREL_basic_below)) {
3638 3 : tuplet->setDirection(engraving::DirectionV::DOWN);
3639 3 : tuplet->setPropertyFlags(engraving::Pid::DIRECTION, engraving::PropertyFlags::UNSTYLED);
3640 : }
3641 :
3642 : // @color
3643 41 : Convert::colorFromMEI(tuplet, meiTuplet);
3644 : }
3645 :
3646 41 : libmei::Tuplet Convert::tupletToMEI(const engraving::Tuplet* tuplet)
3647 : {
3648 41 : libmei::Tuplet meiTuplet;
3649 :
3650 41 : meiTuplet.SetNum(tuplet->ratio().numerator());
3651 41 : meiTuplet.SetNumbase(tuplet->ratio().denominator());
3652 :
3653 41 : if (tuplet->numberType() == engraving::TupletNumberType::SHOW_RELATION) {
3654 3 : meiTuplet.SetNumFormat(libmei::tupletVis_NUMFORMAT_ratio);
3655 38 : } else if (tuplet->numberType() == engraving::TupletNumberType::NO_TEXT) {
3656 2 : meiTuplet.SetNumVisible(libmei::BOOLEAN_false);
3657 : }
3658 :
3659 41 : if (tuplet->bracketType() == engraving::TupletBracketType::SHOW_NO_BRACKET) {
3660 2 : meiTuplet.SetBracketVisible(libmei::BOOLEAN_false);
3661 39 : } else if (tuplet->bracketType() == engraving::TupletBracketType::SHOW_BRACKET) {
3662 3 : meiTuplet.SetBracketVisible(libmei::BOOLEAN_true);
3663 : }
3664 :
3665 41 : if (tuplet->direction() == engraving::DirectionV::UP) {
3666 2 : meiTuplet.SetBracketPlace(libmei::STAFFREL_basic_above);
3667 2 : meiTuplet.SetNumPlace(libmei::STAFFREL_basic_above);
3668 39 : } else if (tuplet->direction() == engraving::DirectionV::DOWN) {
3669 3 : meiTuplet.SetBracketPlace(libmei::STAFFREL_basic_below);
3670 3 : meiTuplet.SetNumPlace(libmei::STAFFREL_basic_below);
3671 : }
3672 :
3673 : // @color
3674 41 : Convert::colorToMEI(tuplet, meiTuplet);
3675 :
3676 41 : return meiTuplet;
3677 0 : }
3678 :
3679 6 : Convert::OrnamStruct Convert::turnFromMEI(engraving::Ornament* ornament, const libmei::Turn& meiTurn, bool& warning)
3680 : {
3681 : // @glyph.name
3682 6 : bool smufl = (meiTurn.HasGlyphAuth() && (meiTurn.GetGlyphAuth() == SMUFL_AUTH));
3683 :
3684 6 : engraving::SymId symId = engraving::SymId::ornamentTurn;
3685 :
3686 : // We give @glyph.name (or @glyph.num) priority over @form and @long
3687 6 : if (smufl && meiTurn.HasGlyphName()) {
3688 1 : symId = engraving::SymNames::symIdByName(String(meiTurn.GetGlyphName().c_str()));
3689 1 : if (symId == engraving::SymId::noSym) {
3690 0 : warning = true;
3691 : }
3692 : }
3693 : // This is for loading MEI files not written by MuseScore and that use @glyph.num instead of @glyph.name
3694 5 : else if (smufl && meiTurn.HasGlyphNum()) {
3695 0 : symId = engravingFonts()->fallbackFont()->fromCode(meiTurn.GetGlyphNum());
3696 0 : if (symId == engraving::SymId::noSym) {
3697 0 : warning = true;
3698 : }
3699 : } else {
3700 5 : if (meiTurn.HasForm()) {
3701 5 : if (meiTurn.GetForm() == libmei::turnLog_FORM_lower) {
3702 3 : symId = engraving::SymId::ornamentTurnInverted;
3703 : }
3704 : }
3705 : }
3706 :
3707 6 : ornament->setSymId(symId);
3708 :
3709 : // Other attributes
3710 6 : return Convert::ornamFromMEI(ornament, meiTurn, warning);
3711 : }
3712 :
3713 6 : libmei::Turn Convert::turnToMEI(const engraving::Ornament* ornament)
3714 : {
3715 6 : libmei::Turn meiTurn;
3716 :
3717 6 : Convert::ornamToMEI(ornament, meiTurn);
3718 :
3719 : // @form
3720 6 : switch (ornament->symId()) {
3721 3 : case (engraving::SymId::ornamentTurn):
3722 3 : case (engraving::SymId::ornamentTurnSlash): meiTurn.SetForm(libmei::turnLog_FORM_upper);
3723 3 : break;
3724 3 : case (engraving::SymId::ornamentTurnInverted): meiTurn.SetForm(libmei::turnLog_FORM_lower);
3725 3 : break;
3726 0 : default: break;
3727 : }
3728 :
3729 : // @glyph.name
3730 6 : if (ornament->symId() == engraving::SymId::ornamentTurnSlash) {
3731 1 : AsciiStringView glyphName = engraving::SymNames::nameForSymId(ornament->symId());
3732 2 : meiTurn.SetGlyphName(glyphName.ascii());
3733 3 : meiTurn.SetGlyphAuth(SMUFL_AUTH);
3734 : }
3735 :
3736 6 : return meiTurn;
3737 0 : }
3738 :
3739 4895 : bool Convert::hasTypeValue(const std::string& typeStr, const std::string& value)
3740 : {
3741 4895 : std::istringstream iss(typeStr);
3742 :
3743 4895 : std::string token;
3744 5037 : while (std::getline(iss, token, ' ')) {
3745 295 : if (token == value) {
3746 153 : return true; // value found
3747 : }
3748 : }
3749 :
3750 4742 : return false;
3751 4895 : }
3752 :
3753 18 : bool Convert::getTypeValueWithPrefix(const std::string& typeStr, const std::string& prefix, std::string& value)
3754 : {
3755 18 : std::istringstream iss(typeStr);
3756 18 : std::list<std::string> values;
3757 :
3758 18 : std::string token;
3759 27 : while (std::getline(iss, token, ' ')) {
3760 19 : if ((token.rfind(prefix, 0) == 0) && (prefix.size() < token.size())) {
3761 10 : value = token.erase(0, prefix.length());
3762 10 : return true;
3763 : }
3764 : }
3765 :
3766 8 : return false;
3767 18 : }
3768 :
3769 : /**
3770 : * Extract the list of values in a @type attribute having a prefix string
3771 : * For example, "mscore-ending-1 primary mscore-ending-3" return ["1", "3"] with prefix "mscore-ending-"
3772 : */
3773 :
3774 26 : std::list<std::string> Convert::getTypeValuesWithPrefix(const std::string& typeStr, const std::string& prefix)
3775 : {
3776 26 : std::istringstream iss(typeStr);
3777 26 : std::list<std::string> values;
3778 :
3779 26 : std::string token;
3780 82 : while (std::getline(iss, token, ' ')) {
3781 30 : if ((token.rfind(prefix, 0) == 0) && (prefix.size() < token.size())) {
3782 30 : values.push_back(token.erase(0, prefix.length()));
3783 : }
3784 : }
3785 :
3786 26 : return values;
3787 26 : }
3788 :
3789 16 : void Convert::layerIdentFromMEI(engraving::EngravingItem* item, const libmei::Element& meiElement)
3790 : {
3791 16 : if (!item->hasVoiceAssignmentProperties()) {
3792 0 : return;
3793 : }
3794 :
3795 16 : const libmei::AttLayerIdent* layerAtt = dynamic_cast<const libmei::AttLayerIdent*>(&meiElement);
3796 :
3797 16 : IF_ASSERT_FAILED(layerAtt) {
3798 0 : return;
3799 : }
3800 :
3801 16 : if (layerAtt->HasLayer()) {
3802 : // without further check we assume the layer to match
3803 1 : item->setProperty(engraving::Pid::VOICE_ASSIGNMENT, engraving::VoiceAssignment::CURRENT_VOICE_ONLY);
3804 : }
3805 : }
3806 :
3807 16 : void Convert::layerIdentToMEI(const engraving::EngravingItem* item, libmei::Element& meiElement)
3808 : {
3809 16 : libmei::AttLayerIdent* layerAtt = dynamic_cast<libmei::AttLayerIdent*>(&meiElement);
3810 :
3811 16 : IF_ASSERT_FAILED(layerAtt) {
3812 0 : return;
3813 : }
3814 :
3815 48 : if (item->hasVoiceAssignmentProperties()
3816 16 : && (item->getProperty(engraving::Pid::VOICE_ASSIGNMENT).value<engraving::VoiceAssignment>()
3817 : == engraving::VoiceAssignment::CURRENT_VOICE_ONLY)) {
3818 1 : layerAtt->SetLayer(static_cast<int>(item->voice()) + 1);
3819 : }
3820 : }
3821 :
3822 70 : void Convert::staffIdentToMEI(const engraving::EngravingItem* item, libmei::Element& meiElement)
3823 : {
3824 70 : libmei::AttStaffIdent* staffAtt = dynamic_cast<libmei::AttStaffIdent*>(&meiElement);
3825 :
3826 70 : IF_ASSERT_FAILED(staffAtt) {
3827 0 : return;
3828 : }
3829 :
3830 70 : libmei::xsdPositiveInteger_List staffList;
3831 70 : staffList.push_back(static_cast<int>(item->staff()->idx()) + 1);
3832 : // TODO: add staff number if centered between staves
3833 70 : staffAtt->SetStaff(staffList);
3834 70 : }
3835 :
3836 16 : double Convert::tstampFromFraction(const engraving::Fraction& fraction, const engraving::Fraction& timesig)
3837 : {
3838 16 : return (double)fraction.numerator() / fraction.denominator() * timesig.denominator() + 1.0;
3839 : }
3840 :
3841 : /**
3842 : * Approximate a fraction for an MEI timestamp (double) values
3843 : * From https://stackoverflow.com/questions/26643695/
3844 : */
3845 :
3846 16 : engraving::Fraction Convert::tstampToFraction(double tstamp, const engraving::Fraction& timesig)
3847 : {
3848 : // Value is -1.0 because MEI time stamps are one-based
3849 : // However, make sure it is not smaller than 0.0, which means that a tstamp 0.0 is moved to 1.0 (the first note)
3850 16 : tstamp = std::max(tstamp - 1.0, 0.0);
3851 :
3852 16 : const int cycles = 10;
3853 16 : const double precision = 0.01;
3854 :
3855 16 : int sign = tstamp > 0 ? 1 : -1;
3856 16 : tstamp = tstamp * sign; //abs(number);
3857 : double new_number, whole_part;
3858 16 : double decimal_part = tstamp - (int)tstamp;
3859 16 : int counter = 0;
3860 :
3861 16 : std::valarray<double> vec_1{ double((int)tstamp), 1 }, vec_2{ 1, 0 }, temporary;
3862 :
3863 16 : while (decimal_part > precision && counter < cycles) {
3864 0 : new_number = 1 / decimal_part;
3865 0 : whole_part = (int)new_number;
3866 :
3867 0 : temporary = vec_1;
3868 0 : vec_1 = whole_part * vec_1 + vec_2;
3869 0 : vec_2 = temporary;
3870 :
3871 0 : decimal_part = new_number - whole_part;
3872 0 : counter += 1;
3873 : }
3874 :
3875 32 : return engraving::Fraction(sign * vec_1[0], vec_1[1]) / timesig.denominator();
3876 16 : }
3877 :
3878 : /**
3879 : * Return a static instance of the register.
3880 : */
3881 :
3882 128 : UIDRegister* UIDRegister::instance()
3883 : {
3884 128 : static UIDRegister uidRegister;
3885 128 : return &uidRegister;
3886 : }
|