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/RulerScale.cpp

244 lines
5.3 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 <cmath>
#include "RulerScale.h"
#include "Composition.h"
namespace Rosegarden {
//////////////////////////////////////////////////////////////////////
// RulerScale
//////////////////////////////////////////////////////////////////////
RulerScale::RulerScale(Composition *c) :
m_composition(c)
{
// nothing
}
RulerScale::~RulerScale()
{
// nothing
}
int
RulerScale::getFirstVisibleBar() const
{
return m_composition->getBarNumber(m_composition->getStartMarker());
}
int
RulerScale::getLastVisibleBar() const
{
return m_composition->getBarNumber(m_composition->getEndMarker());
}
double
RulerScale::getBarWidth(int n) const
{
return getBarPosition(n + 1) - getBarPosition(n);
}
double
RulerScale::getBeatWidth(int n) const
{
std::pair<timeT, timeT> barRange = m_composition->getBarRange(n);
timeT barDuration = barRange.second - barRange.first;
if (barDuration == 0) return 0;
bool isNew;
TimeSignature timeSig = m_composition->getTimeSignatureInBar(n, isNew);
// cope with partial bars
double theoreticalWidth =
(getBarWidth(n) * timeSig.getBarDuration()) / barDuration;
return theoreticalWidth / timeSig.getBeatsPerBar();
}
int
RulerScale::getBarForX(double x) const
{
// binary search
int minBar = getFirstVisibleBar(),
maxBar = getLastVisibleBar();
while (maxBar > minBar) {
int middle = minBar + (maxBar - minBar) / 2;
if (x > getBarPosition(middle)) minBar = middle + 1;
else maxBar = middle;
}
// we've just done equivalent of lower_bound -- we're one bar too
// far into the list
if (minBar > getFirstVisibleBar()) return minBar - 1;
else return minBar;
}
timeT
RulerScale::getTimeForX(double x) const
{
int n = getBarForX(x);
double barWidth = getBarWidth(n);
std::pair<timeT, timeT> barRange = m_composition->getBarRange(n);
if (barWidth < 1.0) {
return barRange.first;
} else {
timeT barDuration = barRange.second - barRange.first;
x -= getBarPosition(n);
return barRange.first + (timeT)nearbyint(((double)(x * barDuration) / barWidth));
}
}
double
RulerScale::getXForTime(timeT time) const
{
int n = m_composition->getBarNumber(time);
double barWidth = getBarWidth(n);
std::pair<timeT, timeT> barRange = m_composition->getBarRange(n);
timeT barDuration = barRange.second - barRange.first;
if (barDuration == 0) {
return getBarPosition(n);
} else {
time -= barRange.first;
return getBarPosition(n) + (double)(time * barWidth) / barDuration;
}
}
timeT
RulerScale::getDurationForWidth(double x, double width) const
{
return getTimeForX(x + width) - getTimeForX(x);
}
double
RulerScale::getWidthForDuration(timeT startTime, timeT duration) const
{
return getXForTime(startTime + duration) - getXForTime(startTime);
}
double
RulerScale::getTotalWidth() const
{
int n = getLastVisibleBar();
return getBarPosition(n) + getBarWidth(n);
}
//////////////////////////////////////////////////////////////////////
// SimpleRulerScale
//////////////////////////////////////////////////////////////////////
SimpleRulerScale::SimpleRulerScale(Composition *composition,
double origin, double ratio) :
RulerScale(composition),
m_origin(origin),
m_ratio(ratio)
{
// nothing
}
SimpleRulerScale::SimpleRulerScale(const SimpleRulerScale &ruler):
RulerScale(ruler.getComposition()),
m_origin(ruler.getOrigin()),
m_ratio(ruler.getUnitsPerPixel())
{
// nothing
}
SimpleRulerScale::~SimpleRulerScale()
{
// nothing
}
double
SimpleRulerScale::getBarPosition(int n) const
{
timeT barStart = m_composition->getBarRange(n).first;
return getXForTime(barStart);
}
double
SimpleRulerScale::getBarWidth(int n) const
{
std::pair<timeT, timeT> range = m_composition->getBarRange(n);
return (double)(range.second - range.first) / m_ratio;
}
double
SimpleRulerScale::getBeatWidth(int n) const
{
bool isNew;
TimeSignature timeSig(m_composition->getTimeSignatureInBar(n, isNew));
return (double)(timeSig.getBeatDuration()) / m_ratio;
}
int
SimpleRulerScale::getBarForX(double x) const
{
return m_composition->getBarNumber(getTimeForX(x));
}
timeT
SimpleRulerScale::getTimeForX(double x) const
{
timeT t = (timeT)(nearbyint((double)(x - m_origin) * m_ratio));
int firstBar = getFirstVisibleBar();
if (firstBar != 0) {
t += m_composition->getBarRange(firstBar).first;
}
return t;
}
double
SimpleRulerScale::getXForTime(timeT time) const
{
int firstBar = getFirstVisibleBar();
if (firstBar != 0) {
time -= m_composition->getBarRange(firstBar).first;
}
return m_origin + (double)time / m_ratio;
}
}