LCOV - code coverage report
Current view: top level - src/importexport/musicxml/internal/shared - musicxmlsupport.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 26.1 % 418 109
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              : /**
      24              :  MusicXML support.
      25              :  */
      26              : 
      27              : #include "musicxmlsupport.h"
      28              : #include "global/serialization/xmlstreamreader.h"
      29              : 
      30              : #include "translation.h"
      31              : #include "engraving/dom/accidental.h"
      32              : #include "engraving/dom/chordlist.h"
      33              : #include "engraving/dom/harmony.h"
      34              : #include "engraving/dom/score.h"
      35              : #include "engraving/dom/staff.h"
      36              : #include "engraving/types/symnames.h"
      37              : #include "engraving/types/types.h"
      38              : 
      39              : using namespace muse;
      40              : using namespace mu::engraving;
      41              : 
      42              : namespace mu::iex::musicxml {
      43              : //---------------------------------------------------------
      44              : //   errorStringWithLocation
      45              : //---------------------------------------------------------
      46              : 
      47            0 : String errorStringWithLocation(int64_t byteOffset, const String& error)
      48              : {
      49            0 :     return muse::mtrc("iex_musicxml", "byte offset %1:").arg(byteOffset) + u" " + error;
      50              : }
      51              : 
      52              : //---------------------------------------------------------
      53              : //   checkAtEndElement
      54              : //---------------------------------------------------------
      55              : 
      56        22366 : muse::String checkAtEndElement(const muse::XmlStreamReader& e, const muse::String& expName)
      57              : {
      58        22366 :     if (e.isEndElement() && e.name() == expName.toAscii().constChar()) {
      59        22366 :         return String();
      60              :     }
      61              : 
      62            0 :     String res = muse::mtrc("iex_musicxml", "expected token type and name ‘EndElement %1’, actual ‘%2 %3’")
      63            0 :                  .arg(expName)
      64            0 :                  .arg(muse::String::fromAscii(e.tokenString().ascii()))
      65            0 :                  .arg(muse::String::fromAscii(e.name().ascii()));
      66            0 :     return res;
      67            0 : }
      68              : 
      69              : //---------------------------------------------------------
      70              : //   stringToInt
      71              : //---------------------------------------------------------
      72              : 
      73              : /**
      74              :  Convert a string in \a s into an int. Set *ok to true if conversion was
      75              :  successful. \a s may end with ".0", as is generated by Audiveris 3.2 and up,
      76              :  in elements <divisions>, <duration>, <alter> and <sound> attributes
      77              :  dynamics and tempo.
      78              :  In case of error val return a default value of 0.
      79              :  Note that non-integer values cannot be handled by mscore.
      80              :  */
      81              : 
      82          351 : int MusicXmlSupport::stringToInt(const String& s, bool* ok)
      83              : {
      84          351 :     int res = 0;
      85          351 :     String str = s;
      86          351 :     if (s.endsWith(u".0")) {
      87            0 :         str = s.left(s.size() - 2);
      88              :     }
      89          351 :     res = str.toInt(ok);
      90          351 :     return res;
      91          351 : }
      92              : 
      93              : //---------------------------------------------------------
      94              : //   noteTypeToFraction
      95              : //---------------------------------------------------------
      96              : 
      97              : /**
      98              :  Convert MusicXML note type to fraction.
      99              :  */
     100              : 
     101            0 : Fraction MusicXmlSupport::noteTypeToFraction(const String& type)
     102              : {
     103            0 :     if (type == u"1024th") {
     104            0 :         return Fraction(1, 1024);
     105            0 :     } else if (type == u"512th") {
     106            0 :         return Fraction(1, 512);
     107            0 :     } else if (type == u"256th") {
     108            0 :         return Fraction(1, 256);
     109            0 :     } else if (type == u"128th") {
     110            0 :         return Fraction(1, 128);
     111            0 :     } else if (type == u"64th") {
     112            0 :         return Fraction(1, 64);
     113            0 :     } else if (type == u"32nd") {
     114            0 :         return Fraction(1, 32);
     115            0 :     } else if (type == u"16th") {
     116            0 :         return Fraction(1, 16);
     117            0 :     } else if (type == u"eighth") {
     118            0 :         return Fraction(1, 8);
     119            0 :     } else if (type == u"quarter") {
     120            0 :         return Fraction(1, 4);
     121            0 :     } else if (type == u"half") {
     122            0 :         return Fraction(1, 2);
     123            0 :     } else if (type == u"whole") {
     124            0 :         return Fraction(1, 1);
     125            0 :     } else if (type == u"breve") {
     126            0 :         return Fraction(2, 1);
     127            0 :     } else if (type == u"long") {
     128            0 :         return Fraction(4, 1);
     129            0 :     } else if (type == u"maxima") {
     130            0 :         return Fraction(8, 1);
     131              :     } else {
     132            0 :         return Fraction(0, 0);
     133              :     }
     134              : }
     135              : 
     136              : //---------------------------------------------------------
     137              : //   calculateFraction
     138              : //---------------------------------------------------------
     139              : 
     140              : /**
     141              :  Convert note type, number of dots and actual and normal notes into a duration
     142              :  */
     143              : 
     144            0 : Fraction MusicXmlSupport::calculateFraction(const String& type, int dots, int normalNotes, int actualNotes)
     145              : {
     146              :     // type
     147            0 :     Fraction f = MusicXmlSupport::noteTypeToFraction(type);
     148            0 :     if (f.isValid()) {
     149              :         // dot(s)
     150            0 :         Fraction f_no_dots = f;
     151            0 :         for (int i = 0; i < dots; ++i) {
     152            0 :             f += (f_no_dots / Fraction(2 << i, 1));
     153              :         }
     154              :         // tuplet
     155            0 :         if (actualNotes > 0 && normalNotes > 0) {
     156            0 :             f *= normalNotes;
     157            0 :             f /= Fraction(actualNotes, 1);
     158              :         }
     159              :         // clean up (just in case)
     160            0 :         f.reduce();
     161              :     }
     162            0 :     return f;
     163              : }
     164              : 
     165              : //---------------------------------------------------------
     166              : //   accSymId2MusicXmlString
     167              : //---------------------------------------------------------
     168              : 
     169           24 : String accSymId2MusicXmlString(const SymId id)
     170              : {
     171           24 :     String s;
     172           24 :     switch (id) {
     173            1 :     case SymId::accidentalSharp:                 s = u"sharp";
     174            1 :         break;
     175            0 :     case SymId::accidentalNatural:               s = u"natural";
     176            0 :         break;
     177            1 :     case SymId::accidentalFlat:                  s = u"flat";
     178            1 :         break;
     179            8 :     case SymId::accidentalDoubleSharp:           s = u"double-sharp";
     180            8 :         break;
     181            0 :     case SymId::accidentalSharpSharp:           s = u"sharp-sharp";
     182            0 :         break;
     183              :     //case SymId::accidentalDoubleFlat:            s = u"double-flat"; break; // doesn't exist in MusicXML, but see below
     184            8 :     case SymId::accidentalDoubleFlat:            s = u"flat-flat";
     185            8 :         break;
     186            0 :     case SymId::accidentalNaturalSharp:          s = u"natural-sharp";
     187            0 :         break;
     188            0 :     case SymId::accidentalNaturalFlat:           s = u"natural-flat";
     189            0 :         break;
     190            1 :     case SymId::accidentalQuarterToneFlatStein:  s = u"quarter-flat";
     191            1 :         break;
     192            1 :     case SymId::accidentalQuarterToneSharpStein: s = u"quarter-sharp";
     193            1 :         break;
     194            0 :     case SymId::accidentalThreeQuarterTonesFlatZimmermann: s = u"three-quarters-flat";
     195            0 :         break;
     196              :     //case SymId::noSym:                                     s = u"three-quarters-flat";  break; // AccidentalType::FLAT_FLAT_SLASH, MuseScore 1?
     197            0 :     case SymId::accidentalThreeQuarterTonesSharpStein:     s = u"three-quarters-sharp";
     198            0 :         break;
     199            0 :     case SymId::accidentalQuarterToneSharpArrowDown:       s = u"sharp-down";
     200            0 :         break;
     201            0 :     case SymId::accidentalThreeQuarterTonesSharpArrowUp:   s = u"sharp-up";
     202            0 :         break;
     203            0 :     case SymId::accidentalQuarterToneFlatNaturalArrowDown: s = u"natural-down";
     204            0 :         break;
     205            0 :     case SymId::accidentalQuarterToneSharpNaturalArrowUp:  s = u"natural-up";
     206            0 :         break;
     207            0 :     case SymId::accidentalThreeQuarterTonesFlatArrowDown:  s = u"flat-down";
     208            0 :         break;
     209            0 :     case SymId::accidentalQuarterToneFlatArrowUp:          s = u"flat-up";
     210            0 :         break;
     211            0 :     case SymId::accidentalThreeQuarterTonesSharpArrowDown: s = u"double-sharp-down";
     212            0 :         break;
     213            0 :     case SymId::accidentalFiveQuarterTonesSharpArrowUp:    s = u"double-sharp-up";
     214            0 :         break;
     215            0 :     case SymId::accidentalFiveQuarterTonesFlatArrowDown:   s = u"flat-flat-down";
     216            0 :         break;
     217            0 :     case SymId::accidentalThreeQuarterTonesFlatArrowUp:    s = u"flat-flat-up";
     218            0 :         break;
     219              : 
     220            0 :     case SymId::accidentalArrowDown:             s = u"arrow-down";
     221            0 :         break;
     222            0 :     case SymId::accidentalArrowUp:               s = u"arrow-up";
     223            0 :         break;
     224              : 
     225            0 :     case SymId::accidentalTripleSharp:           s = u"triple-sharp";
     226            0 :         break;
     227            0 :     case SymId::accidentalTripleFlat:            s = u"triple-flat";
     228            0 :         break;
     229              : 
     230            1 :     case SymId::accidentalKucukMucennebSharp:    s = u"slash-quarter-sharp";
     231            1 :         break;
     232            1 :     case SymId::accidentalBuyukMucennebSharp:    s = u"slash-sharp";
     233            1 :         break;
     234            1 :     case SymId::accidentalBakiyeFlat:            s = u"slash-flat";
     235            1 :         break;
     236            1 :     case SymId::accidentalBuyukMucennebFlat:     s = u"double-slash-flat";
     237            1 :         break;
     238              : 
     239            0 :     case SymId::accidental1CommaSharp:           s = u"sharp-1";
     240            0 :         break;
     241            0 :     case SymId::accidental2CommaSharp:           s = u"sharp-2";
     242            0 :         break;
     243            0 :     case SymId::accidental3CommaSharp:           s = u"sharp-3";
     244            0 :         break;
     245            0 :     case SymId::accidental5CommaSharp:           s = u"sharp-5";
     246            0 :         break;
     247            0 :     case SymId::accidental1CommaFlat:            s = u"flat-1";
     248            0 :         break;
     249            0 :     case SymId::accidental2CommaFlat:            s = u"flat-2";
     250            0 :         break;
     251            0 :     case SymId::accidental3CommaFlat:            s = u"flat-3";
     252            0 :         break;
     253            0 :     case SymId::accidental4CommaFlat:            s = u"flat-4";
     254            0 :         break;
     255              : 
     256            0 :     case SymId::accidentalSori:                  s = u"sori";
     257            0 :         break;
     258            0 :     case SymId::accidentalKoron:                 s = u"koron";
     259            0 :         break;
     260            0 :     default:
     261            0 :         s = u"other";
     262            0 :         LOGD("accSymId2MusicXmlString: unknown accidental %d", static_cast<int>(id));
     263              :     }
     264           24 :     return s;
     265            0 : }
     266              : 
     267              : //---------------------------------------------------------
     268              : //   accSymId2SmuflMusicXmlString
     269              : //---------------------------------------------------------
     270              : 
     271            0 : String accSymId2SmuflMusicXmlString(const SymId id)
     272              : {
     273            0 :     return String::fromAscii(SymNames::nameForSymId(id).ascii());
     274              : }
     275              : 
     276              : //---------------------------------------------------------
     277              : //   musicXmlString2accSymId
     278              : // see https://github.com/w3c/musicxml/blob/6e3a667b85855b04d7e4548ea508b537bc29fc52/schema/musicxml.xsd#L1392-L1439
     279              : //---------------------------------------------------------
     280              : 
     281           24 : SymId musicXmlString2accSymId(const String mxmlName, const String smufl)
     282              : {
     283              :     // map MusicXML accidental name to MuseScore enum SymId
     284              :     static const std::map<String, SymId> map {
     285            0 :         { u"sharp", SymId::accidentalSharp },
     286            0 :         { u"natural", SymId::accidentalNatural },
     287            0 :         { u"flat", SymId::accidentalFlat },
     288            0 :         { u"double-sharp", SymId::accidentalDoubleSharp },
     289            0 :         { u"sharp-sharp", SymId::accidentalSharpSharp },
     290              :         //{ u"double-flat", SymId::accidentalDoubleFlat }, // shouldn't harm, but doesn't exist in MusicXML
     291            0 :         { u"flat-flat", SymId::accidentalDoubleFlat },
     292            0 :         { u"natural-sharp", SymId::accidentalNaturalSharp },
     293            0 :         { u"natural-flat", SymId::accidentalNaturalFlat },
     294              : 
     295            0 :         { u"quarter-flat", SymId::accidentalQuarterToneFlatStein },
     296            0 :         { u"quarter-sharp", SymId::accidentalQuarterToneSharpStein },
     297            0 :         { u"three-quarters-flat", SymId::accidentalThreeQuarterTonesFlatZimmermann },
     298            0 :         { u"three-quarters-sharp", SymId::accidentalThreeQuarterTonesSharpStein },
     299              : 
     300            0 :         { u"sharp-down", SymId::accidentalQuarterToneSharpArrowDown },
     301            0 :         { u"sharp-up", SymId::accidentalThreeQuarterTonesSharpArrowUp },
     302            0 :         { u"natural-down", SymId::accidentalQuarterToneFlatNaturalArrowDown },
     303            0 :         { u"natural-up", SymId::accidentalQuarterToneSharpNaturalArrowUp },
     304            0 :         { u"flat-down", SymId::accidentalThreeQuarterTonesFlatArrowDown },
     305            0 :         { u"flat-up", SymId::accidentalQuarterToneFlatArrowUp },
     306            0 :         { u"double-sharp-down", SymId::accidentalThreeQuarterTonesSharpArrowDown },
     307            0 :         { u"double-sharp-up", SymId::accidentalFiveQuarterTonesSharpArrowUp },
     308            0 :         { u"flat-flat-down", SymId::accidentalFiveQuarterTonesFlatArrowDown },
     309            0 :         { u"flat-flat-up", SymId::accidentalThreeQuarterTonesFlatArrowUp },
     310              : 
     311            0 :         { u"arrow-down", SymId::accidentalArrowDown },
     312            0 :         { u"arrow-up", SymId::accidentalArrowUp },
     313              : 
     314            0 :         { u"triple-sharp", SymId::accidentalTripleSharp },
     315            0 :         { u"triple-flat", SymId::accidentalTripleFlat },
     316              : 
     317            0 :         { u"slash-quarter-sharp", SymId::accidentalKucukMucennebSharp },
     318            0 :         { u"slash-sharp", SymId::accidentalBuyukMucennebSharp },
     319            0 :         { u"slash-flat", SymId::accidentalBakiyeFlat },
     320            0 :         { u"double-slash-flat", SymId::accidentalBuyukMucennebFlat },
     321              : 
     322            0 :         { u"sharp-1", SymId::accidental1CommaSharp },
     323            0 :         { u"sharp-2", SymId::accidental2CommaSharp },
     324            0 :         { u"sharp-3", SymId::accidental3CommaSharp },
     325            0 :         { u"sharp-5", SymId::accidental5CommaSharp },
     326            0 :         { u"flat-1", SymId::accidental1CommaFlat },
     327            0 :         { u"flat-2", SymId::accidental2CommaFlat },
     328            0 :         { u"flat-3", SymId::accidental3CommaFlat },
     329            0 :         { u"flat-4", SymId::accidental4CommaFlat },
     330              : 
     331            0 :         { u"sori", SymId::accidentalSori },
     332            0 :         { u"koron", SymId::accidentalKoron },
     333           66 :     };
     334              : 
     335           24 :     auto it = map.find(mxmlName);
     336           24 :     if (it != map.end()) {
     337           24 :         return it->second;
     338            0 :     } else if (mxmlName == u"other") {
     339            0 :         return SymNames::symIdByName(smufl);
     340              :     } else {
     341            0 :         LOGD("musicXmlString2accSymId: unknown accidental '%s'", muPrintable(mxmlName));
     342              :     }
     343              : 
     344              :     // default
     345            0 :     return SymId::noSym;
     346            1 : }
     347              : 
     348              : //---------------------------------------------------------
     349              : //   accidentalType2MusicXmlString
     350              : //---------------------------------------------------------
     351              : 
     352           98 : String accidentalType2MusicXmlString(const AccidentalType type)
     353              : {
     354           98 :     String s;
     355           98 :     switch (type) {
     356           37 :     case AccidentalType::SHARP:              s = u"sharp";
     357           37 :         break;
     358           18 :     case AccidentalType::NATURAL:            s = u"natural";
     359           18 :         break;
     360           37 :     case AccidentalType::FLAT:               s = u"flat";
     361           37 :         break;
     362            3 :     case AccidentalType::SHARP2:             s = u"double-sharp";
     363            3 :         break;
     364            0 :     case AccidentalType::SHARP_SHARP:        s = u"sharp-sharp";
     365            0 :         break;
     366              :     //case AccidentalType::FLAT2:              s = u"double-flat"; break; // doesn't exist in MusicXML, but see below
     367            3 :     case AccidentalType::FLAT2:              s = u"flat-flat";
     368            3 :         break;
     369            0 :     case AccidentalType::NATURAL_SHARP:      s = u"natural-sharp";
     370            0 :         break;
     371            0 :     case AccidentalType::NATURAL_FLAT:       s = u"natural-flat";
     372            0 :         break;
     373            0 :     case AccidentalType::SHARP_ARROW_UP:     s = u"sharp-up";
     374            0 :         break;
     375            0 :     case AccidentalType::MIRRORED_FLAT:      s = u"quarter-flat";
     376            0 :         break;
     377            0 :     case AccidentalType::SHARP_SLASH:        s = u"quarter-sharp";
     378            0 :         break;
     379            0 :     case AccidentalType::MIRRORED_FLAT2:     s = u"three-quarters-flat";
     380            0 :         break;
     381              :     //case AccidentalType::FLAT_FLAT_SLASH:    s = u"three-quarters-flat";  break; // MuseScore 1?
     382            0 :     case AccidentalType::SHARP_SLASH4:       s = u"three-quarters-sharp";
     383            0 :         break;
     384            0 :     case AccidentalType::SHARP_ARROW_DOWN:   s = u"sharp-down";
     385            0 :         break;
     386            0 :     case AccidentalType::NATURAL_ARROW_UP:   s = u"natural-up";
     387            0 :         break;
     388            0 :     case AccidentalType::NATURAL_ARROW_DOWN: s = u"natural-down";
     389            0 :         break;
     390            0 :     case AccidentalType::FLAT_ARROW_DOWN:    s = u"flat-down";
     391            0 :         break;
     392            0 :     case AccidentalType::FLAT_ARROW_UP:      s = u"flat-up";
     393            0 :         break;
     394            0 :     case AccidentalType::SHARP2_ARROW_DOWN:  s = u"double-sharp-down";
     395            0 :         break;
     396            0 :     case AccidentalType::SHARP2_ARROW_UP:    s = u"double-sharp-up";
     397            0 :         break;
     398            0 :     case AccidentalType::FLAT2_ARROW_DOWN:   s = u"flat-flat-down";
     399            0 :         break;
     400            0 :     case AccidentalType::FLAT2_ARROW_UP:     s = u"flat-flat-up";
     401            0 :         break;
     402              : 
     403            0 :     case AccidentalType::ARROW_DOWN:         s = u"arrow-down";
     404            0 :         break;
     405            0 :     case AccidentalType::ARROW_UP:           s = u"arrow-up";
     406            0 :         break;
     407              : 
     408            0 :     case AccidentalType::SHARP3:             s = u"triple-sharp";
     409            0 :         break;
     410            0 :     case AccidentalType::FLAT3:              s = u"triple-flat";
     411            0 :         break;
     412              : 
     413            0 :     case AccidentalType::SHARP_SLASH3:       s = u"slash-quarter-sharp";
     414            0 :         break;
     415            0 :     case AccidentalType::SHARP_SLASH2:       s = u"slash-sharp";
     416            0 :         break;
     417            0 :     case AccidentalType::FLAT_SLASH:         s = u"slash-flat";
     418            0 :         break;
     419            0 :     case AccidentalType::FLAT_SLASH2:        s = u"double-slash-flat";
     420            0 :         break;
     421              : 
     422            0 :     case AccidentalType::ONE_COMMA_SHARP:    s = u"sharp-1";
     423            0 :         break;
     424            0 :     case AccidentalType::TWO_COMMA_SHARP:    s = u"sharp-2";
     425            0 :         break;
     426            0 :     case AccidentalType::THREE_COMMA_SHARP:  s = u"sharp-3";
     427            0 :         break;
     428            0 :     case AccidentalType::FIVE_COMMA_SHARP:   s = u"sharp-5";
     429            0 :         break;
     430            0 :     case AccidentalType::ONE_COMMA_FLAT:     s = u"flat-1";
     431            0 :         break;
     432            0 :     case AccidentalType::TWO_COMMA_FLAT:     s = u"flat-2";
     433            0 :         break;
     434            0 :     case AccidentalType::THREE_COMMA_FLAT:   s = u"flat-3";
     435            0 :         break;
     436            0 :     case AccidentalType::FOUR_COMMA_FLAT:    s = u"flat-4";
     437            0 :         break;
     438              : 
     439            0 :     case AccidentalType::SORI:               s = u"sori";
     440            0 :         break;
     441            0 :     case AccidentalType::KORON:              s = u"koron";
     442            0 :         break;
     443            0 :     default:
     444            0 :         s = u"other";
     445              :     }
     446           98 :     return s;
     447            0 : }
     448              : 
     449              : static const std::map<muse::String, AccidentalType> smuflAccidentalTypes {
     450              :     { u"accidentalDoubleFlatOneArrowDown",                AccidentalType::DOUBLE_FLAT_ONE_ARROW_DOWN },
     451              :     { u"accidentalFlatOneArrowDown",                      AccidentalType::FLAT_ONE_ARROW_DOWN },
     452              :     { u"accidentalNaturalOneArrowDown",                   AccidentalType::NATURAL_ONE_ARROW_DOWN },
     453              :     { u"accidentalSharpOneArrowDown",                     AccidentalType::SHARP_ONE_ARROW_DOWN },
     454              :     { u"accidentalDoubleSharpOneArrowDown",               AccidentalType::DOUBLE_SHARP_ONE_ARROW_DOWN },
     455              :     { u"accidentalDoubleFlatOneArrowUp",                  AccidentalType::DOUBLE_FLAT_ONE_ARROW_UP },
     456              :     { u"accidentalFlatOneArrowUp",                        AccidentalType::FLAT_ONE_ARROW_UP },
     457              :     { u"accidentalNaturalOneArrowUp",                     AccidentalType::NATURAL_ONE_ARROW_UP },
     458              :     { u"accidentalSharpOneArrowUp",                       AccidentalType::SHARP_ONE_ARROW_UP },
     459              :     { u"accidentalDoubleSharpOneArrowUp",                 AccidentalType::DOUBLE_SHARP_ONE_ARROW_UP },
     460              :     { u"accidentalDoubleFlatTwoArrowsDown",               AccidentalType::DOUBLE_FLAT_TWO_ARROWS_DOWN },
     461              :     { u"accidentalFlatTwoArrowsDown",                     AccidentalType::FLAT_TWO_ARROWS_DOWN },
     462              :     { u"accidentalNaturalTwoArrowsDown",                  AccidentalType::NATURAL_TWO_ARROWS_DOWN },
     463              :     { u"accidentalSharpTwoArrowsDown",                    AccidentalType::SHARP_TWO_ARROWS_DOWN },
     464              :     { u"accidentalDoubleSharpTwoArrowsDown",              AccidentalType::DOUBLE_SHARP_TWO_ARROWS_DOWN },
     465              :     { u"accidentalDoubleFlatTwoArrowsUp",                 AccidentalType::DOUBLE_FLAT_TWO_ARROWS_UP },
     466              :     { u"accidentalFlatTwoArrowsUp",                       AccidentalType::FLAT_TWO_ARROWS_UP },
     467              :     { u"accidentalNaturalTwoArrowsUp",                    AccidentalType::NATURAL_TWO_ARROWS_UP },
     468              :     { u"accidentalSharpTwoArrowsUp",                      AccidentalType::SHARP_TWO_ARROWS_UP },
     469              :     { u"accidentalDoubleSharpTwoArrowsUp",                AccidentalType::DOUBLE_SHARP_TWO_ARROWS_UP },
     470              :     { u"accidentalDoubleFlatThreeArrowsDown",             AccidentalType::DOUBLE_FLAT_THREE_ARROWS_DOWN },
     471              :     { u"accidentalFlatThreeArrowsDown",                   AccidentalType::FLAT_THREE_ARROWS_DOWN },
     472              :     { u"accidentalNaturalThreeArrowsDown",                AccidentalType::NATURAL_THREE_ARROWS_DOWN },
     473              :     { u"accidentalSharpThreeArrowsDown",                  AccidentalType::SHARP_THREE_ARROWS_DOWN },
     474              :     { u"accidentalDoubleSharpThreeArrowsDown",            AccidentalType::DOUBLE_SHARP_THREE_ARROWS_DOWN },
     475              :     { u"accidentalDoubleFlatThreeArrowsUp",               AccidentalType::DOUBLE_FLAT_THREE_ARROWS_UP },
     476              :     { u"accidentalFlatThreeArrowsUp",                     AccidentalType::FLAT_THREE_ARROWS_UP },
     477              :     { u"accidentalNaturalThreeArrowsUp",                  AccidentalType::NATURAL_THREE_ARROWS_UP },
     478              :     { u"accidentalSharpThreeArrowsUp",                    AccidentalType::SHARP_THREE_ARROWS_UP },
     479              :     { u"accidentalDoubleSharpThreeArrowsUp",              AccidentalType::DOUBLE_SHARP_THREE_ARROWS_UP },
     480              :     { u"accidentalLowerOneSeptimalComma",                 AccidentalType::LOWER_ONE_SEPTIMAL_COMMA },
     481              :     { u"accidentalRaiseOneSeptimalComma",                 AccidentalType::RAISE_ONE_SEPTIMAL_COMMA },
     482              :     { u"accidentalLowerTwoSeptimalCommas",                AccidentalType::LOWER_TWO_SEPTIMAL_COMMAS },
     483              :     { u"accidentalRaiseTwoSeptimalCommas",                AccidentalType::RAISE_TWO_SEPTIMAL_COMMAS },
     484              :     { u"accidentalLowerOneUndecimalQuartertone",          AccidentalType::LOWER_ONE_UNDECIMAL_QUARTERTONE },
     485              :     { u"accidentalRaiseOneUndecimalQuartertone",          AccidentalType::RAISE_ONE_UNDECIMAL_QUARTERTONE },
     486              :     { u"accidentalLowerOneTridecimalQuartertone",         AccidentalType::LOWER_ONE_TRIDECIMAL_QUARTERTONE },
     487              :     { u"accidentalRaiseOneTridecimalQuartertone",         AccidentalType::RAISE_ONE_TRIDECIMAL_QUARTERTONE },
     488              :     { u"accidentalDoubleFlatEqualTempered",               AccidentalType::DOUBLE_FLAT_EQUAL_TEMPERED },
     489              :     { u"accidentalFlatEqualTempered",                     AccidentalType::FLAT_EQUAL_TEMPERED },
     490              :     { u"accidentalNaturalEqualTempered",                  AccidentalType::NATURAL_EQUAL_TEMPERED },
     491              :     { u"accidentalSharpEqualTempered",                    AccidentalType::SHARP_EQUAL_TEMPERED },
     492              :     { u"accidentalDoubleSharpEqualTempered",              AccidentalType::DOUBLE_SHARP_EQUAL_TEMPERED },
     493              :     { u"accidentalQuarterFlatEqualTempered",              AccidentalType::QUARTER_FLAT_EQUAL_TEMPERED },
     494              :     { u"accidentalQuarterSharpEqualTempered",             AccidentalType::QUARTER_SHARP_EQUAL_TEMPERED }
     495              : };
     496              : 
     497              : //---------------------------------------------------------
     498              : //   accidentalType2SmuflMusicXmlString
     499              : //---------------------------------------------------------
     500              : 
     501            0 : String accidentalType2SmuflMusicXmlString(const AccidentalType type)
     502              : {
     503            0 :     return muse::key(smuflAccidentalTypes, type);
     504              : }
     505              : 
     506              : //---------------------------------------------------------
     507              : //   musicXmlString2accidentalType
     508              : //---------------------------------------------------------
     509              : 
     510              : /**
     511              :  Convert a MusicXML accidental name to a MuseScore enum AccidentalType.
     512              :  see https://github.com/w3c/musicxml/blob/6e3a667b85855b04d7e4548ea508b537bc29fc52/schema/musicxml.xsd#L1392-L1439
     513              :  */
     514              : 
     515          260 : AccidentalType musicXmlString2accidentalType(const String mxmlName, const String smufl)
     516              : {
     517              :     // map MusicXML accidental name to MuseScore enum AccidentalType
     518              :     static const std::map<String, AccidentalType> map {
     519            0 :         { u"sharp", AccidentalType::SHARP },
     520            0 :         { u"natural", AccidentalType::NATURAL },
     521            0 :         { u"flat", AccidentalType::FLAT },
     522            0 :         { u"double-sharp", AccidentalType::SHARP2 },
     523            0 :         { u"sharp-sharp", AccidentalType::SHARP_SHARP },
     524              :         //{ u"double-flat", AccidentalType::FLAT2 }, // shouldn't harm, but doesn't exist in MusicXML
     525            0 :         { u"flat-flat", AccidentalType::FLAT2 },
     526            0 :         { u"natural-sharp", AccidentalType::NATURAL_SHARP },
     527            0 :         { u"natural-flat", AccidentalType::NATURAL_FLAT },
     528              : 
     529            0 :         { u"quarter-flat", AccidentalType::MIRRORED_FLAT },
     530            0 :         { u"quarter-sharp", AccidentalType::SHARP_SLASH },
     531            0 :         { u"three-quarters-flat", AccidentalType::MIRRORED_FLAT2 },
     532            0 :         { u"three-quarters-sharp", AccidentalType::SHARP_SLASH4 },
     533              : 
     534            0 :         { u"sharp-up", AccidentalType::SHARP_ARROW_UP },
     535            0 :         { u"natural-down", AccidentalType::NATURAL_ARROW_DOWN },
     536            0 :         { u"natural-up", AccidentalType::NATURAL_ARROW_UP },
     537            0 :         { u"sharp-down", AccidentalType::SHARP_ARROW_DOWN },
     538            0 :         { u"flat-down", AccidentalType::FLAT_ARROW_DOWN },
     539            0 :         { u"flat-up", AccidentalType::FLAT_ARROW_UP },
     540            0 :         { u"double-sharp-down", AccidentalType::SHARP2_ARROW_DOWN },
     541            0 :         { u"double-sharp-up", AccidentalType::SHARP2_ARROW_UP },
     542            0 :         { u"flat-flat-down", AccidentalType::FLAT2_ARROW_DOWN },
     543            0 :         { u"flat-flat-up", AccidentalType::FLAT2_ARROW_UP },
     544              : 
     545            0 :         { u"arrow-down", AccidentalType::ARROW_DOWN },
     546            0 :         { u"arrow-up", AccidentalType::ARROW_UP },
     547              : 
     548            0 :         { u"triple-sharp", AccidentalType::SHARP3 },
     549            0 :         { u"triple-flat", AccidentalType::FLAT3 },
     550              : 
     551            0 :         { u"slash-quarter-sharp", AccidentalType::SHARP_SLASH3 }, // MIRRORED_FLAT_SLASH }, ?
     552            0 :         { u"slash-sharp", AccidentalType::SHARP_SLASH2 }, // SHARP_SLASH }, ?
     553            0 :         { u"slash-flat", AccidentalType::FLAT_SLASH },
     554            0 :         { u"double-slash-flat", AccidentalType::FLAT_SLASH2 },
     555              : 
     556            0 :         { u"sharp-1", AccidentalType::ONE_COMMA_SHARP },
     557            0 :         { u"sharp-2", AccidentalType::TWO_COMMA_SHARP },
     558            0 :         { u"sharp-3", AccidentalType::THREE_COMMA_SHARP },
     559            0 :         { u"sharp-5", AccidentalType::FIVE_COMMA_SHARP },
     560            0 :         { u"flat-1", AccidentalType::ONE_COMMA_FLAT },
     561            0 :         { u"flat-2", AccidentalType::TWO_COMMA_FLAT },
     562            0 :         { u"flat-3", AccidentalType::THREE_COMMA_FLAT },
     563            0 :         { u"flat-4", AccidentalType::FOUR_COMMA_FLAT },
     564              : 
     565            0 :         { u"sori", AccidentalType::SORI },
     566            0 :         { u"koron", AccidentalType::KORON },
     567          302 :     };
     568              : 
     569          260 :     auto it = map.find(mxmlName);
     570          260 :     if (it != map.end()) {
     571          260 :         return it->second;
     572            0 :     } else if (mxmlName == "other" && muse::contains(smuflAccidentalTypes, smufl)) {
     573            0 :         return smuflAccidentalTypes.at(smufl);
     574              :     } else {
     575            0 :         LOGD("musicXmlString2accidentalType: unknown accidental '%s'", muPrintable(mxmlName));
     576              :     }
     577            0 :     return AccidentalType::NONE;
     578            1 : }
     579              : 
     580              : //---------------------------------------------------------
     581              : //   musicXmlAccidentalTextToChar
     582              : //---------------------------------------------------------
     583              : 
     584              : /**
     585              :  Convert a MusicXML accidental text to a accidental character.
     586              :  */
     587              : 
     588           20 : String musicXmlAccidentalTextToChar(const String mxmlName)
     589              : {
     590              :     // map MusicXML accidental name to MuseScore enum AccidentalType
     591              :     static const std::map<String, String> map {
     592              :         { u"sharp", u"♯" },
     593              :         { u"natural", u"♮" },
     594              :         { u"flat", u"♭" },
     595           25 :     };
     596              : 
     597           20 :     auto it = map.find(mxmlName);
     598           20 :     if (it != map.end()) {
     599           20 :         return it->second;
     600              :     } else {
     601            0 :         LOGD("musicXmlAccidentalTextToChar: unsupported accidental '%s'", muPrintable(mxmlName));
     602              :     }
     603            0 :     return u"";
     604            1 : }
     605              : 
     606              : //---------------------------------------------------------
     607              : //   microtonalGuess
     608              : //---------------------------------------------------------
     609              : 
     610              : /**
     611              :  Convert a MusicXML alter tag into a microtonal accidental in MuseScore enum AccidentalType.
     612              :  */
     613              : 
     614            0 : AccidentalType microtonalGuess(double val)
     615              : {
     616            0 :     if (muse::RealIsEqual(val, -1.5)) {
     617            0 :         return AccidentalType::MIRRORED_FLAT2;
     618            0 :     } else if (muse::RealIsEqual(val, -0.5)) {
     619            0 :         return AccidentalType::MIRRORED_FLAT;
     620            0 :     } else if (muse::RealIsEqual(val, 0.5)) {
     621            0 :         return AccidentalType::SHARP_SLASH;
     622            0 :     } else if (muse::RealIsEqual(val, 1.5)) {
     623            0 :         return AccidentalType::SHARP_SLASH4;
     624              :     }
     625              : 
     626            0 :     for (int i = 1; i < static_cast<int>(AccidentalType::END); ++i) {
     627            0 :         AccidentalType type = static_cast<AccidentalType>(i);
     628            0 :         double altVal = static_cast<int>(Accidental::subtype2value(type)) + Accidental::subtype2centOffset(type) / 100.0;
     629            0 :         if (muse::RealIsEqual(val, altVal)) {
     630            0 :             return type;
     631              :         }
     632              :     }
     633              : 
     634            0 :     LOGD("Guess for microtonal accidental corresponding to value %f failed.", val);
     635              :     // default
     636            0 :     return AccidentalType::NONE;
     637              : }
     638              : 
     639              : //---------------------------------------------------------
     640              : //   isLaissezVibrer
     641              : //---------------------------------------------------------
     642              : 
     643            6 : bool isLaissezVibrer(const SymId id)
     644              : {
     645            6 :     return id == SymId::articLaissezVibrerAbove || id == SymId::articLaissezVibrerBelow;
     646              : }
     647              : 
     648          113 : String harmonyXmlKind(const engraving::HarmonyInfo* h)
     649              : {
     650          113 :     if (!h) {
     651            0 :         return String();
     652              :     }
     653          113 :     const ChordDescription* cd = h->descr();
     654          113 :     return cd ? cd->xmlKind : String();
     655              : }
     656              : 
     657          198 : String harmonyXmlText(const engraving::HarmonyInfo* h)
     658              : {
     659          198 :     if (!h) {
     660            0 :         return String();
     661              :     }
     662          198 :     const ChordDescription* cd = h->descr();
     663          198 :     return cd ? cd->xmlText : String();
     664              : }
     665              : 
     666           99 : String harmonyXmlSymbols(const engraving::HarmonyInfo* h)
     667              : {
     668           99 :     if (!h) {
     669            0 :         return String();
     670              :     }
     671           99 :     const ChordDescription* cd = h->descr();
     672           99 :     return cd ? cd->xmlSymbols : String();
     673              : }
     674              : 
     675           99 : String harmonyXmlParens(const engraving::HarmonyInfo* h)
     676              : {
     677           99 :     if (!h) {
     678            0 :         return String();
     679              :     }
     680           99 :     const ChordDescription* cd = h->descr();
     681           99 :     return cd ? cd->xmlParens : String();
     682              : }
     683              : 
     684           81 : StringList harmonyXmlDegrees(const engraving::HarmonyInfo* h)
     685              : {
     686           81 :     if (!h) {
     687            0 :         return StringList();
     688              :     }
     689           81 :     const ChordDescription* cd = h->descr();
     690           81 :     return cd ? cd->xmlDegrees : StringList();
     691              : }
     692              : 
     693           79 : const ChordDescription* harmonyFromXml(engraving::HarmonyInfo* info, engraving::Score* score, const muse::String& kind,
     694              :                                        const muse::String& kindText, const muse::String& symbols, const muse::String& parens,
     695              :                                        const std::vector<engraving::HDegree>& dl)
     696              : {
     697           79 :     if (!info) {
     698            0 :         return nullptr;
     699              :     }
     700           79 :     ParsedChord* pc = new ParsedChord;
     701           79 :     info->setTextName(pc->fromXml(kind, kindText, symbols, parens, dl, score->chordList()));
     702           79 :     info->setParsedChord(pc);
     703           79 :     const ChordDescription* cd = info->getDescription(info->textName(), pc);
     704           79 :     return cd;
     705              : }
     706              : 
     707            2 : String harmonyXmlFunction(const engraving::HarmonyInfo* info, const engraving::Harmony* h, engraving::Key key)
     708              : {
     709            2 :     if (!info || !tpcIsValid(info->rootTpc())) {
     710            0 :         return String();
     711              :     }
     712            2 :     if (key == Key::INVALID) {
     713            0 :         const Staff* st = h->staff();
     714            0 :         key = st ? st->key(h->tick()) : Key::INVALID;
     715              :     }
     716            2 :     return tpc2Function(info->rootTpc(), key);
     717              : }
     718              : 
     719           20 : String harmonyXmlFunction(const engraving::HarmonyInfo* info, const engraving::Harmony* h)
     720              : {
     721           20 :     if (!info || !tpcIsValid(info->rootTpc())) {
     722            2 :         return String();
     723              :     }
     724           18 :     const Staff* st = h->staff();
     725           18 :     Key key = st ? st->key(h->tick()) : Key::INVALID;
     726           18 :     return tpc2Function(info->rootTpc(), key);
     727              : }
     728              : 
     729           19 : void setHarmonyRootTpcFromFunction(HarmonyInfo* info, const Harmony* h, const muse::String& s, engraving::Key key)
     730              : {
     731           19 :     if (!info) {
     732            0 :         return;
     733              :     }
     734           19 :     if (key == Key::INVALID) {
     735            0 :         const Staff* st = h->staff();
     736            0 :         key = st ? st->key(h->tick()) : Key::INVALID;
     737              :     }
     738           19 :     info->setRootTpc(function2Tpc(s, key));
     739              : }
     740              : }
        

Generated by: LCOV version 2.0-1