summaryrefslogtreecommitdiffstats
path: root/src/base/Quantizer.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/base/Quantizer.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/base/Quantizer.cpp')
-rw-r--r--src/base/Quantizer.cpp496
1 files changed, 496 insertions, 0 deletions
diff --git a/src/base/Quantizer.cpp b/src/base/Quantizer.cpp
new file mode 100644
index 0000000..c0e4d1b
--- /dev/null
+++ b/src/base/Quantizer.cpp
@@ -0,0 +1,496 @@
+// -*- c-basic-offset: 4 -*-
+
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ 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 "Quantizer.h"
+#include "BaseProperties.h"
+#include "NotationTypes.h"
+#include "Selection.h"
+#include "Composition.h"
+#include "Sets.h"
+#include "Profiler.h"
+
+#include <iostream>
+#include <cmath>
+#include <cstdio> // for sprintf
+#include <ctime>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+//#define DEBUG_NOTATION_QUANTIZER 1
+
+namespace Rosegarden {
+
+Quantizer::Quantizer(std::string source,
+ std::string target) :
+ m_source(source), m_target(target)
+{
+ makePropertyNames();
+}
+
+
+Quantizer::Quantizer(std::string target) :
+ m_target(target)
+{
+ if (target == RawEventData) {
+ m_source = GlobalSource;
+ } else {
+ m_source = RawEventData;
+ }
+
+ makePropertyNames();
+}
+
+
+Quantizer::~Quantizer()
+{
+ // nothing
+}
+
+void
+Quantizer::quantize(Segment *s) const
+{
+ quantize(s, s->begin(), s->getEndMarker());
+}
+
+void
+Quantizer::quantize(Segment *s,
+ Segment::iterator from,
+ Segment::iterator to) const
+{
+ assert(m_toInsert.size() == 0);
+
+ quantizeRange(s, from, to);
+
+ insertNewEvents(s);
+}
+
+void
+Quantizer::quantize(EventSelection *selection)
+{
+ assert(m_toInsert.size() == 0);
+
+ Segment &segment = selection->getSegment();
+
+ // Attempt to handle non-contiguous selections.
+
+ // We have to be a bit careful here, because the rest-
+ // normalisation that's carried out as part of a quantize
+ // process is liable to replace the event that follows
+ // the quantized range. (moved here from editcommands.cpp)
+
+ EventSelection::RangeList ranges(selection->getRanges());
+
+ // So that we can retrieve a list of new events we cheat and stop
+ // the m_toInsert vector from being cleared automatically. Remember
+ // to turn it back on.
+ //
+
+ EventSelection::RangeList::iterator r = ranges.end();
+ while (r-- != ranges.begin()) {
+
+/*
+ cerr << "Quantizer: quantizing range ";
+ if (r->first == segment.end()) {
+ cerr << "end";
+ } else {
+ cerr << (*r->first)->getAbsoluteTime();
+ }
+ cerr << " to ";
+ if (r->second == segment.end()) {
+ cerr << "end";
+ } else {
+ cerr << (*r->second)->getAbsoluteTime();
+ }
+ cerr << endl;
+*/
+
+ quantizeRange(&segment, r->first, r->second);
+ }
+
+ // Push the new events to the selection
+ for (int i = 0; i < m_toInsert.size(); ++i) {
+ selection->addEvent(m_toInsert[i]);
+ }
+
+ // and then to the segment
+ insertNewEvents(&segment);
+}
+
+
+void
+Quantizer::fixQuantizedValues(Segment *s,
+ Segment::iterator from,
+ Segment::iterator to) const
+{
+ assert(m_toInsert.size() == 0);
+
+ quantize(s, from, to);
+
+ if (m_target == RawEventData) return;
+
+ for (Segment::iterator nextFrom = from; from != to; from = nextFrom) {
+
+ ++nextFrom;
+
+ timeT t = getFromTarget(*from, AbsoluteTimeValue);
+ timeT d = getFromTarget(*from, DurationValue);
+ Event *e = new Event(**from, t, d);
+ s->erase(from);
+ m_toInsert.push_back(e);
+ }
+
+ insertNewEvents(s);
+}
+
+
+timeT
+Quantizer::getQuantizedDuration(const Event *e) const
+{
+ if (m_target == RawEventData) {
+ return e->getDuration();
+ } else if (m_target == NotationPrefix) {
+ return e->getNotationDuration();
+ } else {
+ timeT d = e->getDuration();
+ e->get<Int>(m_targetProperties[DurationValue], d);
+ return d;
+ }
+}
+
+timeT
+Quantizer::getQuantizedAbsoluteTime(const Event *e) const
+{
+ if (m_target == RawEventData) {
+ return e->getAbsoluteTime();
+ } else if (m_target == NotationPrefix) {
+ return e->getNotationAbsoluteTime();
+ } else {
+ timeT t = e->getAbsoluteTime();
+ e->get<Int>(m_targetProperties[AbsoluteTimeValue], t);
+ return t;
+ }
+}
+
+timeT
+Quantizer::getUnquantizedAbsoluteTime(Event *e) const
+{
+ return getFromSource(e, AbsoluteTimeValue);
+}
+
+timeT
+Quantizer::getUnquantizedDuration(Event *e) const
+{
+ return getFromSource(e, DurationValue);
+}
+
+void
+Quantizer::quantizeRange(Segment *s,
+ Segment::iterator from,
+ Segment::iterator to) const
+{
+ //!!! It is vital that ordering is maintained after quantization.
+ // That is, an event whose absolute time quantizes to a time t must
+ // appear in the original segment before all events whose times
+ // quantize to greater than t. This means we must quantize the
+ // absolute times of non-note events as well as notes.
+
+ // We don't need to worry about quantizing rests, however; they're
+ // only used for notation and will be explicitly recalculated when
+ // the notation quantization values change.
+
+ for (Segment::iterator nextFrom = from; from != to; from = nextFrom) {
+
+ ++nextFrom;
+ quantizeSingle(s, from);
+ }
+}
+
+void
+Quantizer::unquantize(Segment *s,
+ Segment::iterator from,
+ Segment::iterator to) const
+{
+ assert(m_toInsert.size() == 0);
+
+ for (Segment::iterator nextFrom = from; from != to; from = nextFrom) {
+ ++nextFrom;
+
+ if (m_target == RawEventData || m_target == NotationPrefix) {
+ setToTarget(s, from,
+ getFromSource(*from, AbsoluteTimeValue),
+ getFromSource(*from, DurationValue));
+
+ } else {
+ removeTargetProperties(*from);
+ }
+ }
+
+ insertNewEvents(s);
+}
+
+void
+Quantizer::unquantize(EventSelection *selection) const
+{
+ assert(m_toInsert.size() == 0);
+
+ Segment *s = &selection->getSegment();
+
+ Rosegarden::EventSelection::eventcontainer::iterator it
+ = selection->getSegmentEvents().begin();
+
+ for (; it != selection->getSegmentEvents().end(); it++) {
+
+ if (m_target == RawEventData || m_target == NotationPrefix) {
+
+ Segment::iterator from = s->findSingle(*it);
+ Segment::iterator to = s->findSingle(*it);
+ setToTarget(s, from,
+ getFromSource(*from, AbsoluteTimeValue),
+ getFromSource(*to, DurationValue));
+
+ } else {
+ removeTargetProperties(*it);
+ }
+ }
+
+ insertNewEvents(&selection->getSegment());
+}
+
+
+
+timeT
+Quantizer::getFromSource(Event *e, ValueType v) const
+{
+ Profiler profiler("Quantizer::getFromSource");
+
+// cerr << "Quantizer::getFromSource: source is \"" << m_source << "\"" << endl;
+
+ if (m_source == RawEventData) {
+
+ if (v == AbsoluteTimeValue) return e->getAbsoluteTime();
+ else return e->getDuration();
+
+ } else if (m_source == NotationPrefix) {
+
+ if (v == AbsoluteTimeValue) return e->getNotationAbsoluteTime();
+ else return e->getNotationDuration();
+
+ } else {
+
+ // We need to write the source from the target if the
+ // source doesn't exist (and the target does)
+
+ bool haveSource = e->has(m_sourceProperties[v]);
+ bool haveTarget = ((m_target == RawEventData) ||
+ (e->has(m_targetProperties[v])));
+ timeT t = 0;
+
+ if (!haveSource && haveTarget) {
+ t = getFromTarget(e, v);
+ e->setMaybe<Int>(m_sourceProperties[v], t);
+ return t;
+ }
+
+ e->get<Int>(m_sourceProperties[v], t);
+ return t;
+ }
+}
+
+timeT
+Quantizer::getFromTarget(Event *e, ValueType v) const
+{
+ Profiler profiler("Quantizer::getFromTarget");
+
+ if (m_target == RawEventData) {
+
+ if (v == AbsoluteTimeValue) return e->getAbsoluteTime();
+ else return e->getDuration();
+
+ } else if (m_target == NotationPrefix) {
+
+ if (v == AbsoluteTimeValue) return e->getNotationAbsoluteTime();
+ else return e->getNotationDuration();
+
+ } else {
+ timeT value;
+ if (v == AbsoluteTimeValue) value = e->getAbsoluteTime();
+ else value = e->getDuration();
+ e->get<Int>(m_targetProperties[v], value);
+ return value;
+ }
+}
+
+void
+Quantizer::setToTarget(Segment *s, Segment::iterator i,
+ timeT absTime, timeT duration) const
+{
+ Profiler profiler("Quantizer::setToTarget");
+
+ //cerr << "Quantizer::setToTarget: target is \"" << m_target << "\", absTime is " << absTime << ", duration is " << duration << " (unit is " << m_unit << ", original values are absTime " << (*i)->getAbsoluteTime() << ", duration " << (*i)->getDuration() << ")" << endl;
+
+ timeT st = 0, sd = 0;
+ bool haveSt = false, haveSd = false;
+ if (m_source != RawEventData && m_target == RawEventData) {
+ haveSt = (*i)->get<Int>(m_sourceProperties[AbsoluteTimeValue], st);
+ haveSd = (*i)->get<Int>(m_sourceProperties[DurationValue], sd);
+ }
+
+ Event *e;
+ if (m_target == RawEventData) {
+ e = new Event(**i, absTime, duration);
+ } else if (m_target == NotationPrefix) {
+ // Setting the notation absolute time on an event without
+ // recreating it would be dodgy, just as setting the absolute
+ // time would, because it could change the ordering of events
+ // that are already being referred to in ViewElementLists,
+ // preventing us from locating them in the ViewElementLists
+ // because their ordering would have silently changed
+#ifdef DEBUG_NOTATION_QUANTIZER
+ cout << "Quantizer: setting " << absTime << " to notation absolute time and "
+ << duration << " to notation duration"
+ << endl;
+#endif
+ e = new Event(**i, (*i)->getAbsoluteTime(), (*i)->getDuration(),
+ (*i)->getSubOrdering(), absTime, duration);
+ } else {
+ e = *i;
+ e->clearNonPersistentProperties();
+ }
+
+ if (m_target == NotationPrefix) {
+ timeT normalizeStart = std::min(absTime, (*i)->getAbsoluteTime());
+ timeT normalizeEnd = std::max(absTime + duration,
+ (*i)->getAbsoluteTime() +
+ (*i)->getDuration()) + 1;
+
+ if (m_normalizeRegion.first != m_normalizeRegion.second) {
+ normalizeStart = std::min(normalizeStart, m_normalizeRegion.first);
+ normalizeEnd = std::max(normalizeEnd, m_normalizeRegion.second);
+ }
+
+ m_normalizeRegion = std::pair<timeT, timeT>
+ (normalizeStart, normalizeEnd);
+ }
+
+ if (haveSt) e->setMaybe<Int>(m_sourceProperties[AbsoluteTimeValue],st);
+ if (haveSd) e->setMaybe<Int>(m_sourceProperties[DurationValue], sd);
+
+ if (m_target != RawEventData && m_target != NotationPrefix) {
+ e->setMaybe<Int>(m_targetProperties[AbsoluteTimeValue], absTime);
+ e->setMaybe<Int>(m_targetProperties[DurationValue], duration);
+ } else {
+ s->erase(i);
+ m_toInsert.push_back(e);
+ }
+
+#ifdef DEBUG_NOTATION_QUANTIZER
+ cout << "m_toInsert.size() is now " << m_toInsert.size() << endl;
+#endif
+}
+
+void
+Quantizer::removeProperties(Event *e) const
+{
+ if (m_source != RawEventData) {
+ e->unset(m_sourceProperties[AbsoluteTimeValue]);
+ e->unset(m_sourceProperties[DurationValue]);
+ }
+
+ if (m_target != RawEventData && m_target != NotationPrefix) {
+ e->unset(m_targetProperties[AbsoluteTimeValue]);
+ e->unset(m_targetProperties[DurationValue]);
+ }
+}
+
+void
+Quantizer::removeTargetProperties(Event *e) const
+{
+ if (m_target != RawEventData) {
+ e->unset(m_targetProperties[AbsoluteTimeValue]);
+ e->unset(m_targetProperties[DurationValue]);
+ }
+}
+
+void
+Quantizer::makePropertyNames()
+{
+ if (m_source != RawEventData && m_source != NotationPrefix) {
+ m_sourceProperties[AbsoluteTimeValue] = m_source + "AbsoluteTimeSource";
+ m_sourceProperties[DurationValue] = m_source + "DurationSource";
+ }
+
+ if (m_target != RawEventData && m_target != NotationPrefix) {
+ m_targetProperties[AbsoluteTimeValue] = m_target + "AbsoluteTimeTarget";
+ m_targetProperties[DurationValue] = m_target + "DurationTarget";
+ }
+}
+
+void
+Quantizer::insertNewEvents(Segment *s) const
+{
+ unsigned int sz = m_toInsert.size();
+
+ timeT minTime = m_normalizeRegion.first,
+ maxTime = m_normalizeRegion.second;
+
+ for (unsigned int i = 0; i < sz; ++i) {
+
+ timeT myTime = m_toInsert[i]->getAbsoluteTime();
+ timeT myDur = m_toInsert[i]->getDuration();
+ if (i == 0 || myTime < minTime) minTime = myTime;
+ if (i == 0 || myTime + myDur > maxTime) maxTime = myTime + myDur;
+
+ s->insert(m_toInsert[i]);
+ }
+
+#ifdef DEBUG_NOTATION_QUANTIZER
+ cout << "Quantizer::insertNewEvents: sz is " << sz
+ << ", minTime " << minTime << ", maxTime " << maxTime
+ << endl;
+#endif
+
+ if (m_target == NotationPrefix || m_target == RawEventData) {
+
+ if (m_normalizeRegion.first == m_normalizeRegion.second) {
+ if (sz > 0) {
+ s->normalizeRests(minTime, maxTime);
+ }
+ } else {
+ s->normalizeRests(minTime, maxTime);
+ m_normalizeRegion = std::pair<timeT, timeT>(0, 0);
+ }
+ }
+
+#ifdef DEBUG_NOTATION_QUANTIZER
+ cout << "Quantizer: calling normalizeRests("
+ << minTime << ", " << maxTime << ")" << endl;
+#endif
+
+ m_toInsert.clear();
+}
+
+
+
+
+}