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