Mercurial > hg > svgui
changeset 439:681542f0c8c5
* Add vertical zoom/pan to note layer as well (when not in auto-align
or MIDI scale modes)
author | Chris Cannam |
---|---|
date | Fri, 24 Oct 2008 16:43:59 +0000 |
parents | 76cd1c89eb06 |
children | 08d6bc698d16 |
files | layer/NoteLayer.cpp layer/NoteLayer.h layer/TimeValueLayer.cpp |
diffstat | 3 files changed, 161 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/NoteLayer.cpp Fri Oct 24 16:21:57 2008 +0000 +++ b/layer/NoteLayer.cpp Fri Oct 24 16:43:59 2008 +0000 @@ -20,6 +20,7 @@ #include "base/Profiler.h" #include "base/Pitch.h" #include "base/LogRange.h" +#include "base/RangeMapper.h" #include "ColourDatabase.h" #include "view/View.h" @@ -45,7 +46,9 @@ m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")), m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")), m_editingCommand(0), - m_verticalScale(AutoAlignScale) + m_verticalScale(AutoAlignScale), + m_scaleMinimum(0), + m_scaleMaximum(0) { } @@ -60,6 +63,9 @@ // std::cerr << "NoteLayer::setModel(" << model << ")" << std::endl; + m_scaleMinimum = 0; + m_scaleMaximum = 0; + emit modelReplaced(); } @@ -208,7 +214,7 @@ bool NoteLayer::getDisplayExtents(float &min, float &max) const { - if (!m_model || m_verticalScale == AutoAlignScale) return false; + if (!m_model || shouldAutoAlign()) return false; if (m_verticalScale == MIDIRangeScale) { min = Pitch::getFrequencyForPitch(0); @@ -216,8 +222,13 @@ return true; } - min = m_model->getValueMinimum(); - max = m_model->getValueMaximum(); + if (m_scaleMinimum == m_scaleMaximum) { + m_scaleMinimum = m_model->getValueMinimum(); + m_scaleMaximum = m_model->getValueMaximum(); + } + + min = m_scaleMinimum; + max = m_scaleMaximum; if (shouldConvertMIDIToHz()) { min = Pitch::getFrequencyForPitch(lrintf(min)); @@ -227,6 +238,131 @@ return true; } +bool +NoteLayer::setDisplayExtents(float min, float max) +{ + if (!m_model) return false; + + if (min == max) { + if (min == 0.f) { + max = 1.f; + } else { + max = min * 1.0001; + } + } + + m_scaleMinimum = min; + m_scaleMaximum = max; + +// std::cerr << "NoteLayer::setDisplayExtents: min = " << min << ", max = " << max << std::endl; + + emit layerParametersChanged(); + return true; +} + +int +NoteLayer::getVerticalZoomSteps(int &defaultStep) const +{ + if (shouldAutoAlign()) return 0; + if (!m_model) return 0; + + defaultStep = 0; + return 100; +} + +int +NoteLayer::getCurrentVerticalZoomStep() const +{ + if (shouldAutoAlign()) return 0; + if (!m_model) return 0; + + RangeMapper *mapper = getNewVerticalZoomRangeMapper(); + if (!mapper) return 0; + + float dmin, dmax; + getDisplayExtents(dmin, dmax); + + int nr = mapper->getPositionForValue(dmax - dmin); + + delete mapper; + + return 100 - nr; +} + +//!!! lots of duplication with TimeValueLayer + +void +NoteLayer::setVerticalZoomStep(int step) +{ + if (shouldAutoAlign()) return; + if (!m_model) return; + + RangeMapper *mapper = getNewVerticalZoomRangeMapper(); + if (!mapper) return; + + float min, max; + bool logarithmic; + QString unit; + getValueExtents(min, max, logarithmic, unit); + + float dmin, dmax; + getDisplayExtents(dmin, dmax); + + float newdist = mapper->getValueForPosition(100 - step); + + float newmin, newmax; + + if (logarithmic) { + + // see SpectrogramLayer::setVerticalZoomStep + + newmax = (newdist + sqrtf(newdist*newdist + 4*dmin*dmax)) / 2; + newmin = newmax - newdist; + +// std::cerr << "newmin = " << newmin << ", newmax = " << newmax << std::endl; + + } else { + float dmid = (dmax + dmin) / 2; + newmin = dmid - newdist / 2; + newmax = dmid + newdist / 2; + } + + if (newmin < min) { + newmax += (min - newmin); + newmin = min; + } + if (newmax > max) { + newmax = max; + } + + std::cerr << "NoteLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << std::endl; + + setDisplayExtents(newmin, newmax); +} + +RangeMapper * +NoteLayer::getNewVerticalZoomRangeMapper() const +{ + if (!m_model) return 0; + + RangeMapper *mapper; + + float min, max; + bool logarithmic; + QString unit; + getValueExtents(min, max, logarithmic, unit); + + if (min == max) return 0; + + if (logarithmic) { + mapper = new LogRangeMapper(0, 100, min, max, unit); + } else { + mapper = new LinearRangeMapper(0, 100, min, max, unit); + } + + return mapper; +} + NoteModel::PointList NoteLayer::getLocalPoints(View *v, int x) const { @@ -437,7 +573,7 @@ if (shouldConvertMIDIToHz()) queryUnits = "Hz"; else queryUnits = m_model->getScaleUnits(); - if (m_verticalScale == AutoAlignScale) { + if (shouldAutoAlign()) { if (!v->getValueExtents(queryUnits, min, max, log)) { @@ -461,8 +597,7 @@ } else { - min = m_model->getValueMinimum(); - max = m_model->getValueMaximum(); + getDisplayExtents(min, max); if (m_verticalScale == MIDIRangeScale) { min = Pitch::getFrequencyForPitch(0); @@ -530,6 +665,13 @@ return val; } +bool +NoteLayer::shouldAutoAlign() const +{ + if (!m_model) return false; + return (m_verticalScale == AutoAlignScale); +} + void NoteLayer::paint(View *v, QPainter &paint, QRect rect) const {
--- a/layer/NoteLayer.h Fri Oct 24 16:21:57 2008 +0000 +++ b/layer/NoteLayer.h Fri Oct 24 16:43:59 2008 +0000 @@ -95,6 +95,12 @@ bool &log, QString &unit) const; virtual bool getDisplayExtents(float &min, float &max) const; + virtual bool setDisplayExtents(float min, float max); + + virtual int getVerticalZoomSteps(int &defaultStep) const; + virtual int getCurrentVerticalZoomStep() const; + virtual void setVerticalZoomStep(int); + virtual RangeMapper *getNewVerticalZoomRangeMapper() const; virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; @@ -118,6 +124,11 @@ NoteModel::EditCommand *m_editingCommand; VerticalScale m_verticalScale; + mutable float m_scaleMinimum; + mutable float m_scaleMaximum; + + bool shouldAutoAlign() const; + void finish(NoteModel::EditCommand *command) { Command *c = command->finish(); if (c) CommandHistory::getInstance()->addCommand(c, false);