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 : #include "instrumentsrepository.h"
23 :
24 : #include "global/serialization/json.h"
25 :
26 : #include "engraving/dom/instrtemplate.h"
27 : #include "engraving/types/types.h"
28 :
29 : #include "io/path.h"
30 : #include "mpe/playbacksetupdata.h"
31 :
32 : #include "log.h"
33 : #include "translation.h"
34 :
35 : using namespace muse;
36 : using namespace muse::io;
37 : using namespace mu::notation;
38 :
39 0 : static InstrumentGroup* createAndAddOtherGroup()
40 : {
41 0 : InstrumentGroup* otherGroup = new InstrumentGroup();
42 0 : otherGroup->id = "other_group";
43 0 : otherGroup->name = mtrc("instruments", "Other");
44 0 : mu::engraving::instrumentGroups.push_back(otherGroup);
45 :
46 0 : return otherGroup;
47 : }
48 :
49 0 : static mu::engraving::ClefType museSamplerClefTypeToEngravingClefType(musesampler::ClefType type)
50 : {
51 0 : switch (type) {
52 0 : case musesampler::ClefType::Treble: return mu::engraving::ClefType::G;
53 0 : case musesampler::ClefType::Bass: return mu::engraving::ClefType::F;
54 0 : case musesampler::ClefType::Alto: return mu::engraving::ClefType::C3;
55 0 : case musesampler::ClefType::Tenor: return mu::engraving::ClefType::C4;
56 0 : case musesampler::ClefType::Percussion: return mu::engraving::ClefType::PERC;
57 0 : case musesampler::ClefType::HigherOctaveTreble: return mu::engraving::ClefType::G8_VA;
58 0 : case musesampler::ClefType::LowerOctaveTreble: return mu::engraving::ClefType::G8_VB;
59 0 : case musesampler::ClefType::HigherOctaveBass: return mu::engraving::ClefType::F_8VA;
60 0 : case musesampler::ClefType::LowerOctaveBass: return mu::engraving::ClefType::F8_VB;
61 0 : case musesampler::ClefType::Baritone: return mu::engraving::ClefType::C5;
62 0 : case musesampler::ClefType::Mezzosoprano: return mu::engraving::ClefType::C2;
63 0 : case musesampler::ClefType::Soprano: return mu::engraving::ClefType::C1;
64 0 : case musesampler::ClefType::FrenchViolin: return mu::engraving::ClefType::G_1;
65 0 : case musesampler::ClefType::None: break;
66 : }
67 :
68 0 : return mu::engraving::ClefType::G;
69 : }
70 :
71 0 : static size_t staffCount(musesampler::StaffType type)
72 : {
73 0 : switch (type) {
74 0 : case musesampler::StaffType::Standard: return 1;
75 0 : case musesampler::StaffType::Grand: return 2;
76 : }
77 :
78 0 : return 1;
79 : }
80 :
81 0 : void InstrumentsRepository::init()
82 : {
83 0 : configuration()->userInstrumentsFolderChanged().onReceive(this, [this](const auto&) {
84 0 : load();
85 0 : });
86 :
87 0 : load();
88 0 : }
89 :
90 0 : const InstrumentTemplateList& InstrumentsRepository::instrumentTemplates() const
91 : {
92 0 : return m_instrumentTemplateList;
93 : }
94 :
95 0 : const InstrumentTemplate& InstrumentsRepository::instrumentTemplate(const String& instrumentId) const
96 : {
97 0 : auto it = m_instrumentTemplateMap.find(instrumentId);
98 0 : if (it == m_instrumentTemplateMap.end()) {
99 0 : static const InstrumentTemplate dummy;
100 0 : return dummy;
101 : }
102 :
103 0 : return *it->second;
104 : }
105 :
106 0 : const ScoreOrderList& InstrumentsRepository::orders() const
107 : {
108 0 : return mu::engraving::instrumentOrders;
109 : }
110 :
111 0 : const ScoreOrder& InstrumentsRepository::order(const String& orderId) const
112 : {
113 0 : const ScoreOrderList& orders = mu::engraving::instrumentOrders;
114 :
115 0 : auto it = std::find_if(orders.begin(), orders.end(), [orderId](const ScoreOrder& order) {
116 0 : return order.id == orderId;
117 : });
118 :
119 0 : if (it == orders.cend()) {
120 0 : static ScoreOrder dummy;
121 0 : return dummy;
122 : }
123 :
124 0 : return *it;
125 : }
126 :
127 0 : const InstrumentGenreList& InstrumentsRepository::genres() const
128 : {
129 0 : return mu::engraving::instrumentGenres;
130 : }
131 :
132 0 : const InstrumentGroupList& InstrumentsRepository::groups() const
133 : {
134 0 : return mu::engraving::instrumentGroups;
135 : }
136 :
137 0 : const InstrumentStringTuningsMap& InstrumentsRepository::stringTuningsPresets() const
138 : {
139 0 : return m_stringTuningsPresets;
140 : }
141 :
142 0 : void InstrumentsRepository::load()
143 : {
144 0 : TRACEFUNC;
145 :
146 0 : m_instrumentTemplateList.clear();
147 0 : m_instrumentTemplateMap.clear();
148 :
149 0 : mu::engraving::clearInstrumentTemplates();
150 :
151 0 : const path_t instrumentsXmlPath = configuration()->instrumentsXmlPath();
152 0 : if (!mu::engraving::loadInstrumentTemplates(instrumentsXmlPath)) {
153 0 : LOGE() << "Could not load instruments from " << instrumentsXmlPath;
154 : }
155 :
156 0 : const path_t scoreOrdersXmlPath = configuration()->scoreOrdersXmlPath();
157 0 : if (!mu::engraving::loadInstrumentTemplates(scoreOrdersXmlPath)) {
158 0 : LOGE() << "Could not load score orders from " << scoreOrdersXmlPath;
159 : }
160 :
161 0 : for (const path_t& path : configuration()->userInstrumentsAndScoreOrdersPaths()) {
162 0 : if (!mu::engraving::loadInstrumentTemplates(path)) {
163 0 : LOGE() << "Could not load user instruments and score orders from " << path;
164 : }
165 0 : }
166 :
167 0 : InstrumentTemplateMap instrumentByMusicXmlId;
168 :
169 0 : for (const InstrumentGroup* group : mu::engraving::instrumentGroups) {
170 0 : for (const InstrumentTemplate* templ : group->instrumentTemplates) {
171 0 : if (templ->trackName.isEmpty() || templ->instrumentName.longName().empty()) {
172 0 : continue;
173 : }
174 :
175 0 : m_instrumentTemplateList.push_back(templ);
176 0 : m_instrumentTemplateMap.insert_or_assign(templ->id, templ);
177 0 : instrumentByMusicXmlId.insert_or_assign(templ->musicXmlId, templ);
178 : }
179 : }
180 :
181 0 : loadMuseInstruments(instrumentByMusicXmlId);
182 :
183 0 : path_t stringTuningsPresetsPath = configuration()->stringTuningsPresetsPath();
184 0 : if (!loadStringTuningsPresets(stringTuningsPresetsPath)) {
185 0 : LOGE() << "Could not load string tunings presets from " << stringTuningsPresetsPath << "!";
186 : }
187 0 : }
188 :
189 0 : bool InstrumentsRepository::loadStringTuningsPresets(const path_t& path)
190 : {
191 0 : TRACEFUNC;
192 :
193 0 : Ret ret = fileSystem()->exists(path);
194 0 : if (!ret) {
195 0 : LOGE() << ret.toString();
196 0 : return false;
197 : }
198 :
199 0 : RetVal<ByteArray> retVal = fileSystem()->readFile(path);
200 0 : if (!retVal.ret) {
201 0 : LOGE() << retVal.ret.toString();
202 0 : return false;
203 : }
204 :
205 0 : std::string err;
206 0 : JsonArray arr = JsonDocument::fromJson(retVal.val, &err).rootArray();
207 0 : if (!err.empty()) {
208 0 : LOGE() << "failed parse string tunings presets, err: " << err;
209 0 : return false;
210 : }
211 :
212 0 : for (size_t i = 0; i < arr.size(); ++i) {
213 0 : const JsonValue& presetInfoVal = arr.at(i);
214 0 : JsonObject presetInfoObj = presetInfoVal.toObject();
215 :
216 0 : std::vector<StringTuningsInfo> strings;
217 :
218 0 : JsonArray stringsArr = presetInfoObj.value("strings").toArray();
219 0 : for (size_t j = 0; j < stringsArr.size(); ++j) {
220 0 : StringTuningsInfo info;
221 :
222 0 : const JsonValue& stringVal = stringsArr.at(j);
223 0 : JsonObject stringObj = stringVal.toObject();
224 :
225 0 : info.number = stringObj.value("number").toInt();
226 :
227 0 : JsonArray presetsArr = stringObj.value("presets").toArray();
228 0 : for (size_t k = 0; k < presetsArr.size(); ++k) {
229 0 : const JsonValue& presetVal = presetsArr.at(k);
230 0 : JsonObject presetObj = presetVal.toObject();
231 :
232 0 : StringTuningPreset preset;
233 0 : preset.name = muse::trc("instruments/stringTunings", presetObj.value("name").toStdString().c_str());
234 :
235 0 : JsonArray valuesArr = presetObj.value("value").toArray();
236 0 : for (size_t l = 0; l < valuesArr.size(); ++l) {
237 0 : const JsonValue& valueVal = valuesArr.at(l);
238 0 : preset.value.push_back(valueVal.toInt());
239 0 : }
240 :
241 0 : if (info.number != preset.value.size()) {
242 0 : LOGE() << "Invalid preset " << preset.name;
243 0 : continue;
244 : }
245 :
246 0 : if (presetObj.contains("useFlats")) {
247 0 : preset.useFlats = presetObj.value("useFlats").toBool();
248 : }
249 :
250 0 : info.presets.emplace_back(std::move(preset));
251 0 : }
252 :
253 0 : strings.emplace_back(std::move(info));
254 0 : }
255 :
256 0 : std::string id = presetInfoObj.contains("familyId") ? presetInfoObj.value("familyId").toStdString()
257 0 : : presetInfoObj.value("instrumentId").toStdString();
258 :
259 0 : m_stringTuningsPresets.emplace(std::move(id), std::move(strings));
260 0 : }
261 :
262 0 : return true;
263 0 : }
264 :
265 0 : void InstrumentsRepository::loadMuseInstruments(const InstrumentTemplateMap& standardInstrumentByMusicXmlId)
266 : {
267 0 : TRACEFUNC;
268 :
269 0 : if (!museSampler()) {
270 0 : return;
271 : }
272 :
273 0 : InstrumentGroup* otherGroup = nullptr;
274 0 : std::vector<musesampler::Instrument> instruments = museSampler()->instruments();
275 :
276 0 : for (const musesampler::Instrument& instrument : instruments) {
277 0 : mpe::PlaybackSetupData sound = mpe::PlaybackSetupData::fromString(instrument.soundId);
278 0 : if (!sound.isValid()) {
279 0 : continue;
280 : }
281 :
282 0 : if (sound.isKnownSound()) {
283 0 : continue;
284 : }
285 :
286 0 : InstrumentTemplate* templ = new InstrumentTemplate();
287 0 : templ->id = instrument.id;
288 0 : templ->soundId = instrument.soundId;
289 0 : templ->musicXmlId = instrument.musicXmlId;
290 0 : templ->trackName = instrument.name;
291 0 : templ->instrumentName.setLongName(instrument.name);
292 0 : templ->instrumentName.setShortName(instrument.abbreviation);
293 0 : templ->staffCount = staffCount(instrument.staffType);
294 0 : mu::engraving::ClefType clefType = museSamplerClefTypeToEngravingClefType(instrument.clefType);
295 0 : templ->clefTypes[0].concertClef = clefType;
296 0 : templ->clefTypes[0].transposingClef = clefType;
297 :
298 0 : if (instrument.staffType == musesampler::StaffType::Grand) {
299 0 : templ->bracketSpan[0] = static_cast<int>(templ->staffCount);
300 0 : templ->barlineSpan[0] = true;
301 :
302 0 : for (size_t i = 0; i < templ->staffCount; ++i) {
303 0 : templ->bracket[i] = mu::engraving::BracketType::BRACE;
304 : }
305 :
306 0 : templ->clefTypes[1].concertClef = mu::engraving::ClefType::F;
307 0 : templ->clefTypes[1].transposingClef = mu::engraving::ClefType::F;
308 : }
309 :
310 0 : for (int i = 0; i < MAX_STAVES; ++i) {
311 0 : templ->staffLines[i] = static_cast<int>(instrument.staffLines);
312 : }
313 :
314 0 : if (!instrument.musicXmlId.empty()) {
315 0 : const InstrumentTemplate* standardTempl = muse::value(standardInstrumentByMusicXmlId, instrument.musicXmlId, nullptr);
316 0 : if (standardTempl) {
317 0 : templ->family = standardTempl->family;
318 0 : templ->groupId = standardTempl->groupId;
319 0 : templ->genres = standardTempl->genres;
320 : }
321 : }
322 :
323 0 : if (templ->groupId.empty()) {
324 0 : if (!otherGroup) {
325 0 : otherGroup = createAndAddOtherGroup();
326 : }
327 0 : templ->groupId = otherGroup->id;
328 : }
329 :
330 0 : if (templ->genres.empty()) {
331 0 : const InstrumentGenre* commonGenre = mu::engraving::searchInstrumentGenre(COMMON_GENRE_ID);
332 0 : if (commonGenre) {
333 0 : templ->genres.push_back(commonGenre);
334 : }
335 : }
336 :
337 0 : m_instrumentTemplateList.push_back(templ);
338 0 : m_instrumentTemplateMap.insert_or_assign(templ->id, templ);
339 :
340 0 : mu::engraving::addTemplateToGroup(templ, templ->groupId);
341 0 : }
342 0 : }
|