diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
commit | 145364a8af6a1fec06556221e66d4b724a62fc9a (patch) | |
tree | 53bd71a544008c518034f208d64c932dc2883f50 /src/commands/notation/KeyInsertionCommand.cpp | |
download | rosegarden-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.cpp | 264 |
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); + } + } + } +} + +} |