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 "utils.h"
14 #include "score.h"
15 #include "pitchspelling.h"
16 #include "key.h"
17 #include "staff.h"
18 #include "note.h"
19 #include "harmony.h"
20 #include "segment.h"
21 #include "undo.h"
22 #include "keysig.h"
23 #include "stafftype.h"
24 #include "chord.h"
25 #include "measure.h"
26 #include "fret.h"
27 #include "part.h"
28 
29 namespace Ms {
30 
31 //---------------------------------------------------------
32 //   keydiff2Interval
33 //    keysig -   -7(Cb) - +7(C#)
34 //---------------------------------------------------------
35 
keydiff2Interval(Key oKey,Key nKey,TransposeDirection dir)36 static Interval keydiff2Interval(Key oKey, Key nKey, TransposeDirection dir)
37       {
38       static int stepTable[15] = {
39             // C  G  D  A  E  B Fis
40                0, 4, 1, 5, 2, 6, 3,
41             };
42 
43       int cofSteps;     // circle of fifth steps
44       int diatonic;
45       if (nKey > oKey)
46             cofSteps = int(nKey) - int(oKey);
47       else
48             cofSteps = 12 - (int(oKey) - int(nKey));
49       diatonic = stepTable[(int(nKey) + 7) % 7] - stepTable[(int(oKey) + 7) % 7];
50       if (diatonic < 0)
51             diatonic += 7;
52       diatonic %= 7;
53       int chromatic = (cofSteps * 7) % 12;
54 
55 
56       if ((dir == TransposeDirection::CLOSEST) && (chromatic > 6))
57             dir = TransposeDirection::DOWN;
58 
59       if (dir == TransposeDirection::DOWN) {
60             chromatic = chromatic - 12;
61             diatonic  = diatonic - 7;
62             if (diatonic == -7)
63                   diatonic = 0;
64             if (chromatic == -12)
65                   chromatic = 0;
66             }
67       return Interval(diatonic, chromatic);
68       }
69 
70 /*!
71  * Transposes both pitch and spelling for a note given an interval.
72  *
73  * Uses addition for pitch and transposeTpc() for spelling.
74  *
75  * @param pitch
76  *  The initial (current) pitch. (pitch)
77  * @param tpc
78  *  The initial spelling. (tpc)
79  * @param rpitch
80  *  A pointer to the transposed pitch, calculated by this function. (pitch)
81  * @param rtpc
82  *  A pointer to the transposed spelling. (tcp)
83  * @param interval
84  *  The interval to transpose by.
85  * @param useDoubleSharpsFlats
86  *  Determines whether the output may include double sharps or flats (Abb)
87  *  or should use an enharmonic pitch (Abb = G).
88  */
89 
transposeInterval(int pitch,int tpc,int * rpitch,int * rtpc,Interval interval,bool useDoubleSharpsFlats)90 void transposeInterval(int pitch, int tpc, int* rpitch, int* rtpc, Interval interval,
91    bool useDoubleSharpsFlats)
92       {
93       *rpitch = pitch + interval.chromatic;
94       *rtpc   = transposeTpc(tpc, interval, useDoubleSharpsFlats);
95       }
96 
97 /*!
98  * Transposes a pitch spelling given an interval.
99  *
100  * This function transposes a pitch spelling using first
101  * a diatonic transposition and then calculating any accidentals.
102  * This insures that the note is changed by the correct number of
103  * scale degrees unless it would require too many accidentals.
104  *
105  * @param tpc
106  *  The initial pitch spelling.
107  * @param interval
108  *  The interval to be transposed by.
109  * @param useDoubleSharpsFlats
110  *  Determines whether the output may include double sharps or flats (Abb)
111  *  or should use an enharmonic pitch (Abb = G).
112  *
113  * @return
114  *  The transposed pitch spelling (tpc).
115  */
116 
transposeTpc(int tpc,Interval interval,bool useDoubleSharpsFlats)117 int transposeTpc(int tpc, Interval interval, bool useDoubleSharpsFlats)
118       {
119       if (tpc == Tpc::TPC_INVALID) // perfect unison & perfect octave
120             return tpc;
121 
122       int minAlter;
123       int maxAlter;
124       if (useDoubleSharpsFlats) {
125             minAlter = -2;
126             maxAlter = 2;
127             }
128       else {
129             minAlter = -1;
130             maxAlter = 1;
131             }
132       int steps     = interval.diatonic;
133       int semitones = interval.chromatic;
134 
135 // qDebug("transposeTpc tpc %d steps %d semitones %d", tpc, steps, semitones);
136       if (semitones == 0 && steps == 0)
137             return tpc;
138 
139       int step;
140       int alter;
141       int pitch = tpc2pitch(tpc);
142 
143       for (int k = 0; k < 10; ++k) {
144             step = tpc2step(tpc) + steps;
145             while (step < 0)
146                   step += 7;
147             step   %= 7;
148             int p1 = tpc2pitch(step2tpc(step, AccidentalVal::NATURAL));
149             alter  = semitones - (p1 - pitch);
150             // alter  = p1 + semitones - pitch;
151 
152 //            if (alter < 0) {
153 //                  alter *= -1;
154 //                  alter = 12 - alter;
155 //                  }
156             while (alter < 0)
157                   alter += 12;
158 
159             alter %= 12;
160             if (alter > 6)
161                   alter -= 12;
162             if (alter > maxAlter)
163                   ++steps;
164             else if (alter < minAlter)
165                   --steps;
166             else
167                   break;
168 //            qDebug("  again alter %d steps %d, step %d", alter, steps, step);
169             }
170 //      qDebug("  = step %d alter %d  tpc %d", step, alter, step2tpc(step, alter));
171       return step2tpc(step, AccidentalVal(alter));
172       }
173 
174 //---------------------------------------------------------
175 //   transposeTpcDiatonicByKey
176 //
177 // returns the tpc diatonically transposed by steps, using degrees of given key
178 // option to keep any alteration tpc had with respect to unaltered corresponding degree of key
179 // option to enharmonically reduce tpc using double alterations
180 //---------------------------------------------------------
181 
transposeTpcDiatonicByKey(int tpc,int steps,Key key,bool keepAlteredDegrees,bool useDoubleSharpsFlats)182 int transposeTpcDiatonicByKey(int tpc, int steps, Key key, bool keepAlteredDegrees, bool useDoubleSharpsFlats)
183       {
184       if (tpc == Tpc::TPC_INVALID)
185             return tpc;
186 
187       // get step for tpc with alteration for key
188       int alter;
189       int step = tpc2stepByKey(tpc, key, alter);
190 
191       // transpose step and get tpc for step/key
192       step += steps;
193       int newTpc = step2tpcByKey(step, key);
194 
195       // if required, apply alteration to new tpc
196       if(keepAlteredDegrees)
197             newTpc += alter * TPC_DELTA_SEMITONE;
198 
199       // check results are in ranges
200       while (newTpc > Tpc::TPC_MAX)      newTpc   -= TPC_DELTA_ENHARMONIC;
201       while (newTpc < Tpc::TPC_MIN)      newTpc   += TPC_DELTA_ENHARMONIC;
202 
203       // if required, reduce double alterations
204       if(!useDoubleSharpsFlats) {
205             if(newTpc >= Tpc::TPC_F_SS)  newTpc   -= TPC_DELTA_ENHARMONIC;
206             if(newTpc <= Tpc::TPC_B_BB)  newTpc   += TPC_DELTA_ENHARMONIC;
207             }
208 
209       return newTpc;
210       }
211 
212 //---------------------------------------------------------
213 //   transpose
214 //    return false on failure
215 //---------------------------------------------------------
216 
transpose(Note * n,Interval interval,bool useDoubleSharpsFlats)217 bool Score::transpose(Note* n, Interval interval, bool useDoubleSharpsFlats)
218       {
219       int npitch;
220       int ntpc1, ntpc2;
221       transposeInterval(n->pitch(), n->tpc1(), &npitch, &ntpc1, interval, useDoubleSharpsFlats);
222       if (n->transposition()) {
223             int p;
224             transposeInterval(n->pitch() - n->transposition(), n->tpc2(), &p, &ntpc2, interval, useDoubleSharpsFlats);
225             }
226       else
227             ntpc2 = ntpc1;
228       if (npitch > 127)
229             return false;
230       undoChangePitch(n, npitch, ntpc1, ntpc2);
231       return true;
232       }
233 
234 //---------------------------------------------------------
235 //   transpose
236 //    return false on failure
237 //---------------------------------------------------------
238 
transpose(TransposeMode mode,TransposeDirection direction,Key trKey,int transposeInterval,bool trKeys,bool transposeChordNames,bool useDoubleSharpsFlats)239 bool Score::transpose(TransposeMode mode, TransposeDirection direction, Key trKey,
240   int transposeInterval, bool trKeys, bool transposeChordNames, bool useDoubleSharpsFlats)
241       {
242       bool rangeSelection = selection().isRange();
243       int startStaffIdx   = 0;
244       int endStaffIdx     = 0;
245       Fraction startTick  = Fraction(0,1);
246       if (rangeSelection) {
247             startStaffIdx = selection().staffStart();
248             endStaffIdx   = selection().staffEnd();
249             startTick     = selection().tickStart();
250             }
251 
252       Staff* st = staff(startStaffIdx);
253 
254       Interval interval;
255       if (mode != TransposeMode::DIATONICALLY) {
256             if (mode == TransposeMode::TO_KEY) {
257                   // calculate interval from "transpose to key"
258                   // find the key of the first pitched staff
259                   Key key = Key::C;
260                   for (int i = startStaffIdx; i < endStaffIdx; ++i) {
261                         Staff* s = staff(i);
262                         if (s->isPitchedStaff(startTick)) {
263                               key = s->key(startTick);
264                               if (!styleB(Sid::concertPitch)) {
265                                     int diff = s->part()->instrument(startTick)->transpose().chromatic;
266                                     if (diff)
267                                           key = transposeKey(key, diff, s->part()->preferSharpFlat());
268                                     }
269                               // remember this staff to use as basis in transposing key signatures
270                               st = s;
271                               break;
272                               }
273                         }
274                   if (key != trKey) {
275                         interval = keydiff2Interval(key, trKey, direction);
276                         }
277                   else {      //same key, which direction?
278                         if (direction == TransposeDirection::UP)
279                               interval = Interval(12);
280                         else if (direction == TransposeDirection::DOWN)
281                               interval = Interval(-12);
282                         else  //don't do anything for same key and closest direction
283                               return true;
284                         }
285                   }
286             else {
287                   interval = intervalList[transposeInterval];
288                   if (direction == TransposeDirection::DOWN)
289                         interval.flip();
290                   }
291 
292             if (!rangeSelection) {
293                   trKeys = false;
294                   }
295             bool fullOctave = (interval.chromatic % 12) == 0;
296             if (fullOctave && (mode != TransposeMode::TO_KEY)) {
297                   trKeys = false;
298                   transposeChordNames = false;
299                   }
300             }
301       else  { // diatonic transposition
302             if (direction == TransposeDirection::DOWN)
303                   transposeInterval *= -1;
304             }
305 
306       if (_selection.isList()) {
307             foreach (Element* e, _selection.uniqueElements()) {
308                   if (!e->staff() || e->staff()->staffType(e->tick())->group() == StaffGroup::PERCUSSION)
309                         continue;
310                   if (e->isNote()) {
311                         Note* note = toNote(e);
312                         if (mode == TransposeMode::DIATONICALLY)
313                               note->transposeDiatonic(transposeInterval, trKeys, useDoubleSharpsFlats);
314                         else {
315                               if (!transpose(note, interval, useDoubleSharpsFlats))
316                                     return false;
317                               }
318                         }
319                   else if (e->isHarmony() && transposeChordNames) {
320                         Harmony* h  = toHarmony(e);
321                         int rootTpc, baseTpc;
322                         if (mode == TransposeMode::DIATONICALLY) {
323                               Fraction tick = Fraction(0,1);
324                               if (h->parent()->isSegment())
325                                     tick = toSegment(h->parent())->tick();
326                               else if (h->parent()->isFretDiagram() && h->parent()->parent()->isSegment())
327                                     tick = toSegment(h->parent()->parent())->tick();
328                               Key key = !h->staff() ? Key::C : h->staff()->key(tick);
329                               rootTpc = transposeTpcDiatonicByKey(h->rootTpc(),
330                                           transposeInterval, key, trKeys, useDoubleSharpsFlats);
331                               baseTpc = transposeTpcDiatonicByKey(h->baseTpc(),
332                                           transposeInterval, key, trKeys, useDoubleSharpsFlats);
333                         }
334                         else {
335                               rootTpc = transposeTpc(h->rootTpc(), interval, useDoubleSharpsFlats);
336                               baseTpc = transposeTpc(h->baseTpc(), interval, useDoubleSharpsFlats);
337                               }
338                         undoTransposeHarmony(h, rootTpc, baseTpc);
339                         }
340                   else if (e->isKeySig() && mode != TransposeMode::DIATONICALLY && trKeys) {
341                         // TODO: this currently is disabled in dialog
342                         // if we enabled it, then it will need work
343                         // probably the code should look more like the range selection code
344                         KeySig* ks     = toKeySig(e);
345                         if (!ks->isCustom() && !ks->isAtonal()) {
346                               Key key        = st->key(ks->tick());
347                               KeySigEvent ke = ks->keySigEvent();
348                               ke.setKey(key);
349                               undo(new ChangeKeySig(ks, ke, ks->showCourtesy()));
350                               }
351                         }
352                   }
353             return true;
354             }
355 
356       //--------------------------
357       // process range selection
358       //--------------------------
359 
360       QList<Staff*> sl;
361       for (int staffIdx = _selection.staffStart(); staffIdx < _selection.staffEnd(); ++staffIdx) {
362             Staff* s = staff(staffIdx);
363             if (s->staffType(Fraction(0,1))->group() == StaffGroup::PERCUSSION)      // ignore percussion staff
364                   continue;
365             if (sl.contains(s))
366                   continue;
367             bool alreadyThere = false;
368             for (Staff* s2 : sl) {
369                   if (s2 == s || (s2->links() && s2->links()->contains(s))) {
370                         alreadyThere = true;
371                         break;
372                         }
373                   }
374             if (!alreadyThere)
375                   sl.append(s);
376             }
377       QList<int> tracks;
378       for (Staff* s : sl) {
379             int idx = s->idx() * VOICES;
380             for (int i = 0; i < VOICES; ++i)
381                   tracks.append(idx + i);
382             }
383 
384       Segment* s1 = _selection.startSegment();
385       // if range start on mmRest, get the actual segment instead
386       if (s1->measure()->isMMRest())
387             s1 = tick2segment(s1->tick(), true, s1->segmentType(), false);
388       // if range starts with first CR of measure
389       // then start looping from very beginning of measure
390       // so we include key signature and can transpose that if requested
391       if (s1->rtick().isZero())
392             s1 = s1->measure()->first();
393       Segment* s2 = _selection.endSegment();
394       for (Segment* segment = s1; segment && segment != s2; segment = segment->next1()) {
395             if (!segment->enabled())
396                   continue;
397             for (int track : tracks) {
398                   if (staff(track/VOICES)->staffType(s1->tick())->group() == StaffGroup::PERCUSSION)
399                         continue;
400                   Element* e = segment->element(track);
401                   if (!e)
402                         continue;
403 
404                   if (e->isChord()) {
405                         Chord* chord = toChord(e);
406                         std::vector<Note*> nl = chord->notes();
407                         for (Note* n : nl) {
408                               if (mode == TransposeMode::DIATONICALLY)
409                                     n->transposeDiatonic(transposeInterval, trKeys, useDoubleSharpsFlats);
410                               else {
411                                     if (!transpose(n, interval, useDoubleSharpsFlats))
412                                           return false;
413                                     }
414                               }
415                         for (Chord* g : chord->graceNotes()) {
416                               for (Note* n : g->notes()) {
417                                     if (mode == TransposeMode::DIATONICALLY)
418                                           n->transposeDiatonic(transposeInterval, trKeys, useDoubleSharpsFlats);
419                                     else {
420                                           if (!transpose(n, interval, useDoubleSharpsFlats))
421                                                 return false;
422                                           }
423                                     }
424                               }
425                         }
426                   else if (e->isKeySig() && trKeys && mode != TransposeMode::DIATONICALLY) {
427                         KeySig* ks = toKeySig(e);
428                         Fraction tick = segment->tick();
429                         bool startKey = tick == s1->tick();
430                         bool addKey = ks->isChange();
431                         if ((startKey || addKey) && !ks->isCustom() && !ks->isAtonal()) {
432                               Staff* staff = ks->staff();
433                               Key oKey = ks->key();
434                               if (!styleB(Sid::concertPitch)) {
435                                     Interval i = staff->part()->instrument(tick)->transpose();
436                                     // TODO: here we are converting the instrument-transposed key to concert pitch
437                                     // ideally, we would figure out how to get the original concert pitch key,
438                                     // since the current key may be affected by preferSharpsFlats() setting
439                                     // but ultimately it should not matter,
440                                     // because undoChangeKeySig() is going to change this again
441                                     oKey = transposeKey(oKey, i);
442                                     }
443                               Key nKey = transposeKey(oKey, interval);
444                               KeySigEvent ke = ks->keySigEvent();
445                               ke.setKey(nKey);
446                               // undoChangeKey handles linked staves/parts and generating new keysigs as needed
447                               // it always sets the keysig non-generated
448                               // so only call it when needed
449                               undoChangeKeySig(staff, tick, ke);
450                               }
451                         }
452                   }
453             if (transposeChordNames) {
454                   foreach (Element* e, segment->annotations()) {
455                         if ((e->type() != ElementType::HARMONY) || (!tracks.contains(e->track())))
456                               continue;
457                         Harmony* hh  = toHarmony(e);
458                         int rootTpc, baseTpc;
459                         // undoTransposeHarmony does not do links
460                         // because it is also used to handle transposing instruments
461                         // and score / parts could be in different concert pitch states
462                         for (ScoreElement* se : hh->linkList()) {
463                               Harmony* h = toHarmony(se);
464                               if (mode == TransposeMode::DIATONICALLY) {
465                                     Fraction tick = segment->tick();
466                                     Key key = !h->staff() ? Key::C : h->staff()->key(tick);
467                                     rootTpc = transposeTpcDiatonicByKey(h->rootTpc(),
468                                                 transposeInterval, key, trKeys, useDoubleSharpsFlats);
469                                     baseTpc = transposeTpcDiatonicByKey(h->baseTpc(),
470                                                 transposeInterval, key, trKeys, useDoubleSharpsFlats);
471                                     }
472                               else {
473                                     rootTpc = transposeTpc(h->rootTpc(), interval, useDoubleSharpsFlats);
474                                     baseTpc = transposeTpc(h->baseTpc(), interval, useDoubleSharpsFlats);
475                                     }
476                               undoTransposeHarmony(h, rootTpc, baseTpc);
477                               }
478                         }
479                   }
480             }
481       //
482       // create missing key signatures
483       //
484       if (trKeys && (mode != TransposeMode::DIATONICALLY) && (s1->tick() == Fraction(0,1))) {
485             for (int track : tracks) {
486                   if (track % VOICES)
487                         continue;
488                   Segment* seg = firstMeasure()->undoGetSegmentR(SegmentType::KeySig, Fraction(0,1));
489                   KeySig* ks = toKeySig(seg->element(track));
490                   if (!ks) {
491                         ks = new KeySig(this);
492                         ks->setTrack(track);
493                         Key nKey = transposeKey(Key::C, interval, ks->part()->preferSharpFlat());
494                         ks->setKey(nKey);
495                         ks->setParent(seg);
496                         undoAddElement(ks);
497                         }
498                   }
499             }
500       return true;
501       }
502 
503 //---------------------------------------------------------
504 //   transposeKeys
505 //    key -   -7(Cb) - +7(C#)
506 //---------------------------------------------------------
507 
transposeKeys(int staffStart,int staffEnd,const Fraction & ts,const Fraction & tickEnd,const Interval & interval,bool useInstrument,bool flip)508 void Score::transposeKeys(int staffStart, int staffEnd, const Fraction& ts, const Fraction& tickEnd, const Interval& interval, bool useInstrument, bool flip)
509       {
510       Fraction tickStart(ts);
511       Interval firstInterval = interval;
512       Interval segmentInterval = interval;
513       if (tickStart < Fraction(0,1))            // -1 and 0 are valid values to indicate start of score
514             tickStart = Fraction(0,1);
515       for (int staffIdx = staffStart; staffIdx < staffEnd; ++staffIdx) {
516             Staff* st = staff(staffIdx);
517             if (st->staffType(tickStart)->group() == StaffGroup::PERCUSSION)
518                   continue;
519 
520             bool createKey = tickStart.isZero();
521             for (Segment* s = firstSegment(SegmentType::KeySig); s; s = s->next1(SegmentType::KeySig)) {
522                   if (!s->enabled() || s->tick() < tickStart)
523                         continue;
524                   if (tickEnd != Fraction(-1,1) && s->tick() >= tickEnd)
525                         break;
526                   if (useInstrument) {
527                         segmentInterval = st->part()->instrument(s->tick())->transpose();
528                         if (flip)
529                               segmentInterval.flip();
530                         }
531                   KeySig* ks = toKeySig(s->element(staffIdx * VOICES));
532                   if (!ks || ks->generated())
533                         continue;
534                   if (s->tick().isZero())
535                         createKey = false;
536                   if (!ks->isCustom() && !ks->isAtonal()) {
537                         KeySigEvent ke = st->keySigEvent(s->tick());
538                         PreferSharpFlat pref = ks->part()->preferSharpFlat();
539                         // TODO: if we are transposing to concert pitch,
540                         // then instead of using the part preferSharpFlat() setting,
541                         // we should somehow determine the actual concert pitch key
542                         // eg, if concert pitch for the score as a whole is B, Eb instruments transpose to Ab
543                         // it would be nice if when toggling concert pitch, those instruments were B, not Cb
544                         // the code below makes a bold but unwarranted assumption:
545                         // if you are using the prefer flats option,
546                         // it's because you have sharps in your concert key signatures
547                         // (and vice versa)
548                         // better would be to check other non-transposing staves,
549                         // but ideally we would record and save transposed and concert keys separately
550                         // (like we do tpc1 & tpc2 for notes)
551                         //if (useInstrument && !flip) {
552                         //      if (pref == PreferSharpFlat::FLATS)
553                         //            pref = PreferSharpFlat::SHARPS;
554                         //      else if (pref == PreferSharpFlat::SHARPS)
555                         //            pref = PreferSharpFlat::FLATS;
556                         //      }
557                         Key nKey = transposeKey(ke.key(), segmentInterval, pref);
558                         // remove initial C major key signatures
559                         if (nKey == Key::C && s->tick().isZero()) {
560                               undo(new RemoveElement(ks));
561                               if (s->empty())
562                                     undo(new RemoveElement(s));
563                               }
564                         else {
565                               ke.setKey(nKey);
566                               undo(new ChangeKeySig(ks, ke, ks->showCourtesy()));
567                               }
568                         }
569                   }
570             if (createKey && firstMeasure()) {
571                   KeySig* ks = new KeySig(this);
572                   ks->setTrack(staffIdx * VOICES);
573                   Key nKey = transposeKey(Key::C, firstInterval, ks->part()->preferSharpFlat());
574                   KeySigEvent ke;
575                   ke.setKey(nKey);
576                   ks->setKeySigEvent(ke);
577                   Segment* seg = firstMeasure()->undoGetSegmentR(SegmentType::KeySig, Fraction(0,1));
578                   seg->setHeader(true);
579                   ks->setParent(seg);
580                   undoAddElement(ks);
581                   }
582             }
583       }
584 
585 //---------------------------------------------------------
586 //   transposeSemitone
587 //---------------------------------------------------------
588 
transposeSemitone(int step)589 void Score::transposeSemitone(int step)
590       {
591       if (step == 0)
592             return;
593       if (step > 1)
594             step = 1;
595       if (step < -1)
596             step = -1;
597 
598       TransposeDirection dir = step > 0 ? TransposeDirection::UP : TransposeDirection::DOWN;
599 
600       int keyType = int(staff(0)->key(Fraction(0,1))) + 7;   // ??
601 
602       int intervalListArray[15][2] = {
603             // up - down
604             { 1, 1 },  // Cb
605             { 1, 1 },  // Gb
606             { 1, 1 },  // Db
607             { 1, 1 },  // Ab
608             { 1, 1 },  // Eb
609             { 1, 1 },  // Bb
610             { 1, 1 },  // F
611             { 1, 1 },  // C
612             { 1, 1 },  // G
613             { 1, 1 },  // D
614             { 1, 1 },  // A
615             { 1, 1 },  // E
616             { 1, 1 },  // B
617             { 1, 1 },  // F#
618             { 1, 1 }   // C#
619             };
620 
621       const int interval = intervalListArray[keyType][step > 0 ? 0 : 1];
622 
623       if (!transpose(TransposeMode::BY_INTERVAL, dir, Key::C, interval, true, true, false)) {
624             qDebug("Score::transposeSemitone: failed");
625             // TODO: set error message
626             }
627       else setSelectionChanged(true);
628       }
629 
630 //---------------------------------------------------------
631 //   Note::transposeDiatonic
632 //---------------------------------------------------------
633 
transposeDiatonic(int interval,bool keepAlterations,bool useDoubleAccidentals)634 void Note::transposeDiatonic(int interval, bool keepAlterations, bool useDoubleAccidentals)
635       {
636       // compute note current absolute step
637       int alter;
638       Fraction tick = chord()->segment()->tick();
639       Key key       = staff() ? staff()->key(tick) : Key::C;
640       int absStep   = pitch2absStepByKey(epitch(), tpc(), key, alter);
641 
642       // get pitch and tcp corresponding to unaltered degree for this key
643       int newPitch = absStep2pitchByKey(absStep + interval, key);
644       int newTpc   = step2tpcByKey((absStep + interval) % STEP_DELTA_OCTAVE, key);
645 
646       // if required, transfer original degree alteration to new pitch and tpc
647       if (keepAlterations) {
648             newPitch += alter;
649             newTpc  += alter * TPC_DELTA_SEMITONE;
650             }
651 
652       // transpose appropriately
653       int newTpc1 = TPC_INVALID;
654       int newTpc2 = TPC_INVALID;
655       Interval v   = staff() ? staff()->part()->instrument(tick)->transpose() : Interval(0);
656       if (concertPitch()) {
657             v.flip();
658             newTpc1 = newTpc;
659             newTpc2 = Ms::transposeTpc(newTpc, v, true);
660             }
661       else {
662             newPitch += v.chromatic;
663             newTpc1 = Ms::transposeTpc(newTpc, v, true);
664             newTpc2 = newTpc;
665             }
666 
667       // check results are in ranges
668       while (newPitch > 127)
669             newPitch -= PITCH_DELTA_OCTAVE;
670       while (newPitch < 0)
671             newPitch += PITCH_DELTA_OCTAVE;
672       while (newTpc1 > Tpc::TPC_MAX)
673             newTpc1 -= TPC_DELTA_ENHARMONIC;
674       while (newTpc1 < Tpc::TPC_MIN)
675             newTpc1 += TPC_DELTA_ENHARMONIC;
676       while (newTpc2 > Tpc::TPC_MAX)
677             newTpc2 -= TPC_DELTA_ENHARMONIC;
678       while (newTpc2 < Tpc::TPC_MIN)
679             newTpc2 += TPC_DELTA_ENHARMONIC;
680 
681       // if required, reduce double alterations
682       if (!useDoubleAccidentals) {
683             if (newTpc1 >= Tpc::TPC_F_SS)
684                   newTpc1 -= TPC_DELTA_ENHARMONIC;
685             if (newTpc1 <= Tpc::TPC_B_BB)
686                   newTpc1 += TPC_DELTA_ENHARMONIC;
687             if (newTpc2 >= Tpc::TPC_F_SS)
688                   newTpc2 -= TPC_DELTA_ENHARMONIC;
689             if (newTpc2 <= Tpc::TPC_B_BB)
690                   newTpc2 += TPC_DELTA_ENHARMONIC;
691             }
692 
693       // store new data
694       score()->undoChangePitch(this, newPitch, newTpc1, newTpc2);
695       }
696 
697 //---------------------------------------------------------
698 //   transposeDiatonicAlterations
699 //---------------------------------------------------------
700 
transposeDiatonicAlterations(TransposeDirection direction)701 void Score::transposeDiatonicAlterations(TransposeDirection direction)
702       {
703       // Transpose current selection diatonically (up/down) while keeping degree alterations
704       // Note: Score::transpose() absolutely requires valid selection before invocation.
705       if (!selection().isNone()) {
706             transpose(TransposeMode::DIATONICALLY, direction, Key::C, 1, true, true, true);
707             setPlayNote(true); // For when selection is a single note, also playback that note
708             setSelectionChanged(true); // This will update the on-screen keyboard
709             }
710       }
711 
712 //---------------------------------------------------------
713 //   transpositionChanged
714 //---------------------------------------------------------
715 
transpositionChanged(Part * part,Interval oldV,Fraction tickStart,Fraction tickEnd)716 void Score::transpositionChanged(Part* part, Interval oldV, Fraction tickStart, Fraction tickEnd)
717       {
718       if (tickStart == Fraction(-1,1))
719             tickStart = Fraction(0,1);
720       Interval v = part->instrument(tickStart)->transpose();
721       v.flip();
722       Interval diffV(oldV.chromatic + v.chromatic);
723 
724       // transpose keys first
725       QList<Score*> scores;
726       for (Staff* ls : part->staff(0)->staffList()) {
727             // TODO: special handling for linked staves within a score
728             // could be useful for capo
729             Score* score = ls->score();
730             if (scores.contains(score))
731                   continue;
732             scores.append(score);
733             Part* lp = ls->part();
734             if (!score->styleB(Sid::concertPitch))
735                   score->transposeKeys(lp->startTrack() / VOICES, lp->endTrack() / VOICES, tickStart, tickEnd, diffV);
736             }
737 
738       // now transpose notes and chord symbols
739       for (Segment* s = firstSegment(SegmentType::ChordRest); s; s = s->next1(SegmentType::ChordRest)) {
740             if (s->tick() < tickStart)
741                   continue;
742             if (tickEnd != Fraction(-1,1) && s->tick() >= tickEnd)
743                   break;
744             for (Staff* st : *part->staves()) {
745                   if (st->staffType(tickStart)->group() == StaffGroup::PERCUSSION)
746                         continue;
747                   int t1 = st->idx() * VOICES;
748                   int t2 = t1 + VOICES;
749                   for (int track = t1; track < t2; ++track) {
750                         Element* e = s->element(track);
751                         if (e && e->isChord()) {
752                               Chord* c = toChord(e);
753                               for (Chord* gc : c->graceNotes()) {
754                                     for (Note* n : gc->notes()) {
755                                           int tpc = transposeTpc(n->tpc1(), v, true);
756                                           n->undoChangeProperty(Pid::TPC2, tpc);
757                                           }
758                                     }
759                               for (Note* n : c->notes()) {
760                                     int tpc = transposeTpc(n->tpc1(), v, true);
761                                     n->undoChangeProperty(Pid::TPC2, tpc);
762                                     }
763                               }
764                         // find chord symbols
765                         for (Element* element : s->annotations()) {
766                               if (element->track() != track || element->type() != ElementType::HARMONY)
767                                     continue;
768                               Harmony* h  = toHarmony(element);
769                               int rootTpc = transposeTpc(h->rootTpc(), diffV, false);
770                               int baseTpc = transposeTpc(h->baseTpc(), diffV, false);
771                               for (ScoreElement* scoreElement : h->linkList()) {
772                                     if (!scoreElement->score()->styleB(Sid::concertPitch))
773                                           undoTransposeHarmony(toHarmony(scoreElement), rootTpc, baseTpc);
774                                     }
775                               }
776                         }
777                   }
778             }
779       }
780 }
781 
782