diff layer/NoteLayer.cpp @ 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 e1a9e478b7f2
children 4a14499fb184
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
 {