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