changeset 195:4a3bdde1ef13

* beginnings of spectrum scales
author Chris Cannam
date Mon, 29 Jan 2007 18:11:20 +0000
parents d13e209bfa94
children 22c99c8aa1e0
files layer/PaintAssistant.cpp layer/PaintAssistant.h layer/SliceLayer.cpp layer/SliceLayer.h layer/SpectrumLayer.cpp layer/WaveformLayer.cpp layer/layer.pro view/ViewManager.h
diffstat 8 files changed, 372 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/PaintAssistant.cpp	Mon Jan 29 18:11:20 2007 +0000
@@ -0,0 +1,185 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2007 Chris Cannam and QMUL.
+   
+    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 "PaintAssistant.h"
+
+#include "base/AudioLevel.h"
+
+#include <QPaintDevice>
+#include <QPainter>
+
+void
+PaintAssistant::paintVerticalLevelScale(QPainter &paint, QRect rect,
+					float minVal, float maxVal,
+                                        Scale scale, std::vector<int> *vy)
+{
+    static float meterdbs[] = { -40, -30, -20, -15, -10,
+                                -5, -3, -2, -1, -0.5, 0 };
+
+    int h = rect.height(), w = rect.width();
+    int textHeight = paint.fontMetrics().height();
+    int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
+
+    int lastLabelledY = -1;
+
+    int n = 10;
+    if (vy) vy->clear();
+
+    for (int i = 0; i <= n; ++i) {
+        
+        float val = 0.0, nval = 0.0;
+        QString text = "";
+
+        switch (scale) {
+                
+        case LinearScale:
+            val = minVal + ((maxVal - minVal) * i) / n;
+            text = QString("%1").arg(val);//float(i) / n); // ... val
+/*
+            if (i == 0) text = "0.0";
+            else {
+                nval = -val;
+                if (i == n) text = "1.0";
+            }
+*/
+            break;
+            
+        case MeterScale: // ... min, max
+            val = AudioLevel::dB_to_multiplier(meterdbs[i]);
+            text = QString("%1").arg(meterdbs[i]);
+            if (i == n) text = "0dB";
+            if (i == 0) {
+                text = "-Inf";
+                val = 0.0;
+            }
+            break;
+
+        case dBScale: // ... min, max
+            val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10);
+            text = QString("%1").arg(-(10*n) + i * 10);
+            if (i == n) text = "0dB";
+            if (i == 0) {
+                text = "-Inf";
+                val = 0.0;
+            }
+            break;
+        }
+
+        if (val < minVal || val > maxVal) continue;
+
+        int y = getYForValue(scale, val, minVal, maxVal, rect.y(), rect.height());
+            
+        int ny = y;
+        if (nval != 0.0) {
+            ny = getYForValue(scale, nval, minVal, maxVal, rect.y(), rect.height());
+        }
+
+        bool spaceForLabel = (i == 0 ||
+                              abs(y - lastLabelledY) >= textHeight - 1);
+        
+        if (spaceForLabel) {
+            
+            int tx = 3;
+            if (scale != LinearScale) {
+                tx = w - 10 - paint.fontMetrics().width(text);
+            }
+            
+            int ty = y;
+            if (ty < paint.fontMetrics().ascent()) {
+                ty = paint.fontMetrics().ascent();
+            } else if (ty > h - paint.fontMetrics().descent()) {
+                ty = h - paint.fontMetrics().descent();
+            } else {
+                ty += toff;
+            }
+            paint.drawText(tx, ty, text);
+            
+            lastLabelledY = ty - toff;
+            /*
+            if (ny != y) {
+                ty = ny;
+                if (ty < paint.fontMetrics().ascent()) {
+                    ty = paint.fontMetrics().ascent();
+                } else if (ty > h - paint.fontMetrics().descent()) {
+                    ty = h - paint.fontMetrics().descent();
+                } else {
+                    ty += toff;
+                }
+                paint.drawText(tx, ty, text);
+            }
+            */
+            paint.drawLine(w - 7, y, w, y);
+            if (vy) vy->push_back(y);
+
+            if (ny != y) {
+                paint.drawLine(w - 7, ny, w, ny);
+                if (vy) vy->push_back(ny);
+            }
+            
+        } else {
+            
+            paint.drawLine(w - 4, y, w, y);
+            if (vy) vy->push_back(y);
+
+            if (ny != y) {
+                paint.drawLine(w - 4, ny, w, ny);
+                if (vy) vy->push_back(ny);
+            }
+        }
+    }
+}
+
+static int
+dBscale(float sample, int m, float maxVal, float minVal) 
+{
+    if (sample < 0.0) return dBscale(-sample, m, maxVal, minVal);
+    float dB = AudioLevel::multiplier_to_dB(sample);
+    float mindB = AudioLevel::multiplier_to_dB(minVal);
+    float maxdB = AudioLevel::multiplier_to_dB(maxVal);
+    if (dB < mindB) return 0;
+    if (dB > 0.0) return m;
+    return int(((dB - mindB) * m) / (maxdB - mindB) + 0.1);
+}
+
+int
+PaintAssistant::getYForValue(Scale scale, float value, 
+                             float minVal, float maxVal,
+                             int minY, int height)
+{
+    int vy = 0;
+
+//    int m = height/2;
+//    int my = minY + m;
+
+    switch (scale) {
+
+    case LinearScale:
+//        vy = my - int(m * value);
+        vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height);
+        break;
+
+    case MeterScale:
+//        vy = my - AudioLevel::multiplier_to_preview(value, m);
+        vy = minY + height - AudioLevel::multiplier_to_preview
+            ((value - minVal) / (maxVal - minVal), height);
+        break;
+
+    case dBScale:
+        vy = minY + height - dBscale(value, height, maxVal, minVal);
+        break;
+    }
+
+    return vy;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/PaintAssistant.h	Mon Jan 29 18:11:20 2007 +0000
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2007 Chris Cannam and QMUL.
+   
+    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.
+*/
+
+#ifndef _PAINT_ASSISTANT_H_
+#define _PAINT_ASSISTANT_H_
+
+#include <QRect>
+#include <vector>
+
+class QPainter;
+
+class PaintAssistant
+{
+public:
+    enum Scale { LinearScale, MeterScale, dBScale };
+
+    static void paintVerticalLevelScale(QPainter &p, QRect rect,
+                                        float minVal, float maxVal,
+                                        Scale scale,
+                                        std::vector<int> *markCoordRtns = 0);
+
+    static int getYForValue(Scale scale, float value,
+                            float minVal, float maxVal,
+                            int minY, int height);
+};
+
+#endif
--- a/layer/SliceLayer.cpp	Fri Jan 26 17:20:58 2007 +0000
+++ b/layer/SliceLayer.cpp	Mon Jan 29 18:11:20 2007 +0000
@@ -5,7 +5,7 @@
     Sonic Visualiser
     An audio file viewer and annotation editor.
     Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2006 QMUL.
+    This file copyright 2006-2007 QMUL.
     
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License as
@@ -19,6 +19,9 @@
 #include "view/View.h"
 #include "base/AudioLevel.h"
 #include "base/RangeMapper.h"
+#include "base/RealTime.h"
+
+#include "PaintAssistant.h"
 
 #include <QPainter>
 #include <QPainterPath>
@@ -28,7 +31,7 @@
     m_colour(Qt::darkBlue),
     m_energyScale(dBScale),
     m_samplingMode(SamplePeak),
-    m_plotStyle(PlotLines),
+    m_plotStyle(PlotSteps),
     m_binScale(LinearBins),
     m_normalize(false),
     m_bias(false),
@@ -94,15 +97,30 @@
 {
     if (!m_sliceableModel) return;
 
-    int w = (v->width() * 2) / 3;
-    int xorigin = (v->width() / 2) - (w / 2);
+    paint.save();
+    paint.setRenderHint(QPainter::Antialiasing, false);
+
+    if (v->getViewManager() && v->getViewManager()->shouldShowScaleGuides()) {
+        if (!m_scalePoints.empty()) {
+            paint.setPen(QColor(240, 240, 240)); //!!! and dark background?
+            for (size_t i = 0; i < m_scalePoints.size(); ++i) {
+                paint.drawLine(0, m_scalePoints[i], rect.width(), m_scalePoints[i]);
+            }
+        }
+    }
+
+    paint.setPen(m_colour);
+
+//    int w = (v->width() * 2) / 3;
+    int xorigin = getVerticalScaleWidth(v, paint) + 1; //!!! (v->width() / 2) - (w / 2);
+    int w = v->width() - xorigin - 1;
     
-    int h = (v->height() * 2) / 3;
-    int yorigin = (v->height() / 2) + (h / 2);
+    int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7;
+    int h = yorigin - paint.fontMetrics().height() - 8;
+    if (h < 0) return;
 
-    paint.save();
-    paint.setPen(m_colour);
-    paint.setRenderHint(QPainter::Antialiasing, false);
+//    int h = (v->height() * 3) / 4;
+//    int yorigin = (v->height() / 2) + (h / 2);
     
     QPainterPath path;
     float thresh = -80.f;
@@ -118,16 +136,19 @@
 
     size_t f0 = v->getCentreFrame();
     int f0x = v->getXForFrame(f0);
+    f0 = v->getFrameForX(f0x);
     size_t f1 = v->getFrameForX(f0x + 1);
+    if (f1 > f0) --f1;
 
     size_t col0 = f0 / m_sliceableModel->getResolution();
     size_t col1 = col0;
     if (m_samplingMode != NearestSample) {
         col1 = f1 / m_sliceableModel->getResolution();
     }
-    if (col1 <= col0) col1 = col0 + 1;
+    f0 = col0 * m_sliceableModel->getResolution();
+    f1 = (col1 + 1) * m_sliceableModel->getResolution() - 1;
 
-    for (size_t col = col0; col < col1; ++col) {
+    for (size_t col = col0; col <= col1; ++col) {
         for (size_t bin = 0; bin < mh; ++bin) {
             float value = m_sliceableModel->getValueAt(col, bin);
             if (m_bias) value *= bin + 1;
@@ -236,6 +257,107 @@
     paint.drawPath(path);
     paint.restore();
 
+    if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount()) {
+
+        int sampleRate = m_sliceableModel->getSampleRate();
+
+        QString startText = QString("%1 / %2")
+            .arg(QString::fromStdString
+                 (RealTime::frame2RealTime
+                  (f0, sampleRate).toText(true)))
+            .arg(f0);
+
+        QString endText = QString(" %1 / %2")
+            .arg(QString::fromStdString
+                 (RealTime::frame2RealTime
+                  (f1, sampleRate).toText(true)))
+            .arg(f1);
+
+        QString durationText = QString("(%1 / %2) ")
+            .arg(QString::fromStdString
+                 (RealTime::frame2RealTime
+                  (f1 - f0 + 1, sampleRate).toText(true)))
+            .arg(f1 - f0 + 1);
+
+        v->drawVisibleText
+            (paint, xorigin + 5,
+             paint.fontMetrics().ascent() + 5,
+             startText, View::OutlinedText);
+        
+        v->drawVisibleText
+            (paint, xorigin + 5,
+             paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10,
+             endText, View::OutlinedText);
+        
+        v->drawVisibleText
+            (paint, xorigin + 5,
+             paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15,
+             durationText, View::OutlinedText);
+    }
+    
+/*
+
+    QString frameRange;
+    if (f1 != f0) {
+        frameRange = QString("%1 - %2").arg(f0).arg(f1);
+    } else {
+        frameRange = QString("%1").arg(f0);
+    }
+
+    QString colRange;
+    if (col1 != col0) {
+        colRange = tr("%1 hops").arg(col1 - col0 + 1);
+    } else {
+        colRange = tr("1 hop");
+    }
+
+    if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount()) {
+
+        v->drawVisibleText
+            (paint, xorigin + 5,
+             paint.fontMetrics().ascent() + 5,
+             frameRange, View::OutlinedText);
+        
+        v->drawVisibleText
+            (paint, xorigin + 5,
+             paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10,
+             colRange, View::OutlinedText);
+    }
+*/
+}
+
+int
+SliceLayer::getVerticalScaleWidth(View *v, QPainter &paint) const
+{
+    if (m_energyScale == LinearScale) {
+	return paint.fontMetrics().width("0.0") + 13;
+    } else {
+	return std::max(paint.fontMetrics().width(tr("0dB")),
+			paint.fontMetrics().width(tr("-Inf"))) + 13;
+    }
+}
+
+void
+SliceLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
+{
+    float thresh = 0;
+    if (m_energyScale != LinearScale) {
+        thresh = AudioLevel::dB_to_multiplier(-80); //!!! thresh
+    }
+    
+//    int h = (rect.height() * 3) / 4;
+//    int y = (rect.height() / 2) - (h / 2);
+    
+    int yorigin = v->height() - 20 - paint.fontMetrics().height() - 6;
+    int h = yorigin - paint.fontMetrics().height() - 8;
+    if (h < 0) return;
+
+    QRect actual(rect.x(), rect.y() + yorigin - h, rect.width(), h);
+
+    PaintAssistant::paintVerticalLevelScale
+        (paint, actual, thresh, 1.0 / m_gain,
+         PaintAssistant::Scale(m_energyScale),
+         const_cast<std::vector<int> *>(&m_scalePoints));
 }
 
 Layer::PropertyList
--- a/layer/SliceLayer.h	Fri Jan 26 17:20:58 2007 +0000
+++ b/layer/SliceLayer.h	Mon Jan 29 18:11:20 2007 +0000
@@ -41,6 +41,9 @@
 
     virtual void paint(View *v, QPainter &paint, QRect rect) const;
 
+    virtual int getVerticalScaleWidth(View *v, QPainter &) const;
+    virtual void paintVerticalScale(View *v, QPainter &paint, QRect rect) const;
+
     virtual PropertyList getProperties() const;
     virtual QString getPropertyLabel(const PropertyName &) const;
     virtual PropertyType getPropertyType(const PropertyName &) const;
@@ -104,6 +107,7 @@
     bool                              m_normalize;
     bool                              m_bias;
     float                             m_gain;
+    mutable std::vector<int>          m_scalePoints;
 };
 
 #endif
--- a/layer/SpectrumLayer.cpp	Fri Jan 26 17:20:58 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Mon Jan 29 18:11:20 2007 +0000
@@ -5,7 +5,7 @@
     Sonic Visualiser
     An audio file viewer and annotation editor.
     Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2006 QMUL.
+    This file copyright 2006-2007 QMUL.
     
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License as
@@ -34,6 +34,8 @@
     connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
             this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
     setWindowType(prefs->getWindowType());
+
+    setBinScale(LogBins);
 }
 
 SpectrumLayer::~SpectrumLayer()
--- a/layer/WaveformLayer.cpp	Fri Jan 26 17:20:58 2007 +0000
+++ b/layer/WaveformLayer.cpp	Mon Jan 29 18:11:20 2007 +0000
@@ -592,7 +592,9 @@
         int n = 10;
         int py = -1;
         
-        if (v->hasLightBackground()) {
+        if (v->hasLightBackground() &&
+            v->getViewManager() &&
+            v->getViewManager()->shouldShowScaleGuides()) {
 
             paint->setPen(QColor(240, 240, 240));
 
--- a/layer/layer.pro	Fri Jan 26 17:20:58 2007 +0000
+++ b/layer/layer.pro	Mon Jan 29 18:11:20 2007 +0000
@@ -18,6 +18,7 @@
            Layer.h \
            LayerFactory.h \
            NoteLayer.h \
+           PaintAssistant.h \
            SpectrogramLayer.h \
            SpectrumLayer.h \
            SliceLayer.h \
@@ -31,6 +32,7 @@
            Layer.cpp \
            LayerFactory.cpp \
            NoteLayer.cpp \
+           PaintAssistant.cpp \
            SpectrogramLayer.cpp \
            SpectrumLayer.cpp \
            SliceLayer.cpp \
--- a/view/ViewManager.h	Fri Jan 26 17:20:58 2007 +0000
+++ b/view/ViewManager.h	Mon Jan 29 18:11:20 2007 +0000
@@ -125,6 +125,9 @@
     bool shouldShowLayerNames() const {
         return m_overlayMode == AllOverlays;
     }
+    bool shouldShowScaleGuides() const {
+        return m_overlayMode != NoOverlays;
+    }
 
     void setZoomWheelsEnabled(bool enable);
     bool getZoomWheelsEnabled() const { return m_zoomWheelsEnabled; }