LCOV - code coverage report
Current view: top level - src/importexport/mei/internal - meiconverter.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 83.0 % 2236 1856
Test Date: 2026-11-05 04:07:02

            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              : }
        

Generated by: LCOV version 2.0-1