diff layer/WaveformLayer.cpp @ 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
line wrap: on
line diff
--- 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);
+            }
 	}
     }
 }