1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2008-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 "instrchange.h"
14 #include "score.h"
15 #include "segment.h"
16 #include "staff.h"
17 #include "part.h"
18 #include "undo.h"
19 #include "mscore.h"
20 #include "xml.h"
21 #include "measure.h"
22 #include "system.h"
23 #include "chord.h"
24 #include "keysig.h"
25 
26 namespace Ms {
27 
28 //---------------------------------------------------------
29 //   instrumentChangeStyle
30 //---------------------------------------------------------
31 
32 static const ElementStyle instrumentChangeStyle {
33       { Sid::instrumentChangePlacement,          Pid::PLACEMENT              },
34       { Sid::instrumentChangeMinDistance,        Pid::MIN_DISTANCE           },
35       };
36 
37 //---------------------------------------------------------
38 //   InstrumentChange
39 //---------------------------------------------------------
40 
InstrumentChange(Score * s)41 InstrumentChange::InstrumentChange(Score* s)
42    : TextBase(s, Tid::INSTRUMENT_CHANGE, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
43       {
44       initElementStyle(&instrumentChangeStyle);
45       _instrument = new Instrument();
46       }
47 
InstrumentChange(const Instrument & i,Score * s)48 InstrumentChange::InstrumentChange(const Instrument& i, Score* s)
49    : TextBase(s, Tid::INSTRUMENT_CHANGE, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
50       {
51       initElementStyle(&instrumentChangeStyle);
52       _instrument = new Instrument(i);
53       }
54 
InstrumentChange(const InstrumentChange & is)55 InstrumentChange::InstrumentChange(const InstrumentChange& is)
56    : TextBase(is)
57       {
58       _instrument = new Instrument(*is._instrument);
59       _init = is._init;
60       }
61 
~InstrumentChange()62 InstrumentChange::~InstrumentChange()
63       {
64       delete _instrument;
65       }
66 
setInstrument(const Instrument & i)67 void InstrumentChange::setInstrument(const Instrument& i)
68       {
69       *_instrument = i;
70       //delete _instrument;
71       //_instrument = new Instrument(i);
72       }
73 
setupInstrument(const Instrument * instrument)74 void InstrumentChange::setupInstrument(const Instrument* instrument)
75       {
76       if (_init) {
77             Fraction tickStart = segment()->tick();
78             Part* part = staff()->part();
79             Interval oldV = part->instrument(tickStart)->transpose();
80 
81             // change the clef for each staff
82             for (int i = 0; i < part->nstaves(); i++) {
83                   if (part->instrument(tickStart)->clefType(i) != instrument->clefType(i)) {
84                         ClefType clefType = score()->styleB(Sid::concertPitch) ? instrument->clefType(i)._concertClef : instrument->clefType(i)._transposingClef;
85                         // If instrument change is at the start of a measure, use the measure as the element, as this will place the instrument change before the barline.
86                         Element* element = rtick().isZero() ? toElement(findMeasure()) : toElement(this);
87                         score()->undoChangeClef(part->staff(i), element, clefType, true);
88                   }
89             }
90 
91             // Change key signature if necessary
92             if (instrument->transpose() != oldV) {
93                   for (int i = 0; i < part->nstaves(); i++) {
94                         if (!part->staff(i)->keySigEvent(tickStart).isAtonal()) {
95                               KeySigEvent ks;
96                               ks.setForInstrumentChange(true);
97                               Key key = part->staff(i)->key(tickStart);
98                               if (!score()->styleB(Sid::concertPitch))
99                                     key = transposeKey(key, oldV);
100                               ks.setKey(key);
101                               score()->undoChangeKeySig(part->staff(i), tickStart, ks);
102                               }
103                         }
104                   }
105 
106             // change instrument in all linked scores
107             for (ScoreElement* se : linkList()) {
108                   InstrumentChange* lic = static_cast<InstrumentChange*>(se);
109                   Instrument* newInstrument = new Instrument(*instrument);
110                   lic->score()->undo(new ChangeInstrument(lic, newInstrument));
111                   }
112 
113             // transpose for current score only
114             // this automatically propagates to linked scores
115             if (part->instrument(tickStart)->transpose() != oldV) {
116                   auto i = part->instruments()->upper_bound(tickStart.ticks());    // find(), ++i
117                   Fraction tickEnd;
118                   if (i == part->instruments()->end())
119                         tickEnd = Fraction(-1, 1);
120                   else
121                         tickEnd = Fraction::fromTicks(i->first);
122                   score()->transpositionChanged(part, oldV, tickStart, tickEnd);
123                   }
124 
125             const QString newInstrChangeText = tr("To %1").arg(instrument->trackName());
126             undoChangeProperty(Pid::TEXT, TextBase::plainToXmlText(newInstrChangeText));
127             }
128       }
129 
130 //---------------------------------------------------------
131 //   keySigs
132 //---------------------------------------------------------
133 
keySigs() const134 std::vector<KeySig*> InstrumentChange::keySigs() const
135       {
136       std::vector<KeySig*> keysigs;
137       Segment* seg = segment()->prev1(SegmentType::KeySig);
138       if (seg) {
139             int startVoice = part()->staff(0)->idx() * VOICES;
140             int endVoice = part()->staff(part()->nstaves() - 1)->idx() * VOICES;
141             Fraction t = tick();
142             for (int i = startVoice; i <= endVoice; i += VOICES) {
143                   KeySig* ks = toKeySig(seg->element(i));
144                   if (ks && ks->forInstrumentChange() && ks->tick() == t)
145                         keysigs.push_back(ks);
146                   }
147             }
148       return keysigs;
149       }
150 
151 //---------------------------------------------------------
152 //   clefs
153 //---------------------------------------------------------
154 
clefs() const155 std::vector<Clef*> InstrumentChange::clefs() const
156       {
157       std::vector<Clef*> clefs;
158       Segment* seg = segment()->prev1(SegmentType::Clef);
159       if (seg) {
160             int startVoice = part()->staff(0)->idx() * VOICES;
161             int endVoice = part()->staff(part()->nstaves() - 1)->idx() * VOICES;
162             Fraction t = tick();
163             for (int i = startVoice; i <= endVoice; i += VOICES) {
164                   Clef* clef = toClef(seg->element(i));
165                   if (clef && clef->forInstrumentChange() && clef->tick() == t)
166                         clefs.push_back(clef);
167                   }
168             }
169       return clefs;
170       }
171 
172 //---------------------------------------------------------
173 //   write
174 //---------------------------------------------------------
175 
write(XmlWriter & xml) const176 void InstrumentChange::write(XmlWriter& xml) const
177       {
178       xml.stag(this);
179       _instrument->write(xml, part());
180       if (_init)
181             xml.tag("init", _init);
182       TextBase::writeProperties(xml);
183       xml.etag();
184       }
185 
186 //---------------------------------------------------------
187 //   read
188 //---------------------------------------------------------
189 
read(XmlReader & e)190 void InstrumentChange::read(XmlReader& e)
191       {
192       while (e.readNextStartElement()) {
193             const QStringRef& tag(e.name());
194             if (tag == "Instrument")
195                   _instrument->read(e, part());
196             else if (tag == "init")
197                   _init = e.readBool();
198             else if (!TextBase::readProperties(e))
199                   e.unknown();
200             }
201       if (score()->mscVersion() < 206) {
202             // previous versions did not honor transposition of instrument change
203             // except in ways that it should not have
204             // notes entered before the instrument change was added would not be altered,
205             // so original transposition remained in effect
206             // notes added afterwards would be transposed by both intervals, resulting in tpc corruption
207             // here we set the instrument change to inherit the staff transposition to emulate previous versions
208             // in Note::read(), we attempt to fix the tpc corruption
209             // There is also code in read206 to try to deal with this, but it is out of date and therefore disabled
210             // What this means is, scores created in 2.1 or later should be fine, scores created in 2.0 maybe not so much
211 
212             Interval v = staff() ? staff()->part()->instrument(tick())->transpose() : 0;
213             _instrument->setTranspose(v);
214             }
215       }
216 
217 //---------------------------------------------------------
218 //   propertyDefault
219 //---------------------------------------------------------
220 
propertyDefault(Pid propertyId) const221 QVariant InstrumentChange::propertyDefault(Pid propertyId) const
222       {
223       switch (propertyId) {
224             case Pid::SUB_STYLE:
225                   return int(Tid::INSTRUMENT_CHANGE);
226             default:
227                   return TextBase::propertyDefault(propertyId);
228             }
229       }
230 
231 //---------------------------------------------------------
232 //   layout
233 //---------------------------------------------------------
234 
layout()235 void InstrumentChange::layout()
236       {
237       TextBase::layout();
238       autoplaceSegmentElement();
239       }
240 
241 }
242 
243