1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2011 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "part.h"
14 #include "staff.h"
15 #include "xml.h"
16 #include "score.h"
17 #include "style.h"
18 #include "note.h"
19 #include "drumset.h"
20 #include "instrtemplate.h"
21 #include "text.h"
22 #include "measure.h"
23 #include "stringdata.h"
24 #include "stafftype.h"
25 #include "sym.h"
26 #include "chordrest.h"
27 #include "fret.h"
28
29 namespace Ms {
30
31 //---------------------------------------------------------
32 // Part
33 //---------------------------------------------------------
34
Part(Score * s)35 Part::Part(Score* s)
36 : ScoreElement(s)
37 {
38 _color = DEFAULT_COLOR;
39 _show = true;
40 _soloist = false;
41 _instruments.setInstrument(new Instrument, -1); // default instrument
42 _preferSharpFlat = PreferSharpFlat::DEFAULT;
43 }
44
45 //---------------------------------------------------------
46 // initFromInstrTemplate
47 //---------------------------------------------------------
48
initFromInstrTemplate(const InstrumentTemplate * t)49 void Part::initFromInstrTemplate(const InstrumentTemplate* t)
50 {
51 _partName = t->trackName;
52 setInstrument(Instrument::fromTemplate(t));
53 }
54
55 //---------------------------------------------------------
56 // staff
57 //---------------------------------------------------------
58
staff(int idx) const59 Staff* Part::staff(int idx) const
60 {
61 return _staves[idx];
62 }
63
64 //---------------------------------------------------------
65 // Part::masterPart
66 //---------------------------------------------------------
67
masterPart() const68 const Part* Part::masterPart() const
69 {
70 if (score()->isMaster())
71 return this;
72 if (_staves.empty())
73 return this;
74
75 Staff* st = _staves[0];
76 LinkedElements* links = st->links();
77 if (!links)
78 return this;
79
80 for (ScoreElement* le : *links) {
81 if (le->isStaff() && toStaff(le)->score()->isMaster()) {
82 if (Part* p = toStaff(le)->part())
83 return p;
84 }
85 }
86 return this;
87 }
88
89 //---------------------------------------------------------
90 // Part::masterPart
91 //---------------------------------------------------------
92
masterPart()93 Part* Part::masterPart()
94 {
95 return const_cast<Part*>(const_cast<const Part*>(this)->masterPart());
96 }
97
98 //---------------------------------------------------------
99 // readProperties
100 //---------------------------------------------------------
101
readProperties(XmlReader & e)102 bool Part::readProperties(XmlReader& e)
103 {
104 const QStringRef& tag(e.name());
105 if (tag == "Staff") {
106 Staff* staff = new Staff(score());
107 staff->setPart(this);
108 score()->staves().push_back(staff);
109 _staves.push_back(staff);
110 staff->read(e);
111 }
112 else if (tag == "Instrument") {
113 Instrument* instr = new Instrument;
114 instr->read(e, this);
115 setInstrument(instr, Fraction(-1, 1));
116 }
117 else if (tag == "name")
118 instrument()->setLongName(e.readElementText());
119 else if (tag == "color")
120 _color = e.readInt();
121 else if (tag == "shortName")
122 instrument()->setShortName(e.readElementText());
123 else if (tag == "trackName")
124 _partName = e.readElementText();
125 else if (tag == "show")
126 _show = e.readInt();
127 else if (tag == "soloist")
128 _soloist = e.readInt();
129 else if (tag == "preferSharpFlat")
130 _preferSharpFlat =
131 e.readElementText() == "sharps" ? PreferSharpFlat::SHARPS : PreferSharpFlat::FLATS;
132 else
133 return false;
134 return true;
135 }
136
137 //---------------------------------------------------------
138 // read
139 //---------------------------------------------------------
140
read(XmlReader & e)141 void Part::read(XmlReader& e)
142 {
143 while (e.readNextStartElement()) {
144 if (!readProperties(e))
145 e.unknown();
146 }
147 if (_partName.isEmpty())
148 _partName = instrument()->trackName();
149 }
150
151 //---------------------------------------------------------
152 // write
153 //---------------------------------------------------------
154
write(XmlWriter & xml) const155 void Part::write(XmlWriter& xml) const
156 {
157 xml.stag(this);
158 for (const Staff* staff : _staves)
159 staff->write(xml);
160 if (!_show)
161 xml.tag("show", _show);
162 if (_soloist)
163 xml.tag("soloist", _soloist);
164 xml.tag("trackName", _partName);
165 if (_color != DEFAULT_COLOR)
166 xml.tag("color", _color);
167 if (_preferSharpFlat != PreferSharpFlat::DEFAULT)
168 xml.tag("preferSharpFlat",
169 _preferSharpFlat == PreferSharpFlat::SHARPS ? "sharps" : "flats");
170 instrument()->write(xml, this);
171 xml.etag();
172 }
173
174 //---------------------------------------------------------
175 // setLongNames
176 //---------------------------------------------------------
177
setLongNames(QList<StaffName> & name,const Fraction & tick)178 void Part::setLongNames(QList<StaffName>& name, const Fraction& tick)
179 {
180 instrument(tick)->longNames() = name;
181 }
182
setShortNames(QList<StaffName> & name,const Fraction & tick)183 void Part::setShortNames(QList<StaffName>& name, const Fraction& tick)
184 {
185 instrument(tick)->shortNames() = name;
186 }
187
188 //---------------------------------------------------------
189 // setStaves
190 //---------------------------------------------------------
191
setStaves(int n)192 void Part::setStaves(int n)
193 {
194 int ns = _staves.size();
195 if (n < ns) {
196 qDebug("Part::setStaves(): remove staves not implemented!");
197 return;
198 }
199 int staffIdx = score()->staffIdx(this) + ns;
200 for (int i = ns; i < n; ++i) {
201 Staff* staff = new Staff(score());
202 staff->setPart(this);
203 _staves.push_back(staff);
204 score()->staves().insert(staffIdx, staff);
205 for (Measure* m = score()->firstMeasure(); m; m = m->nextMeasure()) {
206 m->insertStaff(staff, staffIdx);
207 if (m->hasMMRest())
208 m->mmRest()->insertStaff(staff, staffIdx);
209 }
210 ++staffIdx;
211 }
212 }
213
214 //---------------------------------------------------------
215 // insertStaff
216 //---------------------------------------------------------
217
insertStaff(Staff * staff,int idx)218 void Part::insertStaff(Staff* staff, int idx)
219 {
220 if (idx < 0 || idx > _staves.size())
221 idx = _staves.size();
222 _staves.insert(idx, staff);
223 staff->setPart(this);
224 }
225
226 //---------------------------------------------------------
227 // removeStaff
228 //---------------------------------------------------------
229
removeStaff(Staff * staff)230 void Part::removeStaff(Staff* staff)
231 {
232 if (!_staves.removeOne(staff)) {
233 qDebug("Part::removeStaff: not found %p", staff);
234 return;
235 }
236 }
237
238 //---------------------------------------------------------
239 // setMidiProgram
240 // TODO
241 //---------------------------------------------------------
242
setMidiProgram(int program,int bank)243 void Part::setMidiProgram(int program, int bank)
244 {
245 Channel* c = instrument()->channel(0);
246 c->setProgram(program);
247 c->setBank(bank);
248 // instrument()->setChannel(0, c);
249 }
250
251 //---------------------------------------------------------
252 // midiProgram
253 //---------------------------------------------------------
254
midiProgram() const255 int Part::midiProgram() const
256 {
257 return instrument()->playbackChannel(0, masterScore())->program();
258 }
259
260 //---------------------------------------------------------
261 // midiChannel
262 //---------------------------------------------------------
263
midiChannel() const264 int Part::midiChannel() const
265 {
266 return masterScore()->midiChannel(instrument()->channel(0)->channel());
267 }
268
269 //---------------------------------------------------------
270 // midiPort
271 //---------------------------------------------------------
272
midiPort() const273 int Part::midiPort() const
274 {
275 return masterScore()->midiPort(instrument()->channel(0)->channel());
276 }
277
278 //---------------------------------------------------------
279 // setMidiChannel
280 // Called from importmusicxml, importMidi and importGtp*.
281 // Specify tick to set MIDI channel to an InstrumentChange element.
282 // Usage:
283 // setMidiChannel(channel) to set channel
284 // setMidiChannel(-1, port) to set port
285 // setMidiChannel(channel, port) to set both
286 //---------------------------------------------------------
287
setMidiChannel(int ch,int port,const Fraction & tick)288 void Part::setMidiChannel(int ch, int port, const Fraction& tick)
289 {
290 Channel* channel = instrument(tick)->channel(0);
291 if (channel->channel() == -1)
292 masterScore()->addMidiMapping(channel, this, port, ch);
293 else
294 masterScore()->updateMidiMapping(channel, this, port, ch);
295 }
296
297 //---------------------------------------------------------
298 // setInstrument
299 //---------------------------------------------------------
300
setInstrument(Instrument * i,Fraction tick)301 void Part::setInstrument(Instrument* i, Fraction tick)
302 {
303 _instruments.setInstrument(i, tick.ticks());
304 }
305
setInstrument(const Instrument && i,Fraction tick)306 void Part::setInstrument(const Instrument&& i, Fraction tick)
307 {
308 _instruments.setInstrument(new Instrument(i), tick.ticks());
309 }
310
setInstrument(const Instrument & i,Fraction tick)311 void Part::setInstrument(const Instrument& i, Fraction tick)
312 {
313 _instruments.setInstrument(new Instrument(i), tick.ticks());
314 }
315
316 //---------------------------------------------------------
317 // removeInstrument
318 //---------------------------------------------------------
319
removeInstrument(const Fraction & tick)320 void Part::removeInstrument(const Fraction& tick)
321 {
322 auto i = _instruments.find(tick.ticks());
323 if (i == _instruments.end()) {
324 qDebug("Part::removeInstrument: not found at tick %d", tick.ticks());
325 return;
326 }
327 _instruments.erase(i);
328 }
329
330 //---------------------------------------------------------
331 // instrument
332 //---------------------------------------------------------
333
instrument(Fraction tick)334 Instrument* Part::instrument(Fraction tick)
335 {
336 return _instruments.instrument(tick.ticks());
337 }
338
339 //---------------------------------------------------------
340 // instrument
341 //---------------------------------------------------------
342
instrument(Fraction tick) const343 const Instrument* Part::instrument(Fraction tick) const
344 {
345 return _instruments.instrument(tick.ticks());
346 }
347
348 //---------------------------------------------------------
349 // instruments
350 //---------------------------------------------------------
351
instruments() const352 const InstrumentList* Part::instruments() const
353 {
354 return &_instruments;
355 }
356
357 //---------------------------------------------------------
358 // instrumentId
359 //---------------------------------------------------------
360
instrumentId(const Fraction & tick) const361 QString Part::instrumentId(const Fraction& tick) const
362 {
363 return instrument(tick)->instrumentId();
364 }
365
366 //---------------------------------------------------------
367 // longName
368 //---------------------------------------------------------
369
longName(const Fraction & tick) const370 QString Part::longName(const Fraction& tick) const
371 {
372 const QList<StaffName>& nl = longNames(tick);
373 return nl.empty() ? "" : nl[0].name();
374 }
375
376 //---------------------------------------------------------
377 // instrumentName
378 //---------------------------------------------------------
379
instrumentName(const Fraction & tick) const380 QString Part::instrumentName(const Fraction& tick) const
381 {
382 return instrument(tick)->trackName();
383 }
384
385 //---------------------------------------------------------
386 // shortName
387 //---------------------------------------------------------
388
shortName(const Fraction & tick) const389 QString Part::shortName(const Fraction& tick) const
390 {
391 const QList<StaffName>& nl = shortNames(tick);
392 return nl.empty() ? "" : nl[0].name();
393 }
394
395 //---------------------------------------------------------
396 // setLongName
397 //---------------------------------------------------------
398
setLongName(const QString & s)399 void Part::setLongName(const QString& s)
400 {
401 instrument()->setLongName(s);
402 }
403
404 //---------------------------------------------------------
405 // setShortName
406 //---------------------------------------------------------
407
setShortName(const QString & s)408 void Part::setShortName(const QString& s)
409 {
410 instrument()->setShortName(s);
411 }
412
413 //---------------------------------------------------------
414 // setPlainLongName
415 //---------------------------------------------------------
416
setPlainLongName(const QString & s)417 void Part::setPlainLongName(const QString& s)
418 {
419 setLongName(XmlWriter::xmlString(s));
420 }
421
422 //---------------------------------------------------------
423 // setPlainShortName
424 //---------------------------------------------------------
425
setPlainShortName(const QString & s)426 void Part::setPlainShortName(const QString& s)
427 {
428 setShortName(XmlWriter::xmlString(s));
429 }
430
431 //---------------------------------------------------------
432 // getProperty
433 //---------------------------------------------------------
434
getProperty(Pid id) const435 QVariant Part::getProperty(Pid id) const
436 {
437 switch (id) {
438 case Pid::VISIBLE:
439 return QVariant(_show);
440 case Pid::USE_DRUMSET:
441 return instrument()->useDrumset();
442 case Pid::PREFER_SHARP_FLAT:
443 return int(preferSharpFlat());
444 default:
445 return QVariant();
446 }
447 }
448
449 //---------------------------------------------------------
450 // setProperty
451 //---------------------------------------------------------
452
setProperty(Pid id,const QVariant & property)453 bool Part::setProperty(Pid id, const QVariant& property)
454 {
455 switch (id) {
456 case Pid::VISIBLE:
457 setShow(property.toBool());
458 break;
459 case Pid::USE_DRUMSET:
460 instrument()->setUseDrumset(property.toBool());
461 break;
462 case Pid::PREFER_SHARP_FLAT:
463 setPreferSharpFlat(PreferSharpFlat(property.toInt()));
464 break;
465 default:
466 qDebug("Part::setProperty: unknown id %d", int(id));
467 break;
468 }
469 score()->setLayoutAll();
470 return true;
471 }
472
473 //---------------------------------------------------------
474 // startTrack
475 //---------------------------------------------------------
476
startTrack() const477 int Part::startTrack() const
478 {
479 return _staves.front()->idx() * VOICES;
480 }
481
482 //---------------------------------------------------------
483 // endTrack
484 //---------------------------------------------------------
485
endTrack() const486 int Part::endTrack() const
487 {
488 return _staves.back()->idx() * VOICES + VOICES;
489 }
490
491 //---------------------------------------------------------
492 // insertTime
493 //---------------------------------------------------------
494
insertTime(const Fraction & tick,const Fraction & len)495 void Part::insertTime(const Fraction& tick, const Fraction& len)
496 {
497 if (len.isZero())
498 return;
499
500 // move all instruments
501
502 if (len < Fraction(0,1)) {
503 // remove instruments between tickpos >= tick and tickpos < (tick+len)
504 // ownership goes back to class InstrumentChange()
505
506 auto si = _instruments.lower_bound(tick.ticks());
507 auto ei = _instruments.lower_bound((tick-len).ticks());
508 _instruments.erase(si, ei);
509 }
510
511 InstrumentList il;
512 for (auto i = _instruments.lower_bound(tick.ticks()); i != _instruments.end();) {
513 Instrument* instrument = i->second;
514 int t = i->first;
515 _instruments.erase(i++);
516 _instruments[t + len.ticks()] = instrument;
517 }
518 _instruments.insert(il.begin(), il.end());
519 }
520
521 //---------------------------------------------------------
522 // lyricCount
523 //---------------------------------------------------------
524
lyricCount() const525 int Part::lyricCount() const
526 {
527 if (!score())
528 return 0;
529
530 if (!score()->firstMeasure())
531 return 0;
532
533 size_t count = 0;
534 SegmentType st = SegmentType::ChordRest;
535 for (Segment* seg = score()->firstMeasure()->first(st); seg; seg = seg->next1(st)) {
536 for (int i = startTrack(); i < endTrack() ; ++i) {
537 ChordRest* cr = toChordRest(seg->element(i));
538 if (cr)
539 count += cr->lyrics().size();
540 }
541 }
542 return int(count);
543 }
544
545 //---------------------------------------------------------
546 // harmonyCount
547 //---------------------------------------------------------
548
harmonyCount() const549 int Part::harmonyCount() const
550 {
551 if (!score())
552 return 0;
553
554 Measure* firstM = score()->firstMeasure();
555 if (!firstM)
556 return 0;
557
558 SegmentType st = SegmentType::ChordRest;
559 int count = 0;
560 for (const Segment* seg = firstM->first(st); seg; seg = seg->next1(st)) {
561 for (const Element* e : seg->annotations()) {
562 if ((e->isHarmony() || (e->isFretDiagram() && toFretDiagram(e)->harmony())) && e->track() >= startTrack() && e->track() < endTrack())
563 count++;
564 }
565 }
566 return count;
567 }
568
569 //---------------------------------------------------------
570 // updateHarmonyChannels
571 /// update the harmony channel by creating a new channel
572 /// when appropriate or using the existing one
573 ///
574 /// checkRemoval can be set to true to check to see if we
575 /// can remove the harmony channel
576 //---------------------------------------------------------
updateHarmonyChannels(bool isDoOnInstrumentChanged,bool checkRemoval)577 void Part::updateHarmonyChannels(bool isDoOnInstrumentChanged, bool checkRemoval)
578 {
579
580 auto onInstrumentChanged = [this]() {
581 masterScore()->rebuildMidiMapping();
582 masterScore()->updateChannel();
583 score()->setInstrumentsChanged(true);
584 score()->setLayoutAll(); //do we need this?
585 };
586
587
588 // usage of harmony count is okay even if expensive since checking harmony channel will shortcircuit if existent
589 // harmonyCount will only be called on loading of a score (where it will need to be scanned for harmony anyway)
590 // or when the first harmony of a score is just added
591 if (checkRemoval) {
592 //may be a bit expensive since it gets called after every single delete or undo, but it should be okay for now
593 //~OPTIM~
594 if (harmonyCount() == 0) {
595 Instrument* instr = instrument();
596 int hChIdx = instr->channelIdx(Channel::HARMONY_NAME);
597 if (hChIdx != -1) {
598 Channel* hChan = instr->channel(hChIdx);
599 instr->removeChannel(hChan);
600 delete hChan;
601 if (isDoOnInstrumentChanged)
602 onInstrumentChanged();
603 return;
604 }
605 }
606 }
607
608 if (!harmonyChannel() && harmonyCount() > 0) {
609 Instrument* instr = instrument();
610 Channel* c = new Channel(*instr->channel(0));
611 // default to program 0, which is piano in General MIDI
612 c->setProgram(0);
613 if (c->bank() == 128) // drumset?
614 c->setBank(0);
615 c->setName(Channel::HARMONY_NAME);
616 instr->appendChannel(c);
617 onInstrumentChanged();
618 }
619 }
620
621 //---------------------------------------------------------
622 // harmonyChannel
623 //---------------------------------------------------------
624
harmonyChannel() const625 const Channel* Part::harmonyChannel() const
626 {
627 const Instrument* instr = instrument();
628 if (!instr)
629 return nullptr;
630
631 int chanIdx = instr->channelIdx(Channel::HARMONY_NAME);
632 if (chanIdx == -1)
633 return nullptr;
634
635 const Channel* chan = instr->channel(chanIdx);
636 Q_ASSERT(chan);
637 return chan;
638 }
639
640 //---------------------------------------------------------
641 // hasPitchedStaff
642 //---------------------------------------------------------
643
hasPitchedStaff() const644 bool Part::hasPitchedStaff() const
645 {
646 if (!staves())
647 return false;
648 for (Staff* s : *staves()) {
649 if (s && s->isPitchedStaff(Fraction(0,1)))
650 return true;
651 }
652 return false;
653 }
654
655 //---------------------------------------------------------
656 // hasTabStaff
657 //---------------------------------------------------------
658
hasTabStaff() const659 bool Part::hasTabStaff() const
660 {
661 if (!staves())
662 return false;
663 for (Staff* s : *staves()) {
664 if (s && s->isTabStaff(Fraction(0,1)))
665 return true;
666 }
667 return false;
668 }
669
670 //---------------------------------------------------------
671 // hasDrumStaff
672 //---------------------------------------------------------
673
hasDrumStaff() const674 bool Part::hasDrumStaff() const
675 {
676 if (!staves())
677 return false;
678 for (Staff* s : *staves()) {
679 if (s && s->isDrumStaff(Fraction(0,1)))
680 return true;
681 }
682 return false;
683 }
684 }
685
686