1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Rosegarden 5 A MIDI and audio sequencer and musical notation editor. 6 Copyright 2000-2021 the Rosegarden development team. 7 8 Other copyrights also apply to some parts of this work. Please 9 see the AUTHORS file and individual file headers for details. 10 11 This program is free software; you can redistribute it and/or 12 modify it under the terms of the GNU General Public License as 13 published by the Free Software Foundation; either version 2 of the 14 License, or (at your option) any later version. See the file 15 COPYING included with this distribution for more information. 16 */ 17 18 19 #include "RespellCommand.h" 20 21 #include "base/NotationTypes.h" 22 #include "base/Selection.h" 23 #include "document/BasicSelectionCommand.h" 24 #include "document/CommandRegistry.h" 25 #include "base/BaseProperties.h" 26 #include <QString> 27 28 29 namespace Rosegarden 30 { 31 using namespace BaseProperties; 32 using namespace Accidentals; 33 34 QString 35 RespellCommand::getGlobalName(RespellType type) 36 { 37 switch (type.type) { 38 39 case RespellType::Set: { 40 QString s(tr("Respell with %1")); 41 //!!! should be in notationstrings: 42 if (type.accidental == DoubleSharp) { 43 s = s.arg(tr("Do&uble Sharp")); 44 } else if (type.accidental == Sharp) { 45 s = s.arg(tr("&Sharp")); 46 } else if (type.accidental == Flat) { 47 s = s.arg(tr("&Flat")); 48 } else if (type.accidental == DoubleFlat) { 49 s = s.arg(tr("Dou&ble Flat")); 50 } else if (type.accidental == Natural) { 51 s = s.arg(tr("&Natural")); 52 } else { 53 s = s.arg(tr("N&one")); 54 } 55 return s; 56 } 57 58 case RespellType::Up: 59 return tr("Respell Accidentals &Upward"); 60 61 case RespellType::Down: 62 return tr("Respell Accidentals &Downward"); 63 64 case RespellType::Restore: 65 return tr("&Restore Accidentals"); 66 } 67 68 return tr("Respell Accidentals"); 69 } 70 71 RespellCommand::RespellType 72 RespellCommand::getArgument(QString actionName, CommandArgumentQuerier &) 73 { 74 RespellType type; 75 type.type = RespellType::Set; 76 type.accidental = Natural; 77 78 if (actionName == "respell_doubleflat") { 79 type.accidental = DoubleFlat; 80 } else if (actionName == "respell_flat") { 81 type.accidental = Flat; 82 } else if (actionName == "respell_natural") { 83 type.accidental = Natural; 84 } else if (actionName == "respell_sharp") { 85 type.accidental = Sharp; 86 } else if (actionName == "respell_doublesharp") { 87 type.accidental = DoubleSharp; 88 } else if (actionName == "respell_restore") { 89 type.type = RespellType::Restore; 90 } else if (actionName == "respell_up") { 91 type.type = RespellType::Up; 92 } else if (actionName == "respell_down") { 93 type.type = RespellType::Down; 94 } 95 96 return type; 97 } 98 99 void 100 RespellCommand::registerCommand(CommandRegistry *r) 101 { 102 RespellType type; 103 type.type = RespellType::Set; 104 105 type.accidental = DoubleFlat; 106 r->registerCommand 107 ("respell_doubleflat", 108 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 109 110 type.accidental = Flat; 111 r->registerCommand 112 ("respell_flat", 113 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 114 115 type.accidental = Natural; 116 r->registerCommand 117 ("respell_natural", 118 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 119 120 type.accidental = Sharp; 121 r->registerCommand 122 ("respell_sharp", 123 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 124 125 type.accidental = DoubleSharp; 126 r->registerCommand 127 ("respell_doublesharp", 128 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 129 130 type.accidental = Natural; 131 132 type.type = RespellType::Up; 133 r->registerCommand 134 ("respell_up", 135 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 136 137 type.type = RespellType::Down; 138 r->registerCommand 139 ("respell_down", 140 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 141 142 type.type = RespellType::Restore; 143 r->registerCommand 144 ("respell_restore", 145 new ArgumentAndSelectionCommandBuilder<RespellCommand>()); 146 } 147 148 void 149 RespellCommand::modifySegment() 150 { 151 EventSelection::eventcontainer::iterator i; 152 153 for (i = m_selection->getSegmentEvents().begin(); 154 i != m_selection->getSegmentEvents().end(); ++i) { 155 156 if ((*i)->isa(Note::EventType)) { 157 158 if (m_type.type == RespellType::Up || 159 m_type.type == RespellType::Down) { 160 161 Accidental acc = NoAccidental; 162 (*i)->get<String>(ACCIDENTAL, acc); 163 164 if (m_type.type == RespellType::Down) { 165 if (acc == DoubleFlat) { 166 acc = Flat; 167 } else if (acc == Flat || acc == NoAccidental) { 168 acc = Sharp; 169 } else if (acc == Sharp) { 170 acc = DoubleSharp; 171 } 172 } else { 173 if (acc == Flat) { 174 acc = DoubleFlat; 175 } else if (acc == Sharp || acc == NoAccidental) { 176 acc = Flat; 177 } else if (acc == DoubleSharp) { 178 acc = Sharp; 179 } 180 } 181 182 (*i)->set<String>(ACCIDENTAL, acc); 183 184 } else if (m_type.type == RespellType::Set) { 185 186 // trap respelling black key notes as natural; which is 187 // impossible, and makes rawPitchToDisplayPitch() do crazy 188 // things as a consequence (fixes #1349782) 189 // 1 = C#, 3 = D#, 6 = F#, 8 = G#, 10 = A# 190 long pitch; 191 pitch = 0; // Avoid a "may be used uninitialized" compilation warning 192 (*i)->get<Int>(PITCH, pitch); 193 pitch %= 12; 194 if ((pitch == 1 || pitch == 3 || pitch == 6 || pitch == 8 || pitch == 10 ) 195 && m_type.accidental == Natural) { 196 // fail silently; is there anything to do here? 197 } else { 198 (*i)->set<String>(ACCIDENTAL, m_type.accidental); 199 } 200 201 } else { 202 203 (*i)->unset(ACCIDENTAL); 204 } 205 } 206 } 207 } 208 209 } 210