summaryrefslogtreecommitdiffstats
path: root/src/commands/notation/KeyInsertionCommand.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 18:37:05 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 18:37:05 +0000
commit145364a8af6a1fec06556221e66d4b724a62fc9a (patch)
tree53bd71a544008c518034f208d64c932dc2883f50 /src/commands/notation/KeyInsertionCommand.cpp
downloadrosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz
rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/commands/notation/KeyInsertionCommand.cpp')
-rw-r--r--src/commands/notation/KeyInsertionCommand.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/commands/notation/KeyInsertionCommand.cpp b/src/commands/notation/KeyInsertionCommand.cpp
new file mode 100644
index 0000000..39b87e2
--- /dev/null
+++ b/src/commands/notation/KeyInsertionCommand.cpp
@@ -0,0 +1,264 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "KeyInsertionCommand.h"
+
+#include "misc/Debug.h"
+#include "base/Event.h"
+#include "base/NotationTypes.h"
+#include "base/Segment.h"
+#include "base/SegmentNotationHelper.h"
+#include "base/Studio.h"
+#include "document/BasicCommand.h"
+#include "base/BaseProperties.h"
+#include <qstring.h>
+
+
+namespace Rosegarden
+{
+
+using namespace BaseProperties;
+
+
+KeyInsertionCommand::KeyInsertionCommand(Segment &segment, timeT time,
+ Key key,
+ bool convert,
+ bool transpose,
+ bool transposeKey,
+ bool ignorePercussion) :
+ BasicCommand(getGlobalName(&key), segment, time, segment.getEndTime()),
+ m_key(key),
+ m_lastInsertedEvent(0),
+ m_convert(convert),
+ m_transpose(transpose),
+ m_transposeKey(transposeKey),
+ m_ignorePercussion(ignorePercussion)
+
+{
+ // nothing
+}
+
+KeyInsertionCommand::~KeyInsertionCommand()
+{
+ // nothing
+}
+
+void
+KeyInsertionCommand::modifySegment()
+{
+ SegmentNotationHelper helper(getSegment());
+ Key oldKey;
+
+ if (m_convert || m_transpose) {
+ oldKey = getSegment().getKeyAtTime(getStartTime());
+ }
+
+ Segment::iterator i = getSegment().findTime(getStartTime());
+ while (getSegment().isBeforeEndMarker(i)) {
+ if ((*i)->getAbsoluteTime() > getStartTime()) {
+ break;
+ }
+ if ((*i)->isa(Key::EventType)) {
+ getSegment().erase(i);
+ break;
+ }
+ ++i;
+ }
+
+ // transpose if desired, according to new dialog option
+ if (m_transposeKey) {
+ // we don't really care about major/minor for this, so pass it through
+ // from the original key
+ bool keyIsMinor = m_key.isMinor();
+
+ // get whether the original key is flat or sharp, so we know what to
+ // prefer for the new key
+ bool keyIsSharp = m_key.isSharp();
+
+ // get the tonic pitch of the user-specified key, reported as a 0-11 int, then
+ // add an extra octave to it to avoid winding up with negative numbers
+ // (the octave will be stripped back off)
+ int specifiedKeyTonic = m_key.getTonicPitch() + 12;
+
+ // get the transpose factor for the segment we're working on
+ int segTranspose = getSegment().getTranspose();
+
+ // subtract the transpose factor from the tonic pitch of the
+ // user-specified key, because we want to move in the opposite
+ // direction for notation (eg. notation is in C major concert, at Bb
+ // transposition, we have -2 from the segment, and want to go +2 for
+ // the key, from tonic pitch 0 (C) to tonic pitch 2 (D) for the key as
+ // written for a Bb instrument
+ //
+ // sanity check: 0 == C; 0 + 12 == 12; (12 - -2) % 12 == 2; 2 == D
+ int transposedKeyTonic = (specifiedKeyTonic - segTranspose) % 12;
+
+ // create a new key with the new tonic pitch, and major/minor from the
+ // original key
+ std::string newKeyName = "";
+
+ switch (transposedKeyTonic) {
+ // 0 C | 1 C# | 2 D | 3 D# | 4 E | 5 F | 6 F# | 7 G | 8 G# | 9 A | 10 A# | 11 B
+ case 0 : // C
+ newKeyName = "C";
+ break;
+ case 2 : // D
+ newKeyName = "D";
+ break;
+ case 4 : // E
+ newKeyName = "E";
+ break;
+ case 5 : // F
+ newKeyName = "F";
+ break;
+ case 7 : // G
+ newKeyName = "G";
+ break;
+ case 9 : // A
+ newKeyName = "A";
+ break;
+ case 11: // B
+ newKeyName = "B";
+ break;
+ // the glorious, glorious black keys need special treatment
+ // again, so we pick flat or sharp spellings based on the
+ // condition of the original, user-specified key we're
+ // transposing
+ case 1 : // C#/Db
+ newKeyName = (keyIsSharp ? "C#" : "Db");
+ break;
+ case 3 : // D#/Eb
+ newKeyName = (keyIsSharp ? "D#" : "Eb");
+ break;
+ case 6 : // F#/Gb
+ newKeyName = (keyIsSharp ? "F#" : "Gb");
+ break;
+ case 8 : // G#/Ab
+ newKeyName = (keyIsSharp ? "G#" : "Ab");
+ break;
+ case 10: // A#/Bb
+ newKeyName = (keyIsSharp ? "A#" : "Bb");
+ break;
+ default:
+ // if this fails, we won't have a valid key name, and
+ // there will be some crashing exception I don't know how
+ // to intercept and avoid, so I'm doing this lame failsafe
+ // instead, which should never, ever actually run under
+ // any conceivable cirumstance anyway
+ RG_DEBUG << "KeyInsertionCommand: by the pricking of my thumbs, something wicked this way comes. :("
+ << endl;
+ return ;
+ }
+
+ newKeyName += (keyIsMinor ? " minor" : " major");
+
+ //for f in C# D# E# F# G# A# B# Cb Db Eb Fb Gb Ab Bb;do grep "$f
+ //major" NotationTypes.C > /dev/null||echo "invalid key: $f
+ //major";grep "$f minor" NotationTypes.C > /dev/null||echo "invalid
+ //key: $f minor";done|sort
+ //invalid key: A# major
+ //invalid key: B# major
+ //invalid key: B# minor
+ //invalid key: Cb minor
+ //invalid key: Db minor
+ //invalid key: D# major
+ //invalid key: E# major
+ //invalid key: E# minor
+ //invalid key: Fb major
+ //invalid key: Fb minor
+ //invalid key: Gb minor
+ //invalid key: G# major
+
+ // some kludgery to avoid creating invalid key names with some if/then
+ // swapping to manually respell things generated incorrectly by the
+ // above, rather than adding all kinds of nonsense to avoid this
+ // necessity
+ if (newKeyName == "A# major")
+ newKeyName = "Bb major";
+ else if (newKeyName == "B# major")
+ newKeyName = "C major";
+ else if (newKeyName == "Cb minor")
+ newKeyName = "B minor";
+ else if (newKeyName == "Db minor")
+ newKeyName = "C# minor";
+ else if (newKeyName == "D# major")
+ newKeyName = "Eb major";
+ else if (newKeyName == "E# major")
+ newKeyName = "F major";
+ else if (newKeyName == "E# minor")
+ newKeyName = "F minor";
+ else if (newKeyName == "Fb major")
+ newKeyName = "E major";
+ else if (newKeyName == "Fb minor")
+ newKeyName = "E minor";
+ else if (newKeyName == "Gb minor")
+ newKeyName = "F# minor";
+ else if (newKeyName == "G# major")
+ newKeyName = "Ab major";
+
+ // create a new key with the newly derived name, and swap it for the
+ // user-specified version
+ Key k(newKeyName);
+ RG_DEBUG << "KeyInsertCommand: inserting transposed key" << endl
+ << " user key was: " << m_key.getName() << endl
+ << " tranposed key is: " << k.getName() << endl;
+ m_key = k;
+ } // if (m_transposeKey)
+
+ i = helper.insertKey(getStartTime(), m_key);
+
+ if (i != helper.segment().end()) {
+
+ m_lastInsertedEvent = *i;
+ if (!m_convert && !m_transpose)
+ return ;
+
+ while (++i != helper.segment().end()) {
+
+ //!!! what if we get two keys at the same time...?
+ if ((*i)->isa(Key::EventType))
+ break;
+
+ if ((*i)->isa(Note::EventType) &&
+ (*i)->has(PITCH)) {
+
+ long pitch = (*i)->get
+ <Int>(PITCH);
+
+ if (m_convert) {
+ (*i)->set
+ <Int>(PITCH, m_key.convertFrom(pitch, oldKey));
+ } else {
+ (*i)->set
+ <Int>(PITCH, m_key.transposeFrom(pitch, oldKey));
+ }
+
+ (*i)->unset(ACCIDENTAL);
+ }
+ }
+ }
+}
+
+}