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 "part.h"
24 :
25 : #include "containers.h"
26 :
27 : #include "iengravingconfiguration.h"
28 :
29 : #include "style/style.h"
30 : #include "rw/xmlwriter.h"
31 :
32 : #include "chordrest.h"
33 : #include "factory.h"
34 : #include "fret.h"
35 : #include "harppedaldiagram.h"
36 : #include "instrtemplate.h"
37 : #include "instrchange.h"
38 : #include "linkedobjects.h"
39 : #include "masterscore.h"
40 : #include "measure.h"
41 : #include "score.h"
42 : #include "sharedpart.h"
43 : #include "staff.h"
44 : #include "system.h"
45 : #include "stringtunings.h"
46 :
47 : #include "log.h"
48 :
49 : using namespace mu;
50 : using namespace mu::engraving;
51 :
52 : namespace mu::engraving {
53 : const Fraction Part::MAIN_INSTRUMENT_TICK = Fraction(-1, 1);
54 : //---------------------------------------------------------
55 : // Part
56 : //---------------------------------------------------------
57 :
58 3054 : Part::Part(Score* s, ElementType type)
59 3054 : : EngravingObject(type, s)
60 : {
61 3054 : m_show = true;
62 3054 : m_soloist = false;
63 3054 : m_instruments.setInstrument(new Instrument, -1); // default instrument
64 3054 : m_preferSharpFlat = PreferSharpFlat::AUTO;
65 3054 : }
66 :
67 : //---------------------------------------------------------
68 : // initFromInstrTemplate
69 : //---------------------------------------------------------
70 :
71 326 : void Part::initFromInstrTemplate(const InstrumentTemplate* t)
72 : {
73 326 : setInstrument(Instrument::fromTemplate(t));
74 326 : }
75 :
76 27766 : const ID& Part::id() const
77 : {
78 27766 : return m_id;
79 : }
80 :
81 3940 : void Part::setId(const ID& id)
82 : {
83 3940 : m_id = id;
84 3940 : }
85 :
86 0 : Part* Part::clone() const
87 : {
88 0 : return new Part(*this);
89 : }
90 :
91 : //---------------------------------------------------------
92 : // staff
93 : //---------------------------------------------------------
94 :
95 4056 : Staff* Part::staff(staff_idx_t idx) const
96 : {
97 4056 : if (idx >= m_staves.size()) {
98 0 : return nullptr;
99 : }
100 :
101 4056 : return m_staves[idx];
102 : }
103 :
104 : //---------------------------------------------------------
105 : // family
106 : //---------------------------------------------------------
107 :
108 0 : String Part::familyId() const
109 : {
110 0 : if (m_instruments.empty()) {
111 0 : return String();
112 : }
113 :
114 0 : InstrumentIndex ii = searchTemplateIndexForId(instrumentId());
115 0 : return ii.instrTemplate && ii.instrTemplate->family ? ii.instrTemplate->family->id : String();
116 : }
117 :
118 : //---------------------------------------------------------
119 : // Part::masterPart
120 : //---------------------------------------------------------
121 :
122 335 : const Part* Part::masterPart() const
123 : {
124 335 : if (score()->isMaster()) {
125 16 : return this;
126 : }
127 319 : if (m_staves.empty()) {
128 0 : return this;
129 : }
130 :
131 319 : Staff* st = m_staves[0];
132 319 : LinkedObjects* links = st->links();
133 319 : if (!links) {
134 0 : return this;
135 : }
136 :
137 319 : for (EngravingObject* le : *links) {
138 319 : if (le->isStaff() && toStaff(le)->score()->isMaster()) {
139 319 : if (Part* p = toStaff(le)->part()) {
140 319 : return p;
141 : }
142 : }
143 : }
144 0 : return this;
145 : }
146 :
147 : //---------------------------------------------------------
148 : // Part::masterPart
149 : //---------------------------------------------------------
150 :
151 335 : Part* Part::masterPart()
152 : {
153 335 : return const_cast<Part*>(const_cast<const Part*>(this)->masterPart());
154 : }
155 :
156 300538 : const Part* Part::originPart(track_idx_t, const Fraction&) const
157 : {
158 300538 : return this;
159 : }
160 :
161 303133 : Part* Part::originPart(track_idx_t track, const Fraction& tick)
162 : {
163 303133 : return const_cast<Part*>(const_cast<const Part*>(this)->originPart(track, tick));
164 : }
165 :
166 398138 : size_t Part::nstaves() const
167 : {
168 398138 : return m_staves.size();
169 : }
170 :
171 59727 : size_t Part::visibleStavesCount() const
172 : {
173 59727 : size_t result = 0;
174 130473 : for (const Staff* staff : m_staves) {
175 70746 : if (staff->show()) {
176 70423 : ++result;
177 : }
178 : }
179 :
180 59727 : return result;
181 : }
182 :
183 117257 : const std::vector<Staff*>& Part::staves() const
184 : {
185 117257 : return m_staves;
186 : }
187 :
188 7093 : std::set<staff_idx_t> Part::staveIdxList() const
189 : {
190 7093 : std::set<staff_idx_t> result;
191 :
192 14499 : for (const Staff* stave : m_staves) {
193 7406 : if (!stave) {
194 0 : continue;
195 : }
196 :
197 7406 : result.insert(stave->idx());
198 : }
199 :
200 7093 : return result;
201 0 : }
202 :
203 3238 : void Part::appendStaff(Staff* staff)
204 : {
205 3238 : m_staves.push_back(staff);
206 3238 : }
207 :
208 10 : void Part::clearStaves()
209 : {
210 10 : m_staves.clear();
211 10 : }
212 :
213 : //---------------------------------------------------------
214 : // setStaves
215 : //---------------------------------------------------------
216 :
217 253 : void Part::setStaves(int n)
218 : {
219 253 : int ns = static_cast<int>(m_staves.size());
220 253 : if (n < ns) {
221 0 : LOGD("Part::setStaves(): remove staves not implemented!");
222 0 : return;
223 : }
224 :
225 253 : int staffIdx = static_cast<int>(score()->staffIdx(this)) + ns;
226 527 : for (int i = ns; i < n; ++i) {
227 274 : Staff* staff = Factory::createStaff(this);
228 274 : score()->insertStaff(staff, i);
229 :
230 438 : for (Measure* m = score()->firstMeasure(); m; m = m->nextMeasure()) {
231 164 : m->insertStaff(staff, staffIdx);
232 164 : if (m->hasMMRest()) {
233 0 : m->mmRest()->insertStaff(staff, staffIdx);
234 : }
235 : }
236 274 : ++staffIdx;
237 : }
238 : }
239 :
240 : //---------------------------------------------------------
241 : // insertStaff
242 : //---------------------------------------------------------
243 :
244 343 : void Part::insertStaff(Staff* staff, staff_idx_t idx)
245 : {
246 343 : if (idx >= m_staves.size()) {
247 338 : idx = m_staves.size();
248 : }
249 343 : m_staves.insert(m_staves.begin() + idx, staff);
250 343 : staff->setPart(this);
251 343 : }
252 :
253 : //---------------------------------------------------------
254 : // removeStaff
255 : //---------------------------------------------------------
256 :
257 37 : void Part::removeStaff(Staff* staff)
258 : {
259 37 : if (!muse::remove(m_staves, staff)) {
260 0 : LOGD("Part::removeStaff: not found %p", staff);
261 0 : return;
262 : }
263 : }
264 :
265 3551601 : bool Part::show() const
266 : {
267 3551601 : if (score()->configuration()->debuggingOptions().showOriginAndCombinedStaves) {
268 0 : return m_show;
269 : }
270 :
271 3551601 : bool sharedPartEnabled = sharedPart() && sharedPart()->enabled();
272 3551601 : return m_show && !sharedPartEnabled;
273 : }
274 :
275 : //---------------------------------------------------------
276 : // setMidiProgram
277 : //---------------------------------------------------------
278 :
279 994 : void Part::setMidiProgram(int program, int bank)
280 : {
281 994 : InstrChannel* c = instrument()->channel(0);
282 994 : c->setProgram(program);
283 994 : c->setBank(bank);
284 994 : }
285 :
286 : //---------------------------------------------------------
287 : // midiProgram
288 : //---------------------------------------------------------
289 :
290 103 : int Part::midiProgram() const
291 : {
292 103 : return instrument()->playbackChannel(0, masterScore())->program();
293 : }
294 :
295 : //---------------------------------------------------------
296 : // midiChannel
297 : //---------------------------------------------------------
298 :
299 1006 : int Part::midiChannel() const
300 : {
301 1006 : return masterScore()->midiChannel(instrument()->channel(0)->channel());
302 : }
303 :
304 : //---------------------------------------------------------
305 : // midiPort
306 : //---------------------------------------------------------
307 :
308 592 : int Part::midiPort() const
309 : {
310 592 : return masterScore()->midiPort(instrument()->channel(0)->channel());
311 : }
312 :
313 : //---------------------------------------------------------
314 : // setMidiChannel
315 : // Called from importmusicxml, importMidi and importGtp*.
316 : // Specify tick to set MIDI channel to an InstrumentChange element.
317 : // Usage:
318 : // setMidiChannel(channel) to set channel
319 : // setMidiChannel(-1, port) to set port
320 : // setMidiChannel(channel, port) to set both
321 : //---------------------------------------------------------
322 :
323 958 : void Part::setMidiChannel(int ch, int port, const Fraction& tick)
324 : {
325 958 : InstrChannel* channel = instrument(tick)->channel(0);
326 958 : if (channel->channel() == -1) {
327 942 : masterScore()->addMidiMapping(channel, this, port, ch);
328 : } else {
329 16 : masterScore()->updateMidiMapping(channel, this, port, ch);
330 : }
331 958 : }
332 :
333 : //---------------------------------------------------------
334 : // setInstrument
335 : //---------------------------------------------------------
336 :
337 1594 : void Part::setInstrument(Instrument* i, Fraction tick)
338 : {
339 1594 : m_instruments.setInstrument(i, tick.ticks());
340 1594 : }
341 :
342 0 : void Part::setInstrument(Instrument* i, int tick)
343 : {
344 0 : m_instruments.setInstrument(i, tick);
345 0 : }
346 :
347 326 : void Part::setInstrument(const Instrument&& i, Fraction tick)
348 : {
349 326 : m_instruments.setInstrument(new Instrument(i), tick.ticks());
350 326 : }
351 :
352 539 : void Part::setInstrument(const Instrument& i, Fraction tick)
353 : {
354 539 : m_instruments.setInstrument(new Instrument(i), tick.ticks());
355 539 : }
356 :
357 0 : void Part::setInstruments(const InstrumentList& instruments)
358 : {
359 0 : m_instruments.clear();
360 :
361 0 : for (auto it = instruments.begin(); it != instruments.end(); ++it) {
362 0 : m_instruments.setInstrument(it->second, it->first);
363 : }
364 0 : }
365 :
366 : //---------------------------------------------------------
367 : // removeInstrument
368 : //---------------------------------------------------------
369 :
370 1 : void Part::removeInstrument(Instrument* instr, const Fraction& tick)
371 : {
372 1 : auto i = m_instruments.find(tick.ticks());
373 1 : if (i == m_instruments.end()) {
374 0 : LOGD("Part::removeInstrument: not found at tick %d", tick.ticks());
375 0 : return;
376 : }
377 1 : if (i->second != instr) {
378 0 : LOGD("Part::removeInstrument: item at tick %d (%p) != instr (%p)", tick.ticks(), i->second, instr);
379 0 : return;
380 : }
381 1 : m_instruments.erase(i);
382 : }
383 :
384 : //---------------------------------------------------------
385 : // removeNonPrimaryInstruments
386 : //---------------------------------------------------------
387 :
388 0 : void Part::removeNonPrimaryInstruments()
389 : {
390 0 : auto it = m_instruments.begin();
391 0 : while (it != m_instruments.end()) {
392 0 : if (it->first != -1) {
393 0 : it = m_instruments.erase(it);
394 0 : continue;
395 : }
396 0 : ++it;
397 : }
398 0 : }
399 :
400 : //---------------------------------------------------------
401 : // instrument
402 : //---------------------------------------------------------
403 :
404 795362 : Instrument* Part::instrument(Fraction tick)
405 : {
406 795362 : return m_instruments.instrument(tick.ticks());
407 : }
408 :
409 : //---------------------------------------------------------
410 : // instrument
411 : //---------------------------------------------------------
412 :
413 39611 : const Instrument* Part::instrument(Fraction tick) const
414 : {
415 39611 : return m_instruments.instrument(tick.ticks());
416 : }
417 :
418 0 : const Instrument* Part::instrumentById(const String& id) const
419 : {
420 0 : for (const auto& pair: m_instruments) {
421 0 : if (pair.second->id() == id) {
422 0 : return pair.second;
423 : }
424 : }
425 :
426 0 : return nullptr;
427 : }
428 :
429 : //---------------------------------------------------------
430 : // instruments
431 : //---------------------------------------------------------
432 :
433 22729 : const InstrumentList& Part::instruments() const
434 : {
435 22729 : return m_instruments;
436 : }
437 :
438 1844 : const StringData* Part::stringData(const Fraction& tick, staff_idx_t staffIdx) const
439 : {
440 1844 : if (!score()) {
441 0 : return nullptr;
442 : }
443 :
444 1844 : const Instrument* instrument = this->instrument(tick);
445 1844 : if (!instrument) {
446 0 : return nullptr;
447 : }
448 :
449 1844 : bool reflectTranspositionInLinkedTab = true;
450 :
451 1844 : const Staff* staff = staffIdx != muse::nidx ? score()->staff(staffIdx) : nullptr;
452 1844 : if (staff && staff->isTabStaff(tick)) {
453 1452 : if (const Staff* primaryStaff = staff->primaryStaff()) {
454 1126 : reflectTranspositionInLinkedTab = primaryStaff->reflectTranspositionInLinkedTab();
455 : }
456 : }
457 :
458 1844 : StringTunings* stringTunings = nullptr;
459 :
460 1844 : if (reflectTranspositionInLinkedTab) {
461 1844 : auto it = muse::findLessOrEqual(m_stringTunings, tick.ticks());
462 1844 : if (it != m_stringTunings.end()) {
463 3 : stringTunings = it->second;
464 : }
465 : }
466 :
467 1844 : if (stringTunings) {
468 : //!NOTE: if there is string tunings element between current instrument and current tick,
469 : //! then return string data from string tunings element
470 3 : const Instrument* stringTuningsInstrument = this->instrument(stringTunings->tick());
471 3 : if (instrument == stringTuningsInstrument) {
472 3 : return stringTunings->stringData();
473 : }
474 : }
475 :
476 1841 : return instrument->stringData();
477 : }
478 :
479 19 : void Part::addStringTunings(StringTunings* stringTunings)
480 : {
481 19 : DO_ASSERT(!isSharedPart());
482 19 : m_stringTunings[stringTunings->segment()->tick().ticks()] = stringTunings;
483 19 : }
484 :
485 0 : void Part::removeStringTunings(StringTunings* stringTunings)
486 : {
487 0 : int tick = stringTunings->segment()->tick().ticks();
488 0 : auto it = m_stringTunings.find(tick);
489 :
490 0 : if (it != m_stringTunings.end() && it->second == stringTunings) {
491 0 : m_stringTunings.erase(it);
492 : }
493 0 : }
494 :
495 19 : StringTunings* Part::nextStringTuning(const Fraction& tick) const
496 : {
497 19 : auto i = m_stringTunings.upper_bound(tick.ticks());
498 19 : return (i == m_stringTunings.end()) ? nullptr : i->second;
499 : }
500 :
501 : //---------------------------------------------------------
502 : // instrumentId
503 : //---------------------------------------------------------
504 :
505 1630 : String Part::instrumentId(const Fraction& tick) const
506 : {
507 1630 : return instrument(tick)->id();
508 : }
509 :
510 : //---------------------------------------------------------
511 : // longName
512 : //---------------------------------------------------------
513 :
514 749 : String Part::longName(const Fraction& tick) const
515 : {
516 749 : return instrument(tick)->longName();
517 : }
518 :
519 : //---------------------------------------------------------
520 : // instrumentName
521 : //---------------------------------------------------------
522 :
523 58 : String Part::instrumentName(const Fraction& tick) const
524 : {
525 58 : return instrument(tick)->trackName();
526 : }
527 :
528 : //---------------------------------------------------------
529 : // shortName
530 : //---------------------------------------------------------
531 :
532 1390 : String Part::shortName(const Fraction& tick) const
533 : {
534 1390 : return instrument(tick)->shortName();
535 : }
536 :
537 : //---------------------------------------------------------
538 : // setLongName
539 : //---------------------------------------------------------
540 :
541 848 : void Part::setLongName(const String& s, const Fraction& tick)
542 : {
543 848 : instrument(tick)->setLongName(s);
544 848 : }
545 :
546 : //---------------------------------------------------------
547 : // setShortName
548 : //---------------------------------------------------------
549 :
550 584 : void Part::setShortName(const String& s, const Fraction& tick)
551 : {
552 584 : instrument(tick)->setShortName(s);
553 584 : }
554 :
555 : //---------------------------------------------------------
556 : // setLongNameAll
557 : //---------------------------------------------------------
558 :
559 472 : void Part::setLongNameAll(const String& s)
560 : {
561 949 : for (auto instrument : m_instruments) {
562 477 : instrument.second->setLongName(s);
563 : }
564 472 : }
565 :
566 : //---------------------------------------------------------
567 : // setShortNameAll
568 : //---------------------------------------------------------
569 :
570 471 : void Part::setShortNameAll(const String& s)
571 : {
572 947 : for (auto instrument : m_instruments) {
573 476 : instrument.second->setShortName(s);
574 : }
575 471 : }
576 :
577 765 : int Part::number(const Fraction& tick) const
578 : {
579 765 : return instrument(tick)->number();
580 : }
581 :
582 0 : void Part::setNumber(int v, const Fraction& tick)
583 : {
584 0 : instrument(tick)->setNumber(v);
585 0 : }
586 :
587 0 : String Part::transposition(const Fraction& tick) const
588 : {
589 0 : return instrument(tick)->transposition();
590 : }
591 :
592 0 : void Part::setTransposition(const String& s, const Fraction& tick)
593 : {
594 0 : instrument(tick)->setTransposition(s);
595 0 : }
596 :
597 : //---------------------------------------------------------
598 : // setPlainLongName
599 : //---------------------------------------------------------
600 :
601 429 : void Part::setPlainLongName(const String& s)
602 : {
603 429 : setLongName(XmlWriter::xmlString(s));
604 429 : }
605 :
606 : //---------------------------------------------------------
607 : // setPlainShortName
608 : //---------------------------------------------------------
609 :
610 273 : void Part::setPlainShortName(const String& s)
611 : {
612 273 : setShortName(XmlWriter::xmlString(s));
613 273 : }
614 :
615 : //---------------------------------------------------------
616 : // setPlainLongNameAll
617 : //---------------------------------------------------------
618 :
619 0 : void Part::setPlainLongNameAll(const String& s)
620 : {
621 0 : setLongNameAll(XmlWriter::xmlString(s));
622 0 : }
623 :
624 : //---------------------------------------------------------
625 : // setPlainShortNameAll
626 : //---------------------------------------------------------
627 :
628 471 : void Part::setPlainShortNameAll(const String& s)
629 : {
630 471 : setShortNameAll(XmlWriter::xmlString(s));
631 471 : }
632 :
633 : //---------------------------------------------------------
634 : // getProperty
635 : //---------------------------------------------------------
636 :
637 1786 : PropertyValue Part::getProperty(Pid id) const
638 : {
639 1786 : switch (id) {
640 1762 : case Pid::VISIBLE:
641 1762 : return PropertyValue(m_show);
642 0 : case Pid::HIDE_WHEN_EMPTY:
643 0 : return PropertyValue(m_hideWhenEmpty);
644 0 : case Pid::HIDE_STAVES_WHEN_INDIVIDUALLY_EMPTY:
645 0 : return PropertyValue(m_hideStavesWhenIndividuallyEmpty);
646 0 : case Pid::USE_DRUMSET:
647 0 : return instrument()->useDrumset();
648 6 : case Pid::PREFER_SHARP_FLAT:
649 6 : return int(preferSharpFlat());
650 18 : default:
651 18 : return PropertyValue();
652 : }
653 : }
654 :
655 : //---------------------------------------------------------
656 : // setProperty
657 : //---------------------------------------------------------
658 :
659 20 : bool Part::setProperty(Pid id, const PropertyValue& property)
660 : {
661 20 : switch (id) {
662 8 : case Pid::VISIBLE:
663 8 : setShow(property.toBool());
664 8 : break;
665 0 : case Pid::HIDE_WHEN_EMPTY:
666 0 : setHideWhenEmpty(property.value<AutoOnOff>());
667 0 : break;
668 0 : case Pid::HIDE_STAVES_WHEN_INDIVIDUALLY_EMPTY:
669 0 : setHideStavesWhenIndividuallyEmpty(property.toBool());
670 0 : break;
671 0 : case Pid::USE_DRUMSET:
672 0 : instrument()->setUseDrumset(property.toBool());
673 0 : break;
674 2 : case Pid::PREFER_SHARP_FLAT:
675 2 : setPreferSharpFlat(PreferSharpFlat(property.toInt()));
676 2 : break;
677 10 : default:
678 10 : LOGD("Part::setProperty: unknown id %d", int(id));
679 10 : break;
680 : }
681 20 : score()->setLayoutAll();
682 20 : return true;
683 : }
684 :
685 154412 : TrackRange Part::trackRange() const
686 : {
687 154412 : IF_ASSERT_FAILED(!m_staves.empty()) {
688 0 : return {};
689 : }
690 :
691 154412 : const track_idx_t startTrack = m_staves.front()->idx() * VOICES;
692 154412 : return { startTrack, startTrack + m_staves.size() * VOICES };
693 : }
694 :
695 0 : InstrumentTrackIdList Part::instrumentTrackIdList() const
696 : {
697 0 : InstrumentTrackIdList result;
698 0 : std::set<String> seen;
699 :
700 0 : for (const auto& pair : m_instruments) {
701 0 : String instrId = pair.second->id();
702 0 : if (seen.insert(instrId).second) {
703 0 : result.push_back({ m_id, instrId });
704 : }
705 0 : }
706 :
707 0 : return result;
708 0 : }
709 :
710 109 : InstrumentTrackIdSet Part::instrumentTrackIdSet() const
711 : {
712 109 : InstrumentTrackIdSet result;
713 :
714 218 : for (const auto& pair : m_instruments) {
715 218 : result.insert({ m_id, pair.second->id() });
716 : }
717 :
718 109 : return result;
719 218 : }
720 :
721 : //---------------------------------------------------------
722 : // insertTime
723 : //---------------------------------------------------------
724 :
725 542 : void Part::insertTime(const Fraction& tick, const Fraction& len)
726 : {
727 542 : if (len.isZero()) {
728 9 : return;
729 : }
730 :
731 : // move all instruments
732 :
733 533 : if (len < Fraction(0, 1)) {
734 : // remove instruments between tickpos >= tick and tickpos < (tick+len)
735 : // ownership goes back to class InstrumentChange()
736 :
737 141 : auto si = m_instruments.lower_bound(tick.ticks());
738 141 : auto ei = m_instruments.lower_bound((tick - len).ticks());
739 141 : m_instruments.erase(si, ei);
740 :
741 : // remove harp pedal diagrams between tickpo >= tick
742 141 : m_harpDiagrams.erase(m_harpDiagrams.lower_bound(tick.ticks()), m_harpDiagrams.lower_bound((tick - len).ticks()));
743 : }
744 :
745 533 : InstrumentList il;
746 :
747 533 : for (auto i = m_instruments.lower_bound(tick.ticks()); i != m_instruments.end();) {
748 0 : Instrument* instrument = i->second;
749 0 : int t = i->first;
750 0 : m_instruments.erase(i++);
751 0 : il[t + len.ticks()] = instrument;
752 : }
753 533 : m_instruments.insert(il.begin(), il.end());
754 :
755 533 : std::map<int, HarpPedalDiagram*> hd2;
756 533 : for (auto h = m_harpDiagrams.lower_bound(tick.ticks()); h != m_harpDiagrams.end();) {
757 0 : HarpPedalDiagram* diagram = h->second;
758 0 : int t = h->first;
759 0 : m_harpDiagrams.erase(h++);
760 0 : hd2[t + len.ticks()] = diagram;
761 : }
762 533 : m_harpDiagrams.insert(hd2.begin(), hd2.end());
763 533 : }
764 :
765 : //---------------------------------------------------------
766 : // addHarpDiagram
767 : //---------------------------------------------------------
768 :
769 18 : void Part::addHarpDiagram(HarpPedalDiagram* harpDiagram)
770 : {
771 18 : DO_ASSERT(!isSharedPart());
772 18 : m_harpDiagrams[harpDiagram->segment()->tick().ticks()] = harpDiagram;
773 18 : }
774 :
775 : //---------------------------------------------------------
776 : // removeHarpDiagram
777 : //---------------------------------------------------------
778 :
779 1 : void Part::removeHarpDiagram(HarpPedalDiagram* harpDiagram)
780 : {
781 1 : int tick = harpDiagram->segment()->tick().ticks();
782 1 : auto it = m_harpDiagrams.find(tick);
783 :
784 1 : if (it != m_harpDiagrams.end() && it->second == harpDiagram) {
785 1 : m_harpDiagrams.erase(it);
786 : }
787 1 : }
788 :
789 : //---------------------------------------------------------
790 : // clearHarpDiagrams
791 : //---------------------------------------------------------
792 :
793 0 : void Part::clearHarpDiagrams()
794 : {
795 0 : m_harpDiagrams.clear();
796 0 : }
797 :
798 : //---------------------------------------------------------
799 : // currentHarpDiagram
800 : //---------------------------------------------------------
801 :
802 3 : HarpPedalDiagram* Part::currentHarpDiagram(const Fraction& tick) const
803 : {
804 3 : auto i = m_harpDiagrams.upper_bound(tick.ticks());
805 3 : if (i != m_harpDiagrams.begin()) {
806 3 : --i;
807 : }
808 3 : if (i == m_harpDiagrams.end()) {
809 0 : return nullptr;
810 3 : } else if (tick < Fraction::fromTicks(i->first)) {
811 0 : return nullptr;
812 : }
813 3 : return i->second;
814 : }
815 :
816 : //---------------------------------------------------------
817 : // nextHarpDiagram
818 : //---------------------------------------------------------
819 :
820 8 : HarpPedalDiagram* Part::nextHarpDiagram(const Fraction& tick) const
821 : {
822 8 : auto i = m_harpDiagrams.upper_bound(tick.ticks());
823 8 : return (i == m_harpDiagrams.end()) ? nullptr : i->second;
824 : }
825 :
826 : //---------------------------------------------------------
827 : // prevHarpDiagram
828 : //---------------------------------------------------------
829 :
830 31 : HarpPedalDiagram* Part::prevHarpDiagram(const Fraction& tick) const
831 : {
832 31 : auto i = m_harpDiagrams.lower_bound(tick.ticks());
833 31 : if (i == m_harpDiagrams.begin()) {
834 10 : return nullptr;
835 : }
836 21 : i--;
837 21 : return i->second;
838 : }
839 :
840 : //---------------------------------------------------------
841 : // currentHarpDiagramTick
842 : //---------------------------------------------------------
843 :
844 0 : Fraction Part::currentHarpDiagramTick(const Fraction& tick) const
845 : {
846 0 : if (m_harpDiagrams.empty()) {
847 0 : return Fraction(0, 1);
848 : }
849 0 : auto i = m_harpDiagrams.upper_bound(tick.ticks());
850 0 : if (i == m_harpDiagrams.begin()) {
851 0 : return Fraction(0, 1);
852 : }
853 0 : --i;
854 0 : return Fraction::fromTicks(i->first);
855 : }
856 :
857 475 : String Part::partName() const
858 : {
859 475 : const Instrument* i = instrument();
860 475 : String fullName = i->longName();
861 :
862 475 : const String& transp = i->transposition();
863 475 : if (!transp.empty()) {
864 : //: For instrument transposition, e.g. Horn in F
865 0 : fullName += u" " + muse::mtrc("notation", "in") + u" " + transp;
866 : }
867 :
868 475 : int n = number();
869 475 : if (n != 0) {
870 0 : fullName += u" " + String::number(n);
871 : }
872 :
873 475 : return fullName;
874 0 : }
875 :
876 0 : bool Part::isVisible() const
877 : {
878 0 : return m_show;
879 : }
880 :
881 : //---------------------------------------------------------
882 : // lyricCount
883 : //---------------------------------------------------------
884 :
885 0 : int Part::lyricCount() const
886 : {
887 0 : if (!score()) {
888 0 : return 0;
889 : }
890 :
891 0 : if (!score()->firstMeasure()) {
892 0 : return 0;
893 : }
894 :
895 0 : size_t count = 0;
896 0 : SegmentType st = SegmentType::ChordRest;
897 0 : const TrackRange range = trackRange();
898 0 : for (Segment* seg = score()->firstMeasure()->first(st); seg; seg = seg->next1(st)) {
899 0 : for (track_idx_t i = range.startTrack; i < range.endTrack; ++i) {
900 0 : ChordRest* cr = toChordRest(seg->element(i));
901 0 : if (cr) {
902 0 : count += cr->lyrics().size();
903 : }
904 : }
905 : }
906 0 : return int(count);
907 : }
908 :
909 : //---------------------------------------------------------
910 : // harmonyCount
911 : //---------------------------------------------------------
912 :
913 1915 : int Part::harmonyCount() const
914 : {
915 1915 : if (!score()) {
916 0 : return 0;
917 : }
918 :
919 1915 : Measure* firstM = score()->firstMeasure();
920 1915 : if (!firstM) {
921 8 : return 0;
922 : }
923 :
924 1907 : SegmentType st = SegmentType::ChordRest;
925 1907 : int count = 0;
926 1907 : const TrackRange range = trackRange();
927 32916 : for (const Segment* seg = firstM->first(st); seg; seg = seg->next1(st)) {
928 34512 : for (const EngravingItem* e : seg->annotations()) {
929 7006 : if ((e->isHarmony() || (e->isFretDiagram() && toFretDiagram(e)->harmony())) && e->track() >= range.startTrack
930 7006 : && e->track() < range.endTrack) {
931 601 : count++;
932 : }
933 : }
934 : }
935 1907 : return count;
936 : }
937 :
938 : //---------------------------------------------------------
939 : // updateHarmonyChannels
940 : /// update the harmony channel by creating a new channel
941 : /// when appropriate or using the existing one
942 : ///
943 : /// checkRemoval can be set to true to check to see if we
944 : /// can remove the harmony channel
945 : //---------------------------------------------------------
946 1983 : void Part::updateHarmonyChannels(bool isDoOnInstrumentChanged, bool checkRemoval)
947 : {
948 61 : auto onInstrumentChanged = [this]() {
949 61 : masterScore()->rebuildMidiMapping();
950 61 : masterScore()->updateChannel();
951 61 : score()->setInstrumentsChanged(true);
952 61 : score()->setLayoutAll(); //do we need this?
953 2044 : };
954 :
955 : // usage of harmony count is okay even if expensive since checking harmony channel will shortcircuit if existent
956 : // harmonyCount will only be called on loading of a score (where it will need to be scanned for harmony anyway)
957 : // or when the first harmony of a score is just added
958 1983 : if (checkRemoval) {
959 : //may be a bit expensive since it gets called after every single delete or undo, but it should be okay for now
960 : //~OPTIM~
961 13 : if (harmonyCount() == 0) {
962 4 : Instrument* instr = instrument();
963 4 : int hChIdx = instr->channelIdx(String::fromUtf8(InstrChannel::HARMONY_NAME));
964 4 : if (hChIdx != -1) {
965 3 : InstrChannel* hChan = instr->channel(hChIdx);
966 3 : instr->removeChannel(hChan);
967 3 : delete hChan;
968 3 : if (isDoOnInstrumentChanged) {
969 3 : onInstrumentChanged();
970 : }
971 3 : return;
972 : }
973 : }
974 : }
975 :
976 1980 : if (!harmonyChannel() && harmonyCount() > 0) {
977 58 : Instrument* instr = instrument();
978 58 : InstrChannel* c = new InstrChannel(*instr->channel(0));
979 : // default to program 0, which is piano in General MIDI
980 58 : c->setProgram(0);
981 58 : if (c->bank() == 128) { // drumset?
982 0 : c->setBank(0);
983 : }
984 58 : c->setName(String::fromUtf8(InstrChannel::HARMONY_NAME));
985 58 : instr->appendChannel(c);
986 58 : onInstrumentChanged();
987 : }
988 : }
989 :
990 : //---------------------------------------------------------
991 : // harmonyChannel
992 : //---------------------------------------------------------
993 :
994 2143 : const InstrChannel* Part::harmonyChannel() const
995 : {
996 2143 : const Instrument* instr = instrument();
997 2143 : if (!instr) {
998 0 : return nullptr;
999 : }
1000 :
1001 2143 : int chanIdx = instr->channelIdx(String::fromUtf8(InstrChannel::HARMONY_NAME));
1002 2143 : if (chanIdx == -1) {
1003 2065 : return nullptr;
1004 : }
1005 :
1006 78 : const InstrChannel* chan = instr->channel(chanIdx);
1007 78 : assert(chan);
1008 78 : return chan;
1009 : }
1010 :
1011 163 : bool Part::hasChordSymbol() const
1012 : {
1013 163 : return harmonyChannel() != nullptr;
1014 : }
1015 :
1016 : //---------------------------------------------------------
1017 : // hasPitchedStaff
1018 : //---------------------------------------------------------
1019 :
1020 0 : bool Part::hasPitchedStaff() const
1021 : {
1022 0 : for (Staff* s : staves()) {
1023 0 : if (s && s->isPitchedStaff(Fraction(0, 1))) {
1024 0 : return true;
1025 : }
1026 : }
1027 0 : return false;
1028 : }
1029 :
1030 : //---------------------------------------------------------
1031 : // hasTabStaff
1032 : //---------------------------------------------------------
1033 :
1034 0 : bool Part::hasTabStaff() const
1035 : {
1036 0 : for (Staff* s : staves()) {
1037 0 : if (s && s->isTabStaff(Fraction(0, 1))) {
1038 0 : return true;
1039 : }
1040 : }
1041 0 : return false;
1042 : }
1043 :
1044 : //---------------------------------------------------------
1045 : // hasDrumStaff
1046 : //---------------------------------------------------------
1047 :
1048 2030 : bool Part::hasDrumStaff() const
1049 : {
1050 4015 : for (Staff* s : staves()) {
1051 2049 : if (s && s->isDrumStaff(Fraction(0, 1))) {
1052 64 : return true;
1053 : }
1054 : }
1055 1966 : return false;
1056 : }
1057 : }
|