/* 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; } }