LCOV - code coverage report
Current view: top level - src/importexport/musicxml/internal/import - musicxmlpart.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 74.1 % 81 60
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) 2024 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 "musicxmlpart.h"
      24              : 
      25              : #include "engraving/dom/interval.h"
      26              : #include "engraving/dom/mscore.h"
      27              : 
      28              : #include "log.h"
      29              : 
      30              : using namespace mu::engraving;
      31              : using namespace mu::iex::musicxml;
      32              : 
      33              : static const std::vector<String> vocalInstrumentNames = {
      34              :     u"Voice",
      35              :     u"Soprano",
      36              :     u"Mezzo-Soprano",
      37              :     u"Alto",
      38              :     u"Tenor",
      39              :     u"Baritone",
      40              :     u"Bass",
      41              :     u"Women",
      42              :     u"Men"
      43              : };
      44              : 
      45              : static const std::vector<String> percussionInstrumentNames = {
      46              :     u"Percussion",
      47              :     u"Timpani",
      48              :     u"Glockenspiel",
      49              :     u"Xylophone",
      50              :     u"Vibraphone",
      51              :     u"Marimba",
      52              :     u"Bell",
      53              :     u"Drum",
      54              :     u"Cymbal",
      55              :     u"Triangle",
      56              :     u"Claves",
      57              :     u"Wood Blocks",
      58              :     u"Tambourine",
      59              :     u"Finger Snap",
      60              :     u"Hand Clap",
      61              :     u"Slap",
      62              :     u"Stamp"
      63              : };
      64              : 
      65         5113 : int MusicXmlOctaveShiftList::octaveShift(const Fraction f) const
      66              : {
      67         5113 :     if (empty()) {
      68         4924 :         return 0;
      69              :     }
      70          189 :     auto i = upper_bound(f);
      71          189 :     if (i == begin()) {
      72           31 :         return 0;
      73              :     }
      74          158 :     --i;
      75          158 :     return i->second;
      76              : }
      77              : 
      78           36 : void MusicXmlOctaveShiftList::addOctaveShift(const int shift, const Fraction f)
      79              : {
      80           36 :     IF_ASSERT_FAILED(Fraction(0, 1) <= f) {
      81            0 :         return;
      82              :     }
      83              : 
      84              :     //LOGD("addOctaveShift(shift %d f %s)", shift, muPrintable(f.print()));
      85           36 :     auto i = find(f);
      86           36 :     if (i == end()) {
      87              :         //LOGD("addOctaveShift: not found, inserting");
      88           30 :         insert({ f, shift });
      89              :     } else {
      90              :         //LOGD("addOctaveShift: found %d, adding", (*this)[f]);
      91            6 :         (*this)[f] += shift;
      92              :         //LOGD("addOctaveShift: res %d", (*this)[f]);
      93              :     }
      94              : }
      95              : 
      96         1884 : void MusicXmlOctaveShiftList::calcOctaveShiftShifts()
      97              : {
      98              :     /*
      99              :     for (auto i = cbegin(); i != cend(); ++i)
     100              :           LOGD(" [%s : %d]", muPrintable((*i).first.print()), (*i).second);
     101              :      */
     102              : 
     103              :     // to each MusicXmlOctaveShiftList entry, add the sum of all previous ones
     104         1884 :     int currentShift = 0;
     105         1914 :     for (auto i = begin(); i != end(); ++i) {
     106           30 :         currentShift += i->second;
     107           30 :         i->second = currentShift;
     108              :     }
     109              : 
     110              :     /*
     111              :     for (auto i = cbegin(); i != cend(); ++i)
     112              :           LOGD(" [%s : %d]", muPrintable((*i).first.print()), (*i).second);
     113              :      */
     114         1884 : }
     115              : 
     116          471 : MusicXmlPart::MusicXmlPart(String id, String name)
     117          471 :     : m_id(id), m_name(name)
     118              : {
     119          471 :     m_octaveShifts.resize(MAX_STAVES);
     120          471 : }
     121              : 
     122         2740 : void MusicXmlPart::addMeasureNumberAndDuration(String measureNumber, Fraction measureDuration)
     123              : {
     124         2740 :     m_measureNumbers.push_back(measureNumber);
     125         2740 :     m_measureDurations.push_back(measureDuration);
     126         2740 : }
     127              : 
     128         2389 : void MusicXmlPart::setMaxStaff(const int staff)
     129              : {
     130         2389 :     if (staff > m_maxStaff) {
     131          144 :         m_maxStaff = staff;
     132              :     }
     133         2389 : }
     134              : 
     135         2740 : Fraction MusicXmlPart::measureDuration(size_t i) const
     136              : {
     137         2740 :     if (i < m_measureDurations.size()) {
     138         2740 :         return m_measureDurations.at(i);
     139              :     }
     140            0 :     return Fraction(0, 0);   // return invalid fraction
     141              : }
     142              : 
     143            0 : String MusicXmlPart::toString() const
     144              : {
     145            0 :     String res = String(u"part id '%1' name '%2' print %3 abbr '%4' print %5 maxStaff %6\n")
     146            0 :                  .arg(m_id, m_name).arg(m_printName).arg(m_abbr).arg(m_printAbbr, m_maxStaff);
     147              : 
     148            0 :     for (const auto& p : voicelist) {
     149            0 :         res += String(u"voice %1 map staff data %2\n")
     150            0 :                .arg(String::number(p.first + 1), p.second.toString());
     151              :     }
     152              : 
     153            0 :     for (size_t i = 0; i < m_measureNumbers.size(); ++i) {
     154            0 :         if (i > 0) {
     155            0 :             res += u"\n";
     156              :         }
     157            0 :         res += String(u"measure %1 duration %2 (%3)")
     158            0 :                .arg(m_measureNumbers.at(i), m_measureDurations.at(i).toString()).arg(m_measureDurations.at(i).ticks());
     159              :     }
     160              : 
     161            0 :     return res;
     162            0 : }
     163              : 
     164            0 : Interval MusicXmlPart::interval(const Fraction f) const
     165              : {
     166            0 :     return _intervals.interval(f);
     167              : }
     168              : 
     169         5113 : int MusicXmlPart::octaveShift(const staff_idx_t staff, const Fraction f) const
     170              : {
     171         5113 :     if (MAX_STAVES <= staff) {
     172            0 :         return 0;
     173              :     }
     174         5113 :     if (f < Fraction(0, 1)) {
     175            0 :         return 0;
     176              :     }
     177         5113 :     return m_octaveShifts[staff].octaveShift(f);
     178              : }
     179              : 
     180           36 : void MusicXmlPart::addOctaveShift(const staff_idx_t staff, const int shift, const Fraction f)
     181              : {
     182           36 :     if (MAX_STAVES <= staff) {
     183            0 :         return;
     184              :     }
     185           36 :     if (f < Fraction(0, 1)) {
     186            0 :         return;
     187              :     }
     188           36 :     m_octaveShifts[staff].addOctaveShift(shift, f);
     189              : }
     190              : 
     191          471 : void MusicXmlPart::calcOctaveShifts()
     192              : {
     193         2355 :     for (staff_idx_t i = 0; i < MAX_STAVES; ++i) {
     194         1884 :         m_octaveShifts[i].calcOctaveShiftShifts();
     195              :     }
     196          471 : }
     197              : 
     198              : //---------------------------------------------------------
     199              : //   staffNumberToIndex
     200              : //---------------------------------------------------------
     201              : 
     202              : /**
     203              :  This handles the mapping from MusicXML staff number to the index
     204              :  in a Part's Staff list.
     205              :  In most cases, this is a simple decrement from the 1-based staff number
     206              :  to the 0-based index.
     207              :  However, in some parts some MusicXML staves are discarded, and a mapping
     208              :  must be stored from MusicXML staff number to index. When this mapping is
     209              :  defined (i.e. size() != 0), it is used. See MusicXmlParserPass1::attributes()
     210              :  for more information.
     211              :  */
     212              : 
     213         5213 : int MusicXmlPart::staffNumberToIndex(const int staffNumber) const
     214              : {
     215         5213 :     if (m_staffNumberToIndex.size() == 0) {
     216         4739 :         return staffNumber - 1;
     217          474 :     } else if (muse::contains(m_staffNumberToIndex, staffNumber)) {
     218          466 :         return m_staffNumberToIndex.at(staffNumber);
     219              :     } else {
     220            8 :         return -1;
     221              :     }
     222              : }
     223              : 
     224         7980 : bool MusicXmlPart::isVocalStaff() const
     225              : {
     226         7980 :     return std::find(vocalInstrumentNames.begin(), vocalInstrumentNames.end(), m_name) != vocalInstrumentNames.end();
     227              : }
     228              : 
     229          582 : bool MusicXmlPart::isPercussionStaff() const
     230              : {
     231         9868 :     for (const String& name : percussionInstrumentNames) {
     232         9326 :         if (m_name.contains(name)) {
     233           40 :             return true;
     234              :         }
     235              :     }
     236          542 :     return false;
     237              : }
        

Generated by: LCOV version 2.0-1