summaryrefslogtreecommitdiffstats
path: root/src/base/BasicQuantizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/BasicQuantizer.cpp')
-rw-r--r--src/base/BasicQuantizer.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/base/BasicQuantizer.cpp b/src/base/BasicQuantizer.cpp
new file mode 100644
index 0000000..7cfc0db
--- /dev/null
+++ b/src/base/BasicQuantizer.cpp
@@ -0,0 +1,253 @@
+// -*- 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 "BasicQuantizer.h"
+#include "BaseProperties.h"
+#include "NotationTypes.h"
+#include "Selection.h"
+#include "Composition.h"
+#include "Profiler.h"
+
+#include <iostream>
+#include <cmath>
+#include <cstdio> // for sprintf
+#include <ctime>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace Rosegarden
+{
+
+using namespace BaseProperties;
+
+const std::string Quantizer::RawEventData = "";
+const std::string Quantizer::DefaultTarget = "DefaultQ";
+const std::string Quantizer::GlobalSource = "GlobalQ";
+const std::string Quantizer::NotationPrefix = "Notation";
+
+BasicQuantizer::BasicQuantizer(timeT unit, bool doDurations,
+ int swing, int iterate) :
+ Quantizer(RawEventData),
+ m_unit(unit),
+ m_durations(doDurations),
+ m_swing(swing),
+ m_iterate(iterate)
+{
+ if (m_unit < 0) m_unit = Note(Note::Shortest).getDuration();
+}
+
+BasicQuantizer::BasicQuantizer(std::string source, std::string target,
+ timeT unit, bool doDurations,
+ int swing, int iterate) :
+ Quantizer(source, target),
+ m_unit(unit),
+ m_durations(doDurations),
+ m_swing(swing),
+ m_iterate(iterate)
+{
+ if (m_unit < 0) m_unit = Note(Note::Shortest).getDuration();
+}
+
+BasicQuantizer::BasicQuantizer(const BasicQuantizer &q) :
+ Quantizer(q.m_target),
+ m_unit(q.m_unit),
+ m_durations(q.m_durations),
+ m_swing(q.m_swing),
+ m_iterate(q.m_iterate)
+{
+ // nothing else
+}
+
+BasicQuantizer::~BasicQuantizer()
+{
+ // nothing
+}
+
+void
+BasicQuantizer::quantizeSingle(Segment *s, Segment::iterator i) const
+{
+ timeT d = getFromSource(*i, DurationValue);
+
+ if (d == 0 && (*i)->isa(Note::EventType)) {
+ s->erase(i);
+ return;
+ }
+
+ if (m_unit == 0) return;
+
+ timeT t = getFromSource(*i, AbsoluteTimeValue);
+ timeT d0(d), t0(t);
+
+ timeT barStart = s->getBarStartForTime(t);
+
+ t -= barStart;
+
+ int n = t / m_unit;
+ timeT low = n * m_unit;
+ timeT high = low + m_unit;
+ timeT swingOffset = (m_unit * m_swing) / 300;
+
+ if (high - t > t - low) {
+ t = low;
+ } else {
+ t = high;
+ ++n;
+ }
+
+ if (n % 2 == 1) {
+ t += swingOffset;
+ }
+
+ if (m_durations && d != 0) {
+
+ low = (d / m_unit) * m_unit;
+ high = low + m_unit;
+
+ if (low > 0 && (high - d > d - low)) {
+ d = low;
+ } else {
+ d = high;
+ }
+
+ int n1 = n + d / m_unit;
+
+ if (n % 2 == 0) { // start not swung
+ if (n1 % 2 == 0) { // end not swung
+ // do nothing
+ } else { // end swung
+ d += swingOffset;
+ }
+ } else { // start swung
+ if (n1 % 2 == 0) { // end not swung
+ d -= swingOffset;
+ } else {
+ // do nothing
+ }
+ }
+ }
+
+ t += barStart;
+
+ timeT t1(t), d1(d);
+ t = (t - t0) * m_iterate / 100 + t0;
+ d = (d - d0) * m_iterate / 100 + d0;
+
+ // if an iterative quantize results in something much closer than
+ // the shortest actual note resolution we have, just snap it
+ if (m_iterate != 100) {
+ timeT close = Note(Note::Shortest).getDuration()/2;
+ if (t >= t1 - close && t <= t1 + close) t = t1;
+ if (d >= d1 - close && d <= d1 + close) d = d1;
+ }
+
+ if (t0 != t || d0 != d) setToTarget(s, i, t, d);
+}
+
+
+std::vector<timeT>
+BasicQuantizer::getStandardQuantizations()
+{
+ checkStandardQuantizations();
+ return m_standardQuantizations;
+}
+
+void
+BasicQuantizer::checkStandardQuantizations()
+{
+ if (m_standardQuantizations.size() > 0) return;
+
+ for (Note::Type nt = Note::Semibreve; nt >= Note::Shortest; --nt) {
+
+ int i1 = (nt < Note::Quaver ? 1 : 0);
+ for (int i = 0; i <= i1; ++i) {
+
+ int divisor = (1 << (Note::Semibreve - nt));
+ if (i) divisor = divisor * 3 / 2;
+
+ timeT unit = Note(Note::Semibreve).getDuration() / divisor;
+ m_standardQuantizations.push_back(unit);
+ }
+ }
+}
+
+timeT
+BasicQuantizer::getStandardQuantization(Segment *s)
+{
+ checkStandardQuantizations();
+ timeT unit = -1;
+
+ for (Segment::iterator i = s->begin(); s->isBeforeEndMarker(i); ++i) {
+
+ if (!(*i)->isa(Rosegarden::Note::EventType)) continue;
+ timeT myUnit = getUnitFor(*i);
+ if (unit < 0 || myUnit < unit) unit = myUnit;
+ }
+
+ return unit;
+}
+
+timeT
+BasicQuantizer::getStandardQuantization(EventSelection *s)
+{
+ checkStandardQuantizations();
+ timeT unit = -1;
+
+ if (!s) return 0;
+
+ for (EventSelection::eventcontainer::iterator i =
+ s->getSegmentEvents().begin();
+ i != s->getSegmentEvents().end(); ++i) {
+
+ if (!(*i)->isa(Rosegarden::Note::EventType)) continue;
+ timeT myUnit = getUnitFor(*i);
+ if (unit < 0 || myUnit < unit) unit = myUnit;
+ }
+
+ return unit;
+}
+
+timeT
+BasicQuantizer::getUnitFor(Event *e)
+{
+ timeT absTime = e->getAbsoluteTime();
+ timeT myQuantizeUnit = 0;
+
+ // m_quantizations is in descending order of duration;
+ // stop when we reach one that divides into the note's time
+
+ for (unsigned int i = 0; i < m_standardQuantizations.size(); ++i) {
+ if (absTime % m_standardQuantizations[i] == 0) {
+ myQuantizeUnit = m_standardQuantizations[i];
+ break;
+ }
+ }
+
+ return myQuantizeUnit;
+}
+
+std::vector<timeT>
+BasicQuantizer::m_standardQuantizations;
+
+
+}