changeset 1368:38f35c2e03c4

Merge branch waverevision
author Chris Cannam
date Thu, 01 Nov 2018 10:12:12 +0000
parents c2a3ac0a6688 (current diff) f5566f7271fe (diff)
children ca9a36a5ab76
files
diffstat 3 files changed, 153 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- a/layer/ColourDatabase.cpp	Tue Oct 30 16:23:03 2018 +0000
+++ b/layer/ColourDatabase.cpp	Thu Nov 01 10:12:12 2018 +0000
@@ -85,6 +85,26 @@
     return -1;
 }
 
+QColor
+ColourDatabase::getContrastingColour(int c) const
+{
+    QColor col = getColour(c);
+    if (col.red() > col.blue()) {
+        if (col.green() > col.blue()) {
+            return Qt::blue;
+        } else {
+            return Qt::yellow;
+        }
+    } else {
+        if (col.green() > col.blue()) {
+            return Qt::yellow;
+        } else {
+            return Qt::red;
+        }
+    }
+    return Qt::red;
+}
+
 bool
 ColourDatabase::useDarkBackground(int c) const
 {
--- a/layer/WaveformLayer.cpp	Tue Oct 30 16:23:03 2018 +0000
+++ b/layer/WaveformLayer.cpp	Thu Nov 01 10:12:12 2018 +0000
@@ -45,7 +45,6 @@
     m_gain(1.0f),
     m_autoNormalize(false),
     m_showMeans(true),
-    m_greyscale(true),
     m_channelMode(SeparateChannels),
     m_channel(-1),
     m_scale(LinearScale),
@@ -274,15 +273,6 @@
 }
 
 void
-WaveformLayer::setUseGreyscale(bool useGreyscale)
-{
-    if (m_greyscale == useGreyscale) return;
-    m_greyscale = useGreyscale;
-    m_cacheValid = false;
-    emit layerParametersChanged();
-}
-
-void
 WaveformLayer::setChannelMode(ChannelMode channelMode)
 {
     if (m_channelMode == channelMode) return;
@@ -356,14 +346,14 @@
     return true;
 }
 
-int
+double
 WaveformLayer::dBscale(double sample, int m) const
 {
     if (sample < 0.0) return dBscale(-sample, m);
     double dB = AudioLevel::multiplier_to_dB(sample);
     if (dB < -50.0) return 0;
     if (dB > 0.0) return m;
-    return int(((dB + 50.0) * m) / 50.0 + 0.1);
+    return ((dB + 50.0) * m) / 50.0;
 }
 
 int
@@ -547,7 +537,7 @@
         paint = &viewPainter;
     }
 
-    paint->setRenderHint(QPainter::Antialiasing, false);
+    paint->setRenderHint(QPainter::Antialiasing, true);
 
     if (m_middleLineHeight != 0.5) {
         paint->save();
@@ -764,9 +754,8 @@
     if (channels == 0) return;
 
     QColor baseColour = getBaseQColor();
-    vector<QColor> greys = getPartialShades(v);
-        
     QColor midColour = baseColour;
+    
     if (midColour == Qt::black) {
         midColour = Qt::gray;
     } else if (v->hasLightBackground()) {
@@ -775,9 +764,6 @@
         midColour = midColour.light(50);
     }
 
-    int prevRangeBottom = -1, prevRangeTop = -1;
-    QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour;
-
     double gain = m_effectiveGains[ch];
 
     int m = (h / channels) / 2;
@@ -795,7 +781,8 @@
         my = m + (((ch - minChannel) * h) / channels);
     }
 
-    paint->setPen(greys[1]);
+    // Horizontal axis along middle
+    paint->setPen(QPen(midColour, 0));
     paint->drawLine(x0, my, x1, my);
 
     paintChannelScaleGuides(v, paint, rect, ch);
@@ -808,6 +795,13 @@
     (void)frame1; // not actually used
 #endif
 
+    QPainterPath waveformPath;
+    QPainterPath meanPath;
+    QPainterPath clipPath;
+    vector<QPointF> individualSamplePoints;
+
+    bool firstPoint = true;
+    
     for (int x = x0; x <= x1; ++x) {
 
         sv_frame_t f0, f1;
@@ -863,7 +857,7 @@
             continue;
         }
 
-        int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0;
+        double rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0;
 
         if (mergingChannels && ranges.size() > 1) {
 
@@ -895,65 +889,61 @@
             }
         }
 
-        int greyLevels = 1;
-        if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4;
-
         switch (m_scale) {
 
         case LinearScale:
-            rangeBottom = int(double(m * greyLevels) * range.min() * gain);
-            rangeTop    = int(double(m * greyLevels) * range.max() * gain);
-            meanBottom  = int(double(-m) * range.absmean() * gain);
-            meanTop     = int(double(m) * range.absmean() * gain);
+            rangeBottom = range.min() * gain * m;
+            rangeTop    = range.max() * gain * m;
+            meanBottom  = range.absmean() * gain * (-m);
+            meanTop     = range.absmean() * gain * m;
             break;
 
         case dBScale:
             if (!mergingChannels) {
-                int db0 = dBscale(range.min() * gain, m);
-                int db1 = dBscale(range.max() * gain, m);
-                rangeTop    = std::max(db0, db1);
-                meanTop     = std::min(db0, db1);
+                double db0 = dBscale(range.min() * gain, m);
+                double db1 = dBscale(range.max() * gain, m);
+                rangeTop = std::max(db0, db1);
+                meanTop = std::min(db0, db1);
                 if (mixingChannels) rangeBottom = meanTop;
                 else rangeBottom = dBscale(range.absmean() * gain, m);
-                meanBottom  = rangeBottom;
+                meanBottom = rangeBottom;
             } else {
-                rangeBottom = -dBscale(range.min() * gain, m * greyLevels);
-                rangeTop    =  dBscale(range.max() * gain, m * greyLevels);
-                meanBottom  = -dBscale(range.absmean() * gain, m);
-                meanTop     =  dBscale(range.absmean() * gain, m);
+                rangeBottom = -dBscale(range.min() * gain, m);
+                rangeTop = dBscale(range.max() * gain, m);
+                meanBottom = -dBscale(range.absmean() * gain, m);
+                meanTop = dBscale(range.absmean() * gain, m);
             }
             break;
 
         case MeterScale:
             if (!mergingChannels) {
-                int r0 = abs(AudioLevel::multiplier_to_preview(range.min() * gain, m));
-                int r1 = abs(AudioLevel::multiplier_to_preview(range.max() * gain, m));
-                rangeTop    = std::max(r0, r1);
-                meanTop     = std::min(r0, r1);
+                double r0 = fabs(AudioLevel::multiplier_to_preview
+                                 (range.min() * gain, m));
+                double r1 = fabs(AudioLevel::multiplier_to_preview
+                                 (range.max() * gain, m));
+                rangeTop = std::max(r0, r1);
+                meanTop = std::min(r0, r1);
                 if (mixingChannels) rangeBottom = meanTop;
-                else rangeBottom = AudioLevel::multiplier_to_preview(range.absmean() * gain, m);
+                else rangeBottom = AudioLevel::multiplier_to_preview
+                         (range.absmean() * gain, m);
                 meanBottom  = rangeBottom;
             } else {
-                rangeBottom = -AudioLevel::multiplier_to_preview(range.min() * gain, m * greyLevels);
-                rangeTop    =  AudioLevel::multiplier_to_preview(range.max() * gain, m * greyLevels);
-                meanBottom  = -AudioLevel::multiplier_to_preview(range.absmean() * gain, m);
-                meanTop     =  AudioLevel::multiplier_to_preview(range.absmean() * gain, m);
+                rangeBottom = -AudioLevel::multiplier_to_preview
+                    (range.min() * gain, m);
+                rangeTop = AudioLevel::multiplier_to_preview
+                    (range.max() * gain, m);
+                meanBottom = -AudioLevel::multiplier_to_preview
+                    (range.absmean() * gain, m);
+                meanTop = AudioLevel::multiplier_to_preview
+                    (range.absmean() * gain, m);
             }
             break;
         }
 
-        rangeBottom = my * greyLevels - rangeBottom;
-        rangeTop    = my * greyLevels - rangeTop;
-        meanBottom  = my - meanBottom;
-        meanTop     = my - meanTop;
-
-        int topFill = (rangeTop % greyLevels);
-        if (topFill > 0) topFill = greyLevels - topFill;
-
-        int bottomFill = (rangeBottom % greyLevels);
-
-        rangeTop = rangeTop / greyLevels;
-        rangeBottom = rangeBottom / greyLevels;
+        rangeBottom = my - rangeBottom;
+        rangeTop = my - rangeTop;
+        meanBottom = my - meanBottom;
+        meanTop = my - meanTop;
 
         bool clipped = false;
 
@@ -962,99 +952,102 @@
         if (rangeBottom < my - m) { rangeBottom = my - m; }
         if (rangeBottom > my + m) { rangeBottom = my + m; }
 
-        if (range.max() <= -1.0 ||
-            range.max() >= 1.0) clipped = true;
+        if (range.max() <= -1.0 || range.max() >= 1.0) {
+            clipped = true;
+        }
             
-        if (meanBottom > rangeBottom) meanBottom = rangeBottom;
-        if (meanTop < rangeTop) meanTop = rangeTop;
+        bool drawMean = m_showMeans;
 
-        bool drawMean = m_showMeans;
-        if (meanTop == rangeTop) {
-            if (meanTop < meanBottom) ++meanTop;
-            else drawMean = false;
+        meanTop = meanTop - 0.5;
+        meanBottom = meanBottom + 0.5;
+        
+        if (meanTop <= rangeTop + 1.0) {
+            meanTop = rangeTop + 1.0;
         }
-        if (meanBottom == rangeBottom && m_scale == LinearScale) {
-            if (meanBottom > meanTop) --meanBottom;
-            else drawMean = false;
+        if (meanBottom >= rangeBottom - 1.0 && m_scale == LinearScale) {
+            meanBottom = rangeBottom - 1.0;
         }
-
-        if (showIndividualSample) {
-            paint->setPen(baseColour);
-            paint->drawRect(x-1, rangeTop-1, 2, 2);
-            if (rangeTop != rangeBottom) { // e.g. for "butterfly" merging mode
-                paint->drawRect(x-1, rangeBottom-1, 2, 2);
-            }
-        }
-        
-        if (x != x0 && prevRangeBottom != -1) {
-            if (prevRangeBottom > rangeBottom + 1 &&
-                prevRangeTop    > rangeBottom + 1) {
-//                    paint->setPen(midColour);
-                paint->setPen(baseColour);
-                paint->drawLine(x-1, prevRangeTop, x, rangeBottom + 1);
-                paint->setPen(prevRangeTopColour);
-                paint->drawPoint(x-1, prevRangeTop);
-            } else if (prevRangeBottom < rangeTop - 1 &&
-                       prevRangeTop    < rangeTop - 1) {
-//                    paint->setPen(midColour);
-                paint->setPen(baseColour);
-                paint->drawLine(x-1, prevRangeBottom, x, rangeTop - 1);
-                paint->setPen(prevRangeBottomColour);
-                paint->drawPoint(x-1, prevRangeBottom);
-            }
-        }
-
-        if (m_model->isReady()) {
-            if (clipped /*!!! ||
-                          range.min() * gain <= -1.0 ||
-                          range.max() * gain >=  1.0 */) {
-                paint->setPen(Qt::red); //!!! getContrastingColour
-            } else {
-                paint->setPen(baseColour);
-            }
-        } else {
-            paint->setPen(midColour);
+        if (meanTop > meanBottom - 1.0) {
+            drawMean = false;
         }
 
 #ifdef DEBUG_WAVEFORM_PAINT_BY_PIXEL
         SVCERR << "range " << rangeBottom << " -> " << rangeTop << ", means " << meanBottom << " -> " << meanTop << ", raw range " << range.min() << " -> " << range.max() << endl;
 #endif
 
-        if (rangeTop == rangeBottom) {
-            paint->drawPoint(x, rangeTop);
-        } else {
-            paint->drawLine(x, rangeBottom, x, rangeTop);
-        }
-
-        prevRangeTopColour = baseColour;
-        prevRangeBottomColour = baseColour;
-
-        if (m_greyscale && (m_scale == LinearScale) && m_model->isReady()) {
-            if (!clipped) {
-                if (rangeTop < rangeBottom) {
-                    if (topFill > 0 &&
-                        (!drawMean || (rangeTop < meanTop - 1))) {
-                        paint->setPen(greys[topFill - 1]);
-                        paint->drawPoint(x, rangeTop);
-                        prevRangeTopColour = greys[topFill - 1];
-                    }
-                    if (bottomFill > 0 && 
-                        (!drawMean || (rangeBottom > meanBottom + 1))) {
-                        paint->setPen(greys[bottomFill - 1]);
-                        paint->drawPoint(x, rangeBottom);
-                        prevRangeBottomColour = greys[bottomFill - 1];
-                    }
-                }
+        double rangeMiddle = (rangeTop + rangeBottom) / 2.0;
+        bool trivialRange = (fabs(rangeTop - rangeBottom) < 1.0);
+        double px = x + 0.5;
+        
+        if (showIndividualSample) {
+            individualSamplePoints.push_back(QPointF(px, rangeTop));
+            if (!trivialRange) {
+                // common e.g. in "butterfly" merging mode
+                individualSamplePoints.push_back(QPointF(px, rangeBottom));
             }
         }
         
+        if (firstPoint) {
+            waveformPath = QPainterPath(QPointF(px, rangeMiddle));
+            firstPoint = false;
+        } else {
+            waveformPath.lineTo(QPointF(px, rangeMiddle));
+        }
+
+        if (!trivialRange) {
+            waveformPath.lineTo(QPointF(px, rangeTop));
+            waveformPath.lineTo(QPointF(px, rangeBottom));
+            waveformPath.lineTo(QPointF(px, rangeMiddle));
+        }
+
         if (drawMean) {
-            paint->setPen(midColour);
-            paint->drawLine(x, meanBottom, x, meanTop);
+            meanPath.moveTo(QPointF(px, meanBottom));
+            meanPath.lineTo(QPointF(px, meanTop));
         }
-        
-        prevRangeBottom = rangeBottom;
-        prevRangeTop = rangeTop;
+
+        if (clipped) {
+            if (trivialRange) {
+                clipPath.moveTo(QPointF(px, rangeMiddle));
+                clipPath.lineTo(QPointF(px+1, rangeMiddle));
+            } else {
+                clipPath.moveTo(QPointF(px, rangeBottom));
+                clipPath.lineTo(QPointF(px, rangeTop));
+            }
+        }
+    }
+
+    double penWidth = 1.0;
+    
+    if (m_model->isReady()) {
+        paint->setPen(QPen(baseColour, penWidth));
+    } else {
+        paint->setPen(QPen(midColour, penWidth));
+    }
+    paint->drawPath(waveformPath);
+
+    if (!clipPath.isEmpty()) {
+        paint->save();
+        paint->setPen(QPen(ColourDatabase::getInstance()->
+                           getContrastingColour(m_colour), penWidth));
+        paint->drawPath(clipPath);
+        paint->restore();
+    }
+
+    if (!meanPath.isEmpty()) {
+        paint->save();
+        paint->setPen(QPen(midColour, penWidth));
+        paint->drawPath(meanPath);
+        paint->restore();
+    }
+    
+    if (!individualSamplePoints.empty()) {
+        paint->save();
+        paint->setPen(QPen(baseColour, penWidth));
+        double sz = ViewManager::scalePixelSize(2.0);
+        for (QPointF p: individualSamplePoints) {
+            paint->drawRect(QRectF(p.x() - sz/2, p.y() - sz/2, sz, sz));
+        }
+        paint->restore();
     }
 }
 
@@ -1239,7 +1232,7 @@
         break;
 
     case dBScale:
-        vy = dBscale(value, m);
+        vy = int(dBscale(value, m));
         break;
     }
 
@@ -1511,7 +1504,8 @@
                  "autoNormalize=\"%9\"")
         .arg(m_gain)
         .arg(m_showMeans)
-        .arg(m_greyscale)
+        .arg(true) // Option removed, but effectively always on, so
+                   // retained in the session file for compatibility
         .arg(m_channelMode)
         .arg(m_channel)
         .arg(m_scale)
@@ -1536,10 +1530,6 @@
                       attributes.value("showMeans") == "true");
     setShowMeans(showMeans);
 
-    bool greyscale = (attributes.value("greyscale") == "1" ||
-                      attributes.value("greyscale") == "true");
-    setUseGreyscale(greyscale);
-
     ChannelMode channelMode = (ChannelMode)
         attributes.value("channelMode").toInt(&ok);
     if (ok) setChannelMode(channelMode);
@@ -1555,7 +1545,7 @@
 
     bool aggressive = (attributes.value("aggressive") == "1" ||
                        attributes.value("aggressive") == "true");
-    setUseGreyscale(aggressive);
+    setAggressiveCacheing(aggressive);
 
     bool autoNormalize = (attributes.value("autoNormalize") == "1" ||
                           attributes.value("autoNormalize") == "true");
--- a/layer/WaveformLayer.h	Tue Oct 30 16:23:03 2018 +0000
+++ b/layer/WaveformLayer.h	Thu Nov 01 10:12:12 2018 +0000
@@ -87,19 +87,6 @@
     void setShowMeans(bool);
     bool getShowMeans() const { return m_showMeans; }
 
-    /**
-     * Set whether to use shades of grey (or of the base colour) to
-     * provide additional perceived vertical resolution (i.e. using
-     * half-filled pixels to represent levels that only just meet the
-     * pixel unit boundary).  This provides a small improvement in
-     * waveform quality at a small cost in rendering speed.
-     * 
-     * The default is to use greyscale.
-     */
-    void setUseGreyscale(bool);
-    bool getUseGreyscale() const { return m_greyscale; }
-
-
     enum ChannelMode { SeparateChannels, MixChannels, MergeChannels };
 
     /**
@@ -205,7 +192,7 @@
     virtual bool canExistWithoutModel() const { return true; }
 
 protected:
-    int dBscale(double sample, int m) const;
+    double dBscale(double sample, int m) const;
 
     const RangeSummarisableTimeValueModel *m_model; // I do not own this
 
@@ -247,7 +234,6 @@
     float        m_gain;
     bool         m_autoNormalize;
     bool         m_showMeans;
-    bool         m_greyscale;
     ChannelMode  m_channelMode;
     int          m_channel;
     Scale        m_scale;