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/segment/CreateTempoMapFromSegmentCommand.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/segment/CreateTempoMapFromSegmentCommand.cpp')
-rw-r--r-- | src/commands/segment/CreateTempoMapFromSegmentCommand.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/commands/segment/CreateTempoMapFromSegmentCommand.cpp b/src/commands/segment/CreateTempoMapFromSegmentCommand.cpp new file mode 100644 index 0000000..e548875 --- /dev/null +++ b/src/commands/segment/CreateTempoMapFromSegmentCommand.cpp @@ -0,0 +1,166 @@ +/* -*- 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 "CreateTempoMapFromSegmentCommand.h" + +#include <klocale.h> +#include "misc/Debug.h" +#include "base/Composition.h" +#include "base/NotationTypes.h" +#include "base/RealTime.h" +#include "base/Segment.h" + + +namespace Rosegarden +{ + +CreateTempoMapFromSegmentCommand::CreateTempoMapFromSegmentCommand(Segment *groove) : + KNamedCommand(i18n("Set Tempos from Beat Segment")), + m_composition(groove->getComposition()) +{ + initialise(groove); +} + +CreateTempoMapFromSegmentCommand::~CreateTempoMapFromSegmentCommand() +{ + // nothing +} + +void +CreateTempoMapFromSegmentCommand::execute() +{ + for (TempoMap::iterator i = m_oldTempi.begin(); i != m_oldTempi.end(); ++i) { + int n = m_composition->getTempoChangeNumberAt(i->first); + if (n < m_composition->getTempoChangeCount()) { + m_composition->removeTempoChange(n); + } + } + + for (TempoMap::iterator i = m_newTempi.begin(); i != m_newTempi.end(); ++i) { + m_composition->addTempoAtTime(i->first, i->second); + } +} + +void +CreateTempoMapFromSegmentCommand::unexecute() +{ + for (TempoMap::iterator i = m_newTempi.begin(); i != m_newTempi.end(); ++i) { + int n = m_composition->getTempoChangeNumberAt(i->first); + if (n < m_composition->getTempoChangeCount()) { + m_composition->removeTempoChange(n); + } + } + + for (TempoMap::iterator i = m_oldTempi.begin(); i != m_oldTempi.end(); ++i) { + m_composition->addTempoAtTime(i->first, i->second); + } +} + +void +CreateTempoMapFromSegmentCommand::initialise(Segment *s) +{ + m_oldTempi.clear(); + m_newTempi.clear(); + + //!!! need an additional option: per-chord, per-beat, per-bar. + // Let's work per-beat for the moment. Even for this, we should + // probably use TimeSignature.getDivisions() + + std::vector<timeT> beatTimeTs; + std::vector<RealTime> beatRealTimes; + + int startBar = m_composition->getBarNumber(s->getStartTime()); + int barNo = startBar; + int beat = 0; + + for (Segment::iterator i = s->begin(); s->isBeforeEndMarker(i); ++i) { + if ((*i)->isa(Note::EventType)) { + + bool isNew; + TimeSignature sig = + m_composition->getTimeSignatureInBar(barNo, isNew); + + beatTimeTs.push_back(m_composition->getBarStart(barNo) + + beat * sig.getBeatDuration()); + + if (++beat >= sig.getBeatsPerBar()) { + ++barNo; + beat = 0; + } + + beatRealTimes.push_back(s->getComposition()->getElapsedRealTime + ((*i)->getAbsoluteTime())); + } + } + + if (beatTimeTs.size() < 2) + return ; + + tempoT prevTempo = 0; + + // set up m_oldTempi and prevTempo + + for (int i = m_composition->getTempoChangeNumberAt(*beatTimeTs.begin() - 1) + 1; + i <= m_composition->getTempoChangeNumberAt(*beatTimeTs.end() - 1); ++i) { + + std::pair<timeT, tempoT> tempoChange = + m_composition->getTempoChange(i); + m_oldTempi[tempoChange.first] = tempoChange.second; + if (prevTempo == 0) + prevTempo = tempoChange.second; + } + + RG_DEBUG << "starting tempo: " << prevTempo << endl; + + timeT quarter = Note(Note::Crotchet).getDuration(); + + for (int beat = 1; beat < beatTimeTs.size(); ++beat) { + + timeT beatTime = beatTimeTs[beat] - beatTimeTs[beat - 1]; + RealTime beatRealTime = beatRealTimes[beat] - beatRealTimes[beat - 1]; + + // Calculate tempo to nearest qpm. + // This is 60 / {quarter note duration in seconds} + // = 60 / ( {beat in seconds} * {quarter in ticks} / { beat in ticks} ) + // = ( 60 * {beat in ticks} ) / ( {beat in seconds} * {quarter in ticks} ) + // Precision is deliberately limited to qpm to avoid silly values. + + double beatSec = double(beatRealTime.sec) + + double(beatRealTime.usec() / 1000000.0); + double qpm = (60.0 * beatTime) / (beatSec * quarter); + tempoT tempo = Composition::getTempoForQpm(int(qpm + 0.001)); + + RG_DEBUG << "prev beat: " << beatTimeTs[beat] << ", prev beat real time " << beatRealTimes[beat] << endl; + RG_DEBUG << "time " << beatTime << ", rt " << beatRealTime << ", beatSec " << beatSec << ", tempo " << tempo << endl; + + if (tempo != prevTempo) { + m_newTempi[beatTimeTs[beat - 1]] = tempo; + prevTempo = tempo; + } + } + +} + +} |