changeset 68:193b569a975f

* Add scale lines to waveform layer * Various fixes to vertical scale drawing for waveform and time-value layers * Make log/linear scale have an effect for time-value layer segmentation mode
author Chris Cannam
date Wed, 29 Mar 2006 16:24:25 +0000
parents c4fff27cd651
children 6dad2724f3aa
files layer/TimeValueLayer.cpp layer/TimeValueLayer.h layer/WaveformLayer.cpp layer/WaveformLayer.h widgets/Pane.cpp
diffstat 5 files changed, 290 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/layer/TimeValueLayer.cpp	Wed Mar 29 12:35:17 2006 +0000
+++ b/layer/TimeValueLayer.cpp	Wed Mar 29 16:24:25 2006 +0000
@@ -417,6 +417,28 @@
     return min + (float(h - y) * float(max - min)) / h;
 }
 
+QColor
+TimeValueLayer::getColourForValue(float val) const
+{
+    float min = m_model->getValueMinimum();
+    float max = m_model->getValueMaximum();
+    if (max == min) max = min + 1.0;
+
+    if (m_verticalScale == FrequencyScale || m_verticalScale == LogScale) {
+        min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min);
+        max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max);
+        val = (val < 0.0) ? -log10(-val) : (val == 0.0) ? 0.0 : log10(val);
+    } else if (m_verticalScale == PlusMinusOneScale) {
+        min = -1.0;
+        max = 1.0;
+    }
+
+    int iv = ((val - min) / (max - min)) * 255.999;
+
+    QColor colour = QColor::fromHsv(256 - iv, iv / 2 + 128, iv);
+    return QColor(colour.red(), colour.green(), colour.blue(), 120);
+}
+
 void
 TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const
 {
@@ -497,10 +519,7 @@
 	paint.setPen(m_colour);
 
 	if (m_plotStyle == PlotSegmentation) {
-	    int value = ((p.value - min) / (max - min)) * 255.999;
-	    QColor colour = QColor::fromHsv(256 - value, value / 2 + 128, value);
-	    paint.setBrush(QColor(colour.red(), colour.green(), colour.blue(),
-				  120));
+            paint.setBrush(getColourForValue(p.value));
 	    labelY = v->height();
 	} else if (m_plotStyle == PlotLines ||
 		   m_plotStyle == PlotCurve) {
@@ -617,35 +636,82 @@
 int
 TimeValueLayer::getVerticalScaleWidth(View *v, QPainter &paint) const
 {
-    if (m_plotStyle == PlotSegmentation) return 0;
-    return paint.fontMetrics().width("+0.000e+00") + 15;
+    int w = paint.fontMetrics().width("-000.000");
+    if (m_plotStyle == PlotSegmentation) return w + 20;
+    else return w + 10;
 }
 
 void
 TimeValueLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
 {
     if (!m_model) return;
-    if (m_plotStyle == PlotSegmentation) return;
 
-    float val = m_model->getValueMinimum();
-    float inc = (m_model->getValueMaximum() - val) / 10;
+    int h = v->height();
+
+    int n = 10;
+
+    float max = m_model->getValueMaximum();
+    float min = m_model->getValueMinimum();
+    float val = min;
+    float inc = (max - val) / n;
 
     char buffer[40];
 
     int w = getVerticalScaleWidth(v, paint);
 
-    while (val < m_model->getValueMaximum()) {
-	int y = getYForValue(v, val);
-//	QString label = QString("%1").arg(val);
-	sprintf(buffer, "%+.3e", val);
+    int tx = 5;
+
+    int boxx = 5, boxy = 5;
+    if (m_model->getScaleUnits() != "") {
+        boxy += paint.fontMetrics().height();
+    }
+    int boxw = 10, boxh = h - boxy - 5;
+
+    if (m_plotStyle == PlotSegmentation) {
+        tx += boxx + boxw;
+        paint.drawRect(boxx, boxy, boxw, boxh);
+    }
+
+    if (m_plotStyle == PlotSegmentation) {
+        paint.save();
+        for (int y = 0; y < boxh; ++y) {
+            float val = ((boxh - y) * (max - min)) / boxh + min;
+            paint.setPen(getColourForValue(val));
+            paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1);
+        }
+        paint.restore();
+    }
+
+    for (int i = 0; i < n; ++i) {
+
+	int y, ty;
+        bool drawText = true;
+
+        if (m_plotStyle == PlotSegmentation) {
+            y = boxy + int(boxh - ((val - min) * boxh) / (max - min));
+            ty = y;
+        } else {
+            if (i == n-1) {
+                if (m_model->getScaleUnits() != "") drawText = false;
+            }
+            y = getYForValue(v, val);
+            ty = y - paint.fontMetrics().height() +
+                     paint.fontMetrics().ascent();
+        }
+
+	sprintf(buffer, "%.3f", val);
 	QString label = QString(buffer);
-	paint.drawLine(w - 5, y, w, y);//  100 - 10, y, 100, y);
-	paint.drawText(5, // 100 - 15 - paint.fontMetrics().width(label),
-		       y - paint.fontMetrics().height() + paint.fontMetrics().ascent(),
-		       label);
+
+        if (m_plotStyle != PlotSegmentation) {
+            paint.drawLine(w - 5, y, w, y);
+        } else {
+            paint.drawLine(boxx + boxw - boxw/3, y, boxx + boxw, y);
+        }
+
+        if (drawText) paint.drawText(tx, ty, label);
 	val += inc;
     }
-
+    
     if (m_model->getScaleUnits() != "") {
         paint.drawText(5, 5 + paint.fontMetrics().ascent(),
                        m_model->getScaleUnits());
--- a/layer/TimeValueLayer.h	Wed Mar 29 12:35:17 2006 +0000
+++ b/layer/TimeValueLayer.h	Wed Mar 29 16:24:25 2006 +0000
@@ -105,6 +105,8 @@
     int getYForValue(View *, float value) const;
     float getValueForY(View *, int y) const;
 
+    QColor getColourForValue(float value) const;
+
     SparseTimeValueModel::PointList getLocalPoints(View *v, int) const;
 
     SparseTimeValueModel *m_model;
--- a/layer/WaveformLayer.cpp	Wed Mar 29 12:35:17 2006 +0000
+++ b/layer/WaveformLayer.cpp	Wed Mar 29 16:24:25 2006 +0000
@@ -78,7 +78,11 @@
     list.push_back(tr("Scale"));
     list.push_back(tr("Gain"));
     list.push_back(tr("Normalize Visible Area"));
-    list.push_back(tr("Channels"));
+
+    if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) {
+        list.push_back(tr("Channels"));
+    }
+
     return list;
 }
 
@@ -369,6 +373,9 @@
     return !m_autoNormalize;
 }
 
+static float meterdbs[] = { -40, -30, -20, -15, -10,
+                            -5, -3, -2, -1, -0.5, 0 };
+
 void
 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const
 {
@@ -487,28 +494,6 @@
 	int prevRangeBottom = -1, prevRangeTop = -1;
 	QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour;
 
-	int m = (h / channels) / 2;
-	int my = m + (((ch - minChannel) * h) / channels);
-	
-//	std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl;
-
-	if (my - m > y1 || my + m < y0) continue;
-
-	paint->setPen(greys[0]);
-	paint->drawLine(x0, my, x1, my);
-
-	if (frame1 <= 0) continue;
-
-	size_t modelZoomLevel = zoomLevel;
-
-	ranges = m_model->getRanges
-	    (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
-        
-	if (mergingChannels || mixingChannels) {
-	    otherChannelRanges = m_model->getRanges
-		(1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
-	}
-
         m_effectiveGains[ch] = m_gain;
 
         if (m_autoNormalize) {
@@ -529,6 +514,80 @@
 
         float gain = m_effectiveGains[ch];
 
+	int m = (h / channels) / 2;
+	int my = m + (((ch - minChannel) * h) / channels);
+	
+//	std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl;
+
+	if (my - m > y1 || my + m < y0) continue;
+
+        if ((m_scale == dBScale || m_scale == MeterScale) &&
+            m_channelMode != MergeChannels) {
+            m = (h / channels);
+            my = m + (((ch - minChannel) * h) / channels);
+        }
+
+	paint->setPen(greys[0]);
+	paint->drawLine(x0, my, x1, my);
+
+        int n = 10;
+        int py = -1;
+        
+        if (v->hasLightBackground()) {
+
+            paint->setPen(QColor(240, 240, 240));
+
+            for (int i = 1; i < n; ++i) {
+                
+                float val = 0.0, nval = 0.0;
+
+                switch (m_scale) {
+
+                case LinearScale:
+                    val = (i * gain) / n;
+                    if (i > 0) nval = -val;
+                    break;
+
+                case MeterScale:
+                    val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
+                    break;
+
+                case dBScale:
+                    val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
+                    break;
+                }
+
+                if (val < -1.0 || val > 1.0) continue;
+
+                int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
+
+                if (py >= 0 && abs(y - py) < 10) continue;
+                else py = y;
+
+                int ny = y;
+                if (nval != 0.0) {
+                    ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
+                }
+
+                paint->drawLine(x0, y, x1, y);
+                if (ny != y) {
+                    paint->drawLine(x0, ny, x1, ny);
+                }
+            }
+        }
+
+	if (frame1 <= 0) continue;
+
+	size_t modelZoomLevel = zoomLevel;
+
+	ranges = m_model->getRanges
+	    (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
+        
+	if (mergingChannels || mixingChannels) {
+	    otherChannelRanges = m_model->getRanges
+		(1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
+	}
+
 	for (int x = x0; x <= x1; ++x) {
 
 	    range = RangeSummarisableTimeValueModel::Range();
@@ -832,6 +891,45 @@
 }
 
 int
+WaveformLayer::getYForValue(View *v, Scale scale, float value, size_t channel,
+                            size_t minChannel, size_t maxChannel) const
+{
+    if (maxChannel < minChannel || channel < minChannel) return 0;
+
+    int w = v->width();
+    int h = v->height();
+
+    int channels = maxChannel - minChannel + 1;
+    int m = (h / channels) / 2;
+    int my = m + (((channel - minChannel) * h) / channels);
+	
+    if ((m_scale == dBScale || m_scale == MeterScale) &&
+        m_channelMode != MergeChannels) {
+        m = (h / channels);
+        my = m + (((channel - minChannel) * h) / channels);
+    }
+
+    int vy = 0;
+
+    switch (scale) {
+
+    case LinearScale:
+        vy = int(m * value);
+        break;
+
+    case MeterScale:
+        vy = AudioLevel::multiplier_to_preview(value, m);
+        break;
+
+    case dBScale:
+        vy = dBscale(value, m);
+        break;
+    }
+
+    return my - vy;
+}
+
+int
 WaveformLayer::getVerticalScaleWidth(View *v, QPainter &paint) const
 {
     if (m_scale == LinearScale) {
@@ -864,75 +962,101 @@
 
     for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
 
-	int m = (h / channels) / 2;
-	int my = m + (((ch - minChannel) * h) / channels);
-	int py = -1;
+	int lastLabelledY = -1;
 
         if (ch < m_effectiveGains.size()) gain = m_effectiveGains[ch];
 
-	for (int i = 0; i <= 10; ++i) {
+        int n = 10;
 
-	    int vy = 0;
+	for (int i = 0; i <= n; ++i) {
+
+            float val = 0.0, nval = 0.0;
 	    QString text = "";
 
-	    if (m_scale == LinearScale) {
+            switch (m_scale) {
+                
+            case LinearScale:
+                val = (i * gain) / n;
+		text = QString("%1").arg(float(i) / n);
+		if (i == 0) text = "0.0";
+                else {
+                    nval = -val;
+                    if (i == n) text = "1.0";
+                }
+                break;
 
-		vy = int((m * i * gain) / 10);
+            case MeterScale:
+                val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
+		text = QString("%1").arg(meterdbs[i]);
+		if (i == n) text = tr("0dB");
+		if (i == 0) {
+                    text = tr("-Inf");
+                    val = 0.0;
+		}
+                break;
 
-		text = QString("%1").arg(float(i) / 10.0);
-		if (i == 0) text = "0.0";
-		if (i == 10) text = "1.0";
+            case dBScale:
+                val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
+		text = QString("%1").arg(-(10*n) + i * 10);
+		if (i == n) text = tr("0dB");
+		if (i == 0) {
+                    text = tr("-Inf");
+                    val = 0.0;
+		}
+                break;
+            }
 
-	    } else {
+            if (val < -1.0 || val > 1.0) continue;
 
-		int db;
-		bool minvalue = false;
-		
-		if (m_scale == MeterScale) {
-		    static int dbs[] = { -50, -40, -30, -20, -15,
-					 -10, -5, -3, -2, -1, 0 };
-		    db = dbs[i];
-		    if (db == -50) minvalue = true;
-		    vy = AudioLevel::multiplier_to_preview
-			(AudioLevel::dB_to_multiplier(db) * gain, m);
-		} else {
-		    db = -100 + i * 10;
-		    if (db == -100) minvalue = true;
-		    vy = dBscale
-			(AudioLevel::dB_to_multiplier(db) * gain, m);
-		}
+            int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
 
-		text = QString("%1").arg(db);
-		if (db == 0) text = tr("0dB");
-		if (minvalue) {
-		    text = tr("-Inf");
-		    vy = 0;
-		}
-	    }
+            int ny = y;
+            if (nval != 0.0) {
+                ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
+            }
 
-	    if (vy < 0) vy = -vy;
-//	    if (vy >= m - 1) continue;
+            bool spaceForLabel = (i == 0 ||
+                                  abs(y - lastLabelledY) >= textHeight - 1);
 
-	    if (py >= 0 && (vy - py) < textHeight - 1) {
-		paint.drawLine(w - 4, my - vy, w, my - vy);
-		if (vy > 0) paint.drawLine(w - 4, my + vy, w, my + vy);
-		continue;
-	    }
+            if (spaceForLabel) {
 
-	    paint.drawLine(w - 7, my - vy, w, my - vy);
-	    if (vy > 0) paint.drawLine(w - 7, my + vy, w, my + vy);
+                int tx = 3;
+                if (m_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);
 
-	    int tx = 3;
-	    if (m_scale != LinearScale) {
-		tx = w - 10 - paint.fontMetrics().width(text);
-	    }
-	    
-	    if (vy >= m - 1) continue;
+                lastLabelledY = ty - toff;
 
-	    paint.drawText(tx, my - vy + toff, text);
-	    if (vy > 0) paint.drawText(tx, my + vy + toff, text);
-		
-	    py = vy;
+                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 (ny != y) paint.drawLine(w - 7, ny, w, ny);
+
+            } else {
+
+                paint.drawLine(w - 4, y, w, y);
+                if (ny != y) paint.drawLine(w - 4, ny, w, ny);
+            }
 	}
     }
 }
--- a/layer/WaveformLayer.h	Wed Mar 29 12:35:17 2006 +0000
+++ b/layer/WaveformLayer.h	Wed Mar 29 16:24:25 2006 +0000
@@ -186,6 +186,9 @@
     size_t getChannelArrangement(size_t &min, size_t &max,
                                  bool &merging, bool &mixing) const;
 
+    int getYForValue(View *v, Scale scale, float value, size_t channel,
+                     size_t minChannel, size_t maxChannel) const;
+
     float        m_gain;
     bool         m_autoNormalize;
     QColor       m_colour;
--- a/widgets/Pane.cpp	Wed Mar 29 12:35:17 2006 +0000
+++ b/widgets/Pane.cpp	Wed Mar 29 16:24:25 2006 +0000
@@ -162,7 +162,7 @@
 
 	    paint.setPen(Qt::black);
 	    paint.setBrush(Qt::white);
-	    paint.drawRect(0, 0, verticalScaleWidth, height());
+	    paint.drawRect(0, -1, verticalScaleWidth, height()+1);
 
 	    paint.setBrush(Qt::NoBrush);
 	    (*vi)->paintVerticalScale