2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2002-2011 Werner Schweer
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENCE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include "utils.h"
|
|
|
|
#include "score.h"
|
|
|
|
#include "pitchspelling.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "staff.h"
|
|
|
|
#include "note.h"
|
|
|
|
#include "harmony.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "undo.h"
|
|
|
|
#include "keysig.h"
|
|
|
|
#include "stafftype.h"
|
|
|
|
#include "chord.h"
|
|
|
|
#include "measure.h"
|
2012-12-10 21:15:28 +01:00
|
|
|
#include "fret.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// keydiff2Interval
|
|
|
|
// keysig - -7(Cb) - +7(C#)
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static Interval keydiff2Interval(int oKey, int nKey, TransposeDirection dir)
|
|
|
|
{
|
|
|
|
static int stepTable[15] = {
|
|
|
|
// C G D A E B Fis
|
|
|
|
0, 4, 1, 5, 2, 6, 3,
|
|
|
|
};
|
|
|
|
|
|
|
|
int cofSteps; // circle of fifth steps
|
|
|
|
int diatonic;
|
|
|
|
if (nKey > oKey)
|
|
|
|
cofSteps = nKey - oKey;
|
|
|
|
else
|
|
|
|
cofSteps = 12 - (oKey - nKey);
|
|
|
|
diatonic = stepTable[(nKey + 7) % 7] - stepTable[(oKey + 7) % 7];
|
|
|
|
if (diatonic < 0)
|
|
|
|
diatonic += 7;
|
|
|
|
diatonic %= 7;
|
|
|
|
int chromatic = (cofSteps * 7) % 12;
|
|
|
|
|
|
|
|
|
|
|
|
if ((dir == TRANSPOSE_CLOSEST) && (chromatic > 6))
|
|
|
|
dir = TRANSPOSE_DOWN;
|
|
|
|
|
|
|
|
if (dir == TRANSPOSE_DOWN) {
|
|
|
|
chromatic = chromatic - 12;
|
|
|
|
diatonic = diatonic - 7;
|
|
|
|
if (diatonic == -7)
|
|
|
|
diatonic = 0;
|
|
|
|
if (chromatic == -12)
|
|
|
|
chromatic = 0;
|
|
|
|
}
|
2014-03-25 13:33:47 +01:00
|
|
|
qDebug("TransposeByKey %d -> %d chromatic %d diatonic %d", oKey, nKey, chromatic, diatonic);
|
2012-05-26 14:26:10 +02:00
|
|
|
return Interval(diatonic, chromatic);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Transposes both pitch and spelling for a note given an interval.
|
|
|
|
*
|
|
|
|
* Uses addition for pitch and transposeTpc() for spelling.
|
|
|
|
*
|
|
|
|
* @param pitch
|
|
|
|
* The initial (current) pitch. (pitch)
|
|
|
|
* @param tpc
|
|
|
|
* The initial spelling. (tpc)
|
|
|
|
* @param rpitch
|
|
|
|
* A pointer to the transposed pitch, calculated by this function. (pitch)
|
|
|
|
* @param rtpc
|
|
|
|
* A pointer to the transposed spelling. (tcp)
|
|
|
|
* @param interval
|
|
|
|
* The interval to transpose by.
|
|
|
|
* @param useDoubleSharpsFlats
|
|
|
|
* Determines whether the output may include double sharps or flats (Abb)
|
|
|
|
* or should use an enharmonic pitch (Abb = G).
|
|
|
|
*/
|
|
|
|
|
|
|
|
void transposeInterval(int pitch, int tpc, int* rpitch, int* rtpc, Interval interval,
|
|
|
|
bool useDoubleSharpsFlats)
|
|
|
|
{
|
|
|
|
*rpitch = pitch + interval.chromatic;
|
|
|
|
*rtpc = transposeTpc(tpc, interval, useDoubleSharpsFlats);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Transposes a pitch spelling given an interval.
|
|
|
|
*
|
|
|
|
* This function transposes a pitch spelling using first
|
|
|
|
* a diatonic transposition and then calculating any accidentals.
|
|
|
|
* This insures that the note is changed by the correct number of
|
|
|
|
* scale degrees unless it would require too many accidentals.
|
|
|
|
*
|
|
|
|
* @param tpc
|
|
|
|
* The initial pitch spelling.
|
|
|
|
* @param interval
|
|
|
|
* The interval to be transposed by.
|
|
|
|
* @param useDoubleSharpsFlats
|
|
|
|
* Determines whether the output may include double sharps or flats (Abb)
|
|
|
|
* or should use an enharmonic pitch (Abb = G).
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The transposed pitch spelling (tpc).
|
|
|
|
*/
|
|
|
|
|
|
|
|
int transposeTpc(int tpc, Interval interval, bool useDoubleSharpsFlats)
|
|
|
|
{
|
2014-05-23 21:15:31 +02:00
|
|
|
if (tpc == Tpc::INVALID) // perfect unison & perfect octave
|
2012-05-26 14:26:10 +02:00
|
|
|
return tpc;
|
|
|
|
|
|
|
|
int minAlter;
|
|
|
|
int maxAlter;
|
|
|
|
if (useDoubleSharpsFlats) {
|
|
|
|
minAlter = -2;
|
|
|
|
maxAlter = 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
minAlter = -1;
|
|
|
|
maxAlter = 1;
|
|
|
|
}
|
|
|
|
int steps = interval.diatonic;
|
|
|
|
int semitones = interval.chromatic;
|
|
|
|
|
2014-03-25 13:33:47 +01:00
|
|
|
// qDebug("transposeTpc tpc %d steps %d semitones %d", tpc, steps, semitones);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (semitones == 0 && steps == 0)
|
|
|
|
return tpc;
|
|
|
|
|
2012-08-08 20:46:29 +02:00
|
|
|
int step;
|
|
|
|
int alter;
|
2012-05-26 14:26:10 +02:00
|
|
|
int pitch = tpc2pitch(tpc);
|
|
|
|
|
|
|
|
for (int k = 0; k < 10; ++k) {
|
|
|
|
step = tpc2step(tpc) + steps;
|
|
|
|
while (step < 0)
|
|
|
|
step += 7;
|
|
|
|
step %= 7;
|
2012-08-08 20:46:29 +02:00
|
|
|
int p1 = tpc2pitch(step2tpc(step, NATURAL));
|
|
|
|
alter = AccidentalVal(semitones - (p1 - pitch));
|
2012-05-26 14:26:10 +02:00
|
|
|
// alter = p1 + semitones - pitch;
|
|
|
|
if (alter < 0) {
|
|
|
|
alter *= -1;
|
|
|
|
alter = 12 - alter;
|
|
|
|
}
|
|
|
|
alter %= 12;
|
|
|
|
if (alter > 6)
|
|
|
|
alter -= 12;
|
|
|
|
if (alter > maxAlter)
|
|
|
|
++steps;
|
|
|
|
else if (alter < minAlter)
|
|
|
|
--steps;
|
|
|
|
else
|
|
|
|
break;
|
2014-03-25 13:33:47 +01:00
|
|
|
// qDebug(" again alter %d steps %d, step %d", alter, steps, step);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-03-25 13:33:47 +01:00
|
|
|
// qDebug(" = step %d alter %d tpc %d", step, alter, step2tpc(step, alter));
|
2012-08-08 20:46:29 +02:00
|
|
|
return step2tpc(step, AccidentalVal(alter));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2012-11-14 13:14:56 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// transposeTpcDiatonicByKey
|
|
|
|
//
|
|
|
|
// returns the tpc diatonically transposed by steps, using degrees of given key
|
|
|
|
// option to keep any alteration tpc had with respect to unaltered corresponding degree of key
|
|
|
|
// option to enharmonically reduce tpc using double alterations
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
int transposeTpcDiatonicByKey(int tpc, int steps, int key, bool keepAlteredDegrees, bool useDoubleSharpsFlats)
|
|
|
|
{
|
2014-05-23 21:15:31 +02:00
|
|
|
if (tpc == Tpc::INVALID)
|
2012-11-14 13:14:56 +01:00
|
|
|
return tpc;
|
|
|
|
|
|
|
|
// get step for tpc with alteration for key
|
|
|
|
int alter;
|
|
|
|
int step = tpc2stepByKey(tpc, key, &alter);
|
|
|
|
|
|
|
|
// transpose step and get tpc for step/key
|
|
|
|
step += steps;
|
|
|
|
int newTpc = step2tpcByKey(step, key);
|
|
|
|
|
|
|
|
// if required, apply alteration to new tpc
|
|
|
|
if(keepAlteredDegrees)
|
|
|
|
newTpc += alter * TPC_DELTA_SEMITONE;
|
|
|
|
|
|
|
|
// check results are in ranges
|
2014-05-23 21:15:31 +02:00
|
|
|
while (newTpc > Tpc::MAX) newTpc -= TPC_DELTA_ENHARMONIC;
|
|
|
|
while (newTpc < Tpc::MIN) newTpc += TPC_DELTA_ENHARMONIC;
|
2012-11-14 13:14:56 +01:00
|
|
|
|
|
|
|
// if required, reduce double alterations
|
|
|
|
if(!useDoubleSharpsFlats) {
|
2014-05-23 21:15:31 +02:00
|
|
|
if(newTpc >= Tpc::F_SS) newTpc -= TPC_DELTA_ENHARMONIC;
|
|
|
|
if(newTpc <= Tpc::B_BB) newTpc += TPC_DELTA_ENHARMONIC;
|
2012-11-14 13:14:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return newTpc;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// transposeStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdTransposeStaff(int staffIdx, Interval interval, bool useDoubleSharpsFlats)
|
|
|
|
{
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
if (staff(staffIdx)->staffType()->group() == PERCUSSION_STAFF_GROUP)
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
int startTrack = staffIdx * VOICES;
|
|
|
|
int endTrack = startTrack + VOICES;
|
|
|
|
|
|
|
|
transposeKeys(staffIdx, staffIdx+1, 0, lastSegment()->tick(), interval);
|
|
|
|
|
|
|
|
for (Segment* segment = firstSegment(); segment; segment = segment->next1()) {
|
|
|
|
for (int st = startTrack; st < endTrack; ++st) {
|
|
|
|
Element* e = segment->element(st);
|
2014-05-22 19:49:51 +02:00
|
|
|
if (!e || e->type() != Element::ElementType::CHORD)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
Chord* chord = static_cast<Chord*>(e);
|
|
|
|
QList<Note*> nl = chord->notes();
|
|
|
|
foreach(Note* n, nl)
|
|
|
|
transpose(n, interval, useDoubleSharpsFlats);
|
|
|
|
}
|
2013-04-23 16:12:30 +02:00
|
|
|
foreach (Element* e, segment->annotations()) {
|
2014-05-22 19:49:51 +02:00
|
|
|
if ((e->type() != Element::ElementType::HARMONY) || (e->track() < startTrack) || (e->track() >= endTrack))
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2013-04-23 16:12:30 +02:00
|
|
|
Harmony* h = static_cast<Harmony*>(e);
|
|
|
|
int rootTpc = transposeTpc(h->rootTpc(), interval, false);
|
|
|
|
int baseTpc = transposeTpc(h->baseTpc(), interval, false);
|
|
|
|
undoTransposeHarmony(h, rootTpc, baseTpc);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// transpose
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::transpose(Note* n, Interval interval, bool useDoubleSharpsFlats)
|
|
|
|
{
|
|
|
|
int npitch;
|
2014-04-09 09:40:25 +02:00
|
|
|
int ntpc1, ntpc2;
|
|
|
|
transposeInterval(n->pitch(), n->tpc1(), &npitch, &ntpc1, interval, useDoubleSharpsFlats);
|
2014-04-23 11:23:53 +02:00
|
|
|
if (n->transposition()) {
|
|
|
|
int p;
|
|
|
|
transposeInterval(n->pitch() - n->transposition(), n->tpc2(), &p, &ntpc2, interval, useDoubleSharpsFlats);
|
|
|
|
}
|
2014-04-09 09:40:25 +02:00
|
|
|
else
|
|
|
|
ntpc2 = ntpc1;
|
|
|
|
undoChangePitch(n, npitch, ntpc1, ntpc2);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// transpose
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::transpose(int mode, TransposeDirection direction, int transposeKey,
|
2014-05-26 12:10:59 +02:00
|
|
|
int transposeInterval, bool trKeys, bool transposeChordNames, bool useDoubleSharpsFlats)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-05-26 13:21:04 +02:00
|
|
|
bool rangeSelection = selection().state() == SelState::RANGE;
|
2012-05-26 14:26:10 +02:00
|
|
|
int startStaffIdx = 0;
|
|
|
|
int startTick = 0;
|
|
|
|
if (rangeSelection) {
|
|
|
|
startStaffIdx = selection().staffStart();
|
|
|
|
startTick = selection().tickStart();
|
|
|
|
}
|
|
|
|
KeyList* km = staff(startStaffIdx)->keymap();
|
|
|
|
|
|
|
|
Interval interval;
|
2012-11-14 13:14:56 +01:00
|
|
|
if (mode != TRANSPOSE_DIATONICALLY) {
|
|
|
|
if (mode == TRANSPOSE_BY_KEY) {
|
|
|
|
// calculate interval from "transpose by key"
|
|
|
|
int oKey = km->key(startTick).accidentalType();
|
|
|
|
interval = keydiff2Interval(oKey, transposeKey, direction);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
interval = intervalList[transposeInterval];
|
|
|
|
if (direction == TRANSPOSE_DOWN)
|
|
|
|
interval.flip();
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-11-14 13:14:56 +01:00
|
|
|
if (!rangeSelection) {
|
|
|
|
trKeys = false;
|
|
|
|
}
|
|
|
|
bool fullOctave = (interval.chromatic % 12) == 0;
|
|
|
|
if (fullOctave && (mode != TRANSPOSE_BY_KEY)) {
|
|
|
|
trKeys = false;
|
|
|
|
transposeChordNames = false;
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-11-14 13:14:56 +01:00
|
|
|
else // diatonic transposition
|
|
|
|
if (direction == TRANSPOSE_DOWN)
|
|
|
|
transposeInterval *= -1;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-05-26 13:21:04 +02:00
|
|
|
if (_selection.state() == SelState::LIST) {
|
2014-05-26 12:10:59 +02:00
|
|
|
foreach(Element* e, _selection.uniqueElements()) {
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
if (e->staff()->staffType()->group() == PERCUSSION_STAFF_GROUP)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2014-05-22 19:49:51 +02:00
|
|
|
if (e->type() == Element::ElementType::NOTE) {
|
2012-11-14 13:14:56 +01:00
|
|
|
Note* note = static_cast<Note*>(e);
|
|
|
|
if (mode == TRANSPOSE_DIATONICALLY)
|
|
|
|
note->transposeDiatonic(transposeInterval, trKeys, useDoubleSharpsFlats);
|
|
|
|
else
|
|
|
|
transpose(note, interval, useDoubleSharpsFlats);
|
|
|
|
}
|
2014-05-22 19:49:51 +02:00
|
|
|
else if ((e->type() == Element::ElementType::HARMONY) && transposeChordNames) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Harmony* h = static_cast<Harmony*>(e);
|
2012-11-14 13:14:56 +01:00
|
|
|
int rootTpc, baseTpc;
|
|
|
|
if (mode == TRANSPOSE_DIATONICALLY) {
|
2012-12-10 21:15:28 +01:00
|
|
|
int tick = 0;
|
2014-05-22 19:49:51 +02:00
|
|
|
if (h->parent()->type() == Element::ElementType::SEGMENT)
|
2012-12-10 21:15:28 +01:00
|
|
|
tick = static_cast<Segment*>(h->parent())->tick();
|
2014-05-22 19:49:51 +02:00
|
|
|
else if (h->parent()->type() == Element::ElementType::FRET_DIAGRAM
|
|
|
|
&& h->parent()->parent()->type() == Element::ElementType::SEGMENT) {
|
2012-12-11 10:00:16 +01:00
|
|
|
tick = static_cast<Segment*>(h->parent()->parent())->tick();
|
|
|
|
}
|
2014-05-24 16:27:39 +02:00
|
|
|
int key = !h->staff() ? Key::KEY_C : h->staff()->keymap()->key(tick).accidentalType();
|
2012-11-14 13:14:56 +01:00
|
|
|
rootTpc = transposeTpcDiatonicByKey(h->rootTpc(),
|
|
|
|
transposeInterval, key, trKeys, useDoubleSharpsFlats);
|
|
|
|
baseTpc = transposeTpcDiatonicByKey(h->baseTpc(),
|
|
|
|
transposeInterval, key, trKeys, useDoubleSharpsFlats);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rootTpc = transposeTpc(h->rootTpc(), interval, false);
|
|
|
|
baseTpc = transposeTpc(h->baseTpc(), interval, false);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
undoTransposeHarmony(h, rootTpc, baseTpc);
|
|
|
|
}
|
2014-05-22 19:49:51 +02:00
|
|
|
else if ((e->type() == Element::ElementType::KEYSIG) && mode != TRANSPOSE_DIATONICALLY && trKeys) {
|
2012-05-26 14:26:10 +02:00
|
|
|
KeySig* ks = static_cast<KeySig*>(e);
|
|
|
|
KeySigEvent key = km->key(ks->tick());
|
|
|
|
KeySigEvent okey = km->key(ks->tick() - 1);
|
|
|
|
key.setNaturalType(okey.accidentalType());
|
2014-03-31 13:59:48 +02:00
|
|
|
undo(new ChangeKeySig(ks, key, ks->showCourtesy() /*,
|
|
|
|
ks->showNaturals()*/));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-26 12:10:59 +02:00
|
|
|
//--------------------------
|
|
|
|
// process range selection
|
|
|
|
//--------------------------
|
|
|
|
|
|
|
|
QList<Staff*> sl;
|
|
|
|
for (int staffIdx = _selection.staffStart(); staffIdx < _selection.staffEnd(); ++staffIdx) {
|
|
|
|
Staff* s = staff(staffIdx);
|
|
|
|
if (s->staffType()->group() == PERCUSSION_STAFF_GROUP) // ignore percussion staff
|
|
|
|
continue;
|
|
|
|
if (sl.contains(s))
|
|
|
|
continue;
|
|
|
|
bool alreadyThere = false;
|
|
|
|
for (Staff* s2 : sl) {
|
|
|
|
if (s2 == s || (s2->linkedStaves() && s2->linkedStaves()->staves().contains(s))) {
|
|
|
|
alreadyThere = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!alreadyThere)
|
|
|
|
sl.append(s);
|
|
|
|
}
|
|
|
|
QList<int> tracks;
|
|
|
|
for (Staff* s : sl) {
|
|
|
|
int idx = s->idx() * VOICES;
|
|
|
|
for (int i = 0; i < VOICES; ++i)
|
|
|
|
tracks.append(idx + i);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
for (Segment* segment = _selection.startSegment(); segment && segment != _selection.endSegment(); segment = segment->next1()) {
|
2014-05-26 12:10:59 +02:00
|
|
|
for (int st : tracks) {
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
if (staff(st/VOICES)->staffType()->group() == PERCUSSION_STAFF_GROUP)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
Element* e = segment->element(st);
|
2014-05-22 19:49:51 +02:00
|
|
|
if (!e || e->type() != Element::ElementType::CHORD)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
Chord* chord = static_cast<Chord*>(e);
|
|
|
|
QList<Note*> nl = chord->notes();
|
2013-08-31 17:45:28 +02:00
|
|
|
for (Note* n : nl) {
|
2012-11-14 13:14:56 +01:00
|
|
|
if (mode == TRANSPOSE_DIATONICALLY)
|
|
|
|
n->transposeDiatonic(transposeInterval, trKeys, useDoubleSharpsFlats);
|
|
|
|
else
|
|
|
|
transpose(n, interval, useDoubleSharpsFlats);
|
|
|
|
}
|
2013-08-31 17:45:28 +02:00
|
|
|
for (Chord* g : chord->graceNotes()) {
|
|
|
|
for (Note* n : g->notes()) {
|
|
|
|
if (mode == TRANSPOSE_DIATONICALLY)
|
|
|
|
n->transposeDiatonic(transposeInterval, trKeys, useDoubleSharpsFlats);
|
|
|
|
else
|
|
|
|
transpose(n, interval, useDoubleSharpsFlats);
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
if (transposeChordNames) {
|
|
|
|
foreach (Element* e, segment->annotations()) {
|
2014-05-26 12:10:59 +02:00
|
|
|
if ((e->type() != Element::ElementType::HARMONY) || (!tracks.contains(e->track())))
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
Harmony* h = static_cast<Harmony*>(e);
|
2012-11-14 13:14:56 +01:00
|
|
|
int rootTpc, baseTpc;
|
|
|
|
if (mode == TRANSPOSE_DIATONICALLY) {
|
|
|
|
int tick = segment->tick();
|
2014-05-24 16:27:39 +02:00
|
|
|
int key = !h->staff() ? Key::KEY_C : h->staff()->keymap()->key(tick).accidentalType();
|
2012-11-14 13:14:56 +01:00
|
|
|
rootTpc = transposeTpcDiatonicByKey(h->rootTpc(),
|
|
|
|
transposeInterval, key, trKeys, useDoubleSharpsFlats);
|
|
|
|
baseTpc = transposeTpcDiatonicByKey(h->baseTpc(),
|
|
|
|
transposeInterval, key, trKeys, useDoubleSharpsFlats);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rootTpc = transposeTpc(h->rootTpc(), interval, false);
|
|
|
|
baseTpc = transposeTpc(h->baseTpc(), interval, false);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
undoTransposeHarmony(h, rootTpc, baseTpc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-14 13:14:56 +01:00
|
|
|
if (trKeys && mode != TRANSPOSE_DIATONICALLY) {
|
2012-05-26 14:26:10 +02:00
|
|
|
transposeKeys(_selection.staffStart(), _selection.staffEnd(),
|
|
|
|
_selection.tickStart(), _selection.tickEnd(), interval);
|
|
|
|
}
|
|
|
|
setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// transposeKeys
|
|
|
|
// key - -7(Cb) - +7(C#)
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::transposeKeys(int staffStart, int staffEnd, int tickStart, int tickEnd, const Interval& interval)
|
|
|
|
{
|
|
|
|
for (int staffIdx = staffStart; staffIdx < staffEnd; ++staffIdx) {
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
if (staff(staffIdx)->staffType()->group() == PERCUSSION_STAFF_GROUP)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
KeyList* km = staff(staffIdx)->keymap();
|
2014-04-10 13:13:37 +02:00
|
|
|
for (auto ke = km->lower_bound(tickStart); ke != km->lower_bound(tickEnd); ++ke) {
|
2012-05-26 14:26:10 +02:00
|
|
|
KeySigEvent oKey = ke->second;
|
|
|
|
int tick = ke->first;
|
|
|
|
int nKeyType = transposeKey(oKey.accidentalType(), interval);
|
|
|
|
KeySigEvent nKey;
|
|
|
|
nKey.setAccidentalType(nKeyType);
|
|
|
|
(*km)[tick] = nKey;
|
|
|
|
// undoChangeKey(staff(staffIdx), tick, oKey, nKey);
|
|
|
|
}
|
|
|
|
for (Segment* s = firstSegment(); s; s = s->next1()) {
|
2013-03-05 20:23:59 +01:00
|
|
|
if (s->segmentType() != Segment::SegKeySig)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
if (s->tick() < tickStart)
|
|
|
|
continue;
|
|
|
|
if (s->tick() >= tickEnd)
|
|
|
|
break;
|
|
|
|
KeySig* ks = static_cast<KeySig*>(s->element(staffIdx * VOICES));
|
|
|
|
if (ks) {
|
|
|
|
KeySigEvent key = km->key(s->tick());
|
|
|
|
KeySigEvent okey = km->key(s->tick() - 1);
|
|
|
|
key.setNaturalType(okey.accidentalType());
|
2014-03-31 13:59:48 +02:00
|
|
|
undo(new ChangeKeySig(ks, key, ks->showCourtesy() /*,
|
|
|
|
ks->showNaturals()*/));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// transposeSemitone
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::transposeSemitone(int step)
|
|
|
|
{
|
|
|
|
if (step == 0)
|
|
|
|
return;
|
|
|
|
if (step > 1)
|
|
|
|
step = 1;
|
|
|
|
if (step < -1)
|
|
|
|
step = -1;
|
|
|
|
|
|
|
|
TransposeDirection dir = step > 0 ? TRANSPOSE_UP : TRANSPOSE_DOWN;
|
|
|
|
|
|
|
|
|
|
|
|
KeyList* km = staff(0)->keymap();
|
|
|
|
KeySigEvent key = km->lower_bound(0)->second;
|
|
|
|
int keyType = key.accidentalType() + 7;
|
|
|
|
|
|
|
|
int intervalList[15][2] = {
|
|
|
|
// up - down
|
|
|
|
{ 1, 1 }, // Cb
|
|
|
|
{ 1, 1 }, // Gb
|
|
|
|
{ 1, 1 }, // Db
|
|
|
|
{ 1, 1 }, // Ab
|
|
|
|
{ 1, 1 }, // Eb
|
|
|
|
{ 1, 1 }, // Bb
|
|
|
|
{ 1, 1 }, // F
|
|
|
|
{ 1, 1 }, // C
|
|
|
|
{ 1, 1 }, // G
|
|
|
|
{ 1, 1 }, // D
|
|
|
|
{ 1, 1 }, // A
|
|
|
|
{ 1, 1 }, // E
|
|
|
|
{ 1, 1 }, // B
|
|
|
|
{ 1, 1 }, // F#
|
|
|
|
{ 1, 1 } // C#
|
|
|
|
};
|
|
|
|
|
|
|
|
int interval = intervalList[keyType][step > 0 ? 0 : 1];
|
|
|
|
|
|
|
|
cmdSelectAll();
|
|
|
|
startCmd();
|
|
|
|
transpose(TRANSPOSE_BY_INTERVAL, dir, 0, interval, true, true, false);
|
|
|
|
deselectAll();
|
|
|
|
setLayoutAll(true);
|
|
|
|
endCmd();
|
|
|
|
}
|
|
|
|
|
2012-11-14 13:14:56 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Note::transposeDiatonic
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Note::transposeDiatonic(int interval, bool keepAlterations, bool useDoubleAccidentals)
|
|
|
|
{
|
|
|
|
// compute note current absolute step
|
2014-04-09 09:40:25 +02:00
|
|
|
int alter1;
|
|
|
|
int alter2;
|
|
|
|
int tick = chord()->segment()->tick();
|
2014-05-24 16:27:39 +02:00
|
|
|
int key = !staff() ? Key::KEY_C : staff()->keymap()->key(tick).accidentalType();
|
2014-04-09 09:40:25 +02:00
|
|
|
int absStep1 = pitch2absStepByKey(pitch(), tpc1(), key, &alter1);
|
|
|
|
int absStep2 = pitch2absStepByKey(pitch()-transposition(), tpc2(), key, &alter2);
|
2012-11-14 13:14:56 +01:00
|
|
|
|
|
|
|
// get pitch and tcp corresponding to unaltered degree for this key
|
2014-04-09 09:40:25 +02:00
|
|
|
int newPitch = absStep2pitchByKey(absStep1 + interval, key);
|
|
|
|
int newTpc1 = step2tpcByKey((absStep1 + interval) % STEP_DELTA_OCTAVE, key);
|
|
|
|
int newTpc2 = step2tpcByKey((absStep2 + interval) % STEP_DELTA_OCTAVE, key);
|
2012-11-14 13:14:56 +01:00
|
|
|
|
|
|
|
// if required, transfer original degree alteration to new pitch and tpc
|
2014-04-09 09:40:25 +02:00
|
|
|
if (keepAlterations) {
|
|
|
|
newPitch += alter1;
|
|
|
|
newTpc1 += alter1 * TPC_DELTA_SEMITONE;
|
|
|
|
newTpc2 += alter2 * TPC_DELTA_SEMITONE;
|
2012-11-14 13:14:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// check results are in ranges
|
2014-04-09 09:40:25 +02:00
|
|
|
while (newPitch > 127)
|
|
|
|
newPitch -= PITCH_DELTA_OCTAVE;
|
|
|
|
while (newPitch < 0)
|
|
|
|
newPitch += PITCH_DELTA_OCTAVE;
|
2014-05-23 21:15:31 +02:00
|
|
|
while (newTpc1 > Tpc::MAX)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc1 -= TPC_DELTA_ENHARMONIC;
|
2014-05-23 21:15:31 +02:00
|
|
|
while (newTpc1 < Tpc::MIN)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc1 += TPC_DELTA_ENHARMONIC;
|
2014-05-23 21:15:31 +02:00
|
|
|
while (newTpc2 > Tpc::MAX)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc2 -= TPC_DELTA_ENHARMONIC;
|
2014-05-23 21:15:31 +02:00
|
|
|
while (newTpc2 < Tpc::MIN)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc2 += TPC_DELTA_ENHARMONIC;
|
2012-11-14 13:14:56 +01:00
|
|
|
|
|
|
|
// if required, reduce double alterations
|
2014-04-09 09:40:25 +02:00
|
|
|
if (!useDoubleAccidentals) {
|
2014-05-23 21:15:31 +02:00
|
|
|
if (newTpc1 >= Tpc::F_SS)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc1 -= TPC_DELTA_ENHARMONIC;
|
2014-05-23 21:15:31 +02:00
|
|
|
if (newTpc1 <= Tpc::B_BB)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc1 += TPC_DELTA_ENHARMONIC;
|
2014-05-23 21:15:31 +02:00
|
|
|
if (newTpc2 >= Tpc::F_SS)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc2 -= TPC_DELTA_ENHARMONIC;
|
2014-05-23 21:15:31 +02:00
|
|
|
if (newTpc2 <= Tpc::B_BB)
|
2014-04-09 09:40:25 +02:00
|
|
|
newTpc2 += TPC_DELTA_ENHARMONIC;
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
2012-11-14 13:14:56 +01:00
|
|
|
|
|
|
|
// store new data
|
2014-04-09 09:40:25 +02:00
|
|
|
score()->undoChangePitch(this, newPitch, newTpc1, newTpc2);
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
2012-11-14 13:14:56 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|