You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/base/BasicQuantizer.cpp

251 lines
5.6 KiB

/*
Rosegarden
A 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 <bownie@bownie.com>
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;
}