]> git.sesse.net Git - kdenlive/commitdiff
Spectrogram:
authorSimon A. Eugster <simon.eu@gmail.com>
Tue, 14 Dec 2010 12:59:54 +0000 (12:59 +0000)
committerSimon A. Eugster <simon.eu@gmail.com>
Tue, 14 Dec 2010 12:59:54 +0000 (12:59 +0000)
* Re-using interpolation function (moved to FFTTools)
* Fixed mouse glitch (see previous commit)

svn path=/trunk/kdenlive/; revision=5176

src/audioscopes/audiospectrum.cpp
src/audioscopes/audiospectrum.h
src/audioscopes/ffttools.cpp
src/audioscopes/ffttools.h
src/audioscopes/spectrogram.cpp
src/audioscopes/spectrogram.h

index e0ce51de46dc45fa9cd724517d05a515520c6d6a..52ba211dc26d0acea6bea14b7d89e6365f597a7b 100644 (file)
@@ -178,7 +178,7 @@ QImage AudioSpectrum::renderAudioScope(uint, const QVector<int16_t> audioFrame,
         memcpy(m_lastFFT.data(), &(freqSpectrum[0]), fftWindow/2 * sizeof(float));
 
         uint right = ((float) m_freqMax)/(m_freq/2) * (m_lastFFT.size() - 1);
-        dbMap = interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -180);
+        dbMap = FFTTools::interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -180);
         m_lastFFTLock.release();
 
 
@@ -311,7 +311,7 @@ QImage AudioSpectrum::renderHUD(uint)
         // because the position could already have changed in the meantime (-> crash)
         if (m_lastFFT.size() > 0 && mouseX >= 0 && mouseX < m_innerScopeRect.width()) {
             uint right = ((float) m_freqMax)/(m_freq/2) * (m_lastFFT.size() - 1);
-            QVector<float> dbMap = AudioSpectrum::interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -120);
+            QVector<float> dbMap = FFTTools::interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -120);
 
             db = dbMap[mouseX];
             y = topDist + m_innerScopeRect.height()-1 - (dbMap[mouseX] - m_dBmin) / (m_dBmax-m_dBmin) * (m_innerScopeRect.height()-1);
@@ -463,78 +463,6 @@ void AudioSpectrum::handleMouseDrag(const QPoint movement, const RescaleDirectio
 }
 
 
-const QVector<float> AudioSpectrum::interpolatePeakPreserving(const QVector<float> in, const uint targetSize, uint left, uint right, float fill)
-{
-#ifdef DEBUG_AUDIOSPEC
-    QTime start = QTime::currentTime();
-#endif
-
-    if (right == 0) {
-        right = in.size()-1;
-    }
-    Q_ASSERT(targetSize > 0);
-    Q_ASSERT(left < right);
-
-    QVector<float> out(targetSize);
-
-
-    float x;
-    float x_prev = 0;
-    int xi;
-    uint i;
-    for (i = 0; i < targetSize; i++) {
-
-        // i:  Target index
-        // x:  Interpolated source index (float!)
-        // xi: floor(x)
-
-        // Transform [0,targetSize-1] to [left,right]
-        x = ((float) i) / (targetSize-1) * (right-left) + left;
-        xi = (int) floor(x);
-
-        if (x > in.size()-1) {
-            // This may happen if right > in.size()-1; Fill the rest of the vector
-            // with the default value now.
-            break;
-        }
-
-
-        // Use linear interpolation in order to get smoother display
-        if (xi == 0 || xi == in.size()-1) {
-            // ... except if we are at the left or right border of the input sigal.
-            // Special case here since we consider previous and future values as well for
-            // the actual interpolation (not possible here).
-            out[i] = in[xi];
-        } else {
-            if (in[xi] > in[xi+1]
-                && x_prev < xi) {
-                // This is a hack to preserve peaks.
-                // Consider f = {0, 100, 0}
-                //          x = {0.5,  1.5}
-                // Then x is 50 both times, and the 100 peak is lost.
-                // Get it back here for the first x after the peak (which is at xi).
-                // (x is the first after the peak if the previous x was smaller than floor(x).)
-                out[i] = in[xi];
-            } else {
-                out[i] =   (xi+1 - x) * in[xi]
-                      + (x - xi)   * in[xi+1];
-            }
-        }
-        x_prev = x;
-    }
-    // Fill the rest of the vector if the right border exceeds the input vector.
-    for (; i < targetSize; i++) {
-        out[i] = fill;
-    }
-
-#ifdef DEBUG_AUDIOSPEC
-    qDebug() << "Interpolated " << targetSize << " nodes from " << in.size() << " input points in " << start.elapsed() << " ms";
-#endif
-
-    return out;
-}
-
-
 #ifdef DEBUG_AUDIOSPEC
 #undef DEBUG_AUDIOSPEC
 #endif
index 670160c8d5a7d45a63cc27502665dfc5e372c8d9..2a92cc4cf128a36cbba304d5297f976038c5bed5 100644 (file)
@@ -79,21 +79,6 @@ private:
     /** The user has chosen a custom frequency. */
     bool m_customFreq;
 
-    /** This is linear interpolation with the special property that it preserves peaks, which is required
-        for e.g. showing correct Decibel values (where the peak values are of interest).
-        Consider f = {0, 100, 0}
-                 x = {0.5,  1.5}: With default linear interpolation x0 and x1 would both be mapped to 50.
-        This function maps x1 (the first position after the peak) to 100.
-
-        @param in           The source vector containing the data
-        @param targetSize   Number of interpolation nodes between ...
-        @param left         the left array index in the in-vector and ...
-        @param right        the right array index (both inclusive).
-        @param fill         If right lies outside of the array bounds (which is perfectly fine here) then this value
-                            will be used for filling the missing information.
-        */
-    static const QVector<float> interpolatePeakPreserving(const QVector<float> in, const uint targetSize, uint left = 0, uint right = 0, float fill = 0.0);
-
 #ifdef DEBUG_AUDIOSPEC
     long m_timeTotal;
     long m_showTotal;
index 2ede0fa584cb54a89788c6f9985a568d6b5807c8..2f8aa37e8213674520b82e83d1c51d04110a945d 100644 (file)
@@ -228,6 +228,77 @@ void FFTTools::fftNormalized(const QVector<int16_t> audioFrame, const uint chann
 #endif
 }
 
+const QVector<float> FFTTools::interpolatePeakPreserving(const QVector<float> in, const uint targetSize, uint left, uint right, float fill)
+{
+#ifdef DEBUG_FFTTOOLS
+    QTime start = QTime::currentTime();
+#endif
+
+    if (right == 0) {
+        right = in.size()-1;
+    }
+    Q_ASSERT(targetSize > 0);
+    Q_ASSERT(left < right);
+
+    QVector<float> out(targetSize);
+
+
+    float x;
+    float x_prev = 0;
+    int xi;
+    uint i;
+    for (i = 0; i < targetSize; i++) {
+
+        // i:  Target index
+        // x:  Interpolated source index (float!)
+        // xi: floor(x)
+
+        // Transform [0,targetSize-1] to [left,right]
+        x = ((float) i) / (targetSize-1) * (right-left) + left;
+        xi = (int) floor(x);
+
+        if (x > in.size()-1) {
+            // This may happen if right > in.size()-1; Fill the rest of the vector
+            // with the default value now.
+            break;
+        }
+
+
+        // Use linear interpolation in order to get smoother display
+        if (xi == 0 || xi == in.size()-1) {
+            // ... except if we are at the left or right border of the input sigal.
+            // Special case here since we consider previous and future values as well for
+            // the actual interpolation (not possible here).
+            out[i] = in[xi];
+        } else {
+            if (in[xi] > in[xi+1]
+                && x_prev < xi) {
+                // This is a hack to preserve peaks.
+                // Consider f = {0, 100, 0}
+                //          x = {0.5,  1.5}
+                // Then x is 50 both times, and the 100 peak is lost.
+                // Get it back here for the first x after the peak (which is at xi).
+                // (x is the first after the peak if the previous x was smaller than floor(x).)
+                out[i] = in[xi];
+            } else {
+                out[i] =   (xi+1 - x) * in[xi]
+                      + (x - xi)   * in[xi+1];
+            }
+        }
+        x_prev = x;
+    }
+    // Fill the rest of the vector if the right border exceeds the input vector.
+    for (; i < targetSize; i++) {
+        out[i] = fill;
+    }
+
+#ifdef DEBUG_FFTTOOLS
+    qDebug() << "Interpolated " << targetSize << " nodes from " << in.size() << " input points in " << start.elapsed() << " ms";
+#endif
+
+    return out;
+}
+
 #ifdef DEBUG_FFTTOOLS
 #undef DEBUG_FFTTOOLS
 #endif
index 9014d47e54fb8234e83a6e4f96df85ea450537f7..65a4b2ca215fbe05c8d5a18a2d9b82e984e1ae6d 100644 (file)
@@ -56,6 +56,22 @@ public:
     void fftNormalized(const QVector<int16_t> audioFrame, const uint channel, const uint numChannels, float *freqSpectrum,
                        const WindowType windowType, const uint windowSize, const float param = 0);
 
+
+    /** This is linear interpolation with the special property that it preserves peaks, which is required
+        for e.g. showing correct Decibel values (where the peak values are of interest).
+        Consider f = {0, 100, 0}
+                 x = {0.5,  1.5}: With default linear interpolation x0 and x1 would both be mapped to 50.
+        This function maps x1 (the first position after the peak) to 100.
+
+        @param in           The source vector containing the data
+        @param targetSize   Number of interpolation nodes between ...
+        @param left         the left array index in the in-vector and ...
+        @param right        the right array index (both inclusive).
+        @param fill         If right lies outside of the array bounds (which is perfectly fine here) then this value
+                            will be used for filling the missing information.
+        */
+    static const QVector<float> interpolatePeakPreserving(const QVector<float> in, const uint targetSize, uint left = 0, uint right = 0, float fill = 0.0);
+
 private:
     QHash<QString, kiss_fftr_cfg> m_fftCfgs; // FFT cfg cache
     QHash<QString, QVector<float> > m_windowFunctions; // Window function cache
index 5bf9a86b9182422057681e9a7b2b3fb9493d22be..c1d87c20f8e6db43b7ce962fc64978c74728954a 100644 (file)
@@ -342,16 +342,11 @@ QImage Spectrogram::renderAudioScope(uint, const QVector<int16_t> audioFrame, co
         QImage spectrum(m_scopeRect.size(), QImage::Format_ARGB32);
         spectrum.fill(qRgba(0,0,0,0));
         QPainter davinci(&spectrum);
-        const uint w = m_innerScopeRect.width();
         const uint h = m_innerScopeRect.height();
         const uint leftDist = m_innerScopeRect.left() - m_scopeRect.left();
         const uint topDist = m_innerScopeRect.top() - m_scopeRect.top();
-        float f;
-        float x;
-        float x_prev = 0;
         float val;
         uint windowSize;
-        uint xi;
         uint y;
         bool completeRedraw = true;
 
@@ -372,58 +367,27 @@ QImage Spectrogram::renderAudioScope(uint, const QVector<int16_t> audioFrame, co
         if (newData || m_parameterChanged) {
             m_parameterChanged = false;
 
+            QVector<float> dbMap;
+            uint right;
             for (QList<QVector<float> >::iterator it = m_fftHistory.begin(); it != m_fftHistory.end(); it++) {
 
                 windowSize = (*it).size();
 
-                // TODO use function
-                for (uint i = 0; i < w; i++) {
+                // Interpolate the frequency data to match the pixel coordinates
+                right = ((float) m_freqMax)/(m_freq/2) * (windowSize - 1);
+                dbMap = FFTTools::interpolatePeakPreserving((*it), m_innerScopeRect.width(), 0, right, -180);
 
-                    // i:   Pixel coordinate
-                    // f:   Target frequency
-                    // x:   Frequency array index (float!) corresponding to the pixel
-                    // xi:  floor(x)
-                    // val: dB value at position x (Range: [-inf,0])
+                for (int i = 0; i < dbMap.size(); i++) {
+                    val = dbMap[i];
 
-                    f = i/((float) w-1.0) * m_freqMax;
-                    x = 2*f/freq * (windowSize - 1);
-                    xi = (int) floor(x);
-
-                    if (x >= windowSize) {
-                        break;
-                    }
-
-                    // Use linear interpolation in order to get smoother display
-                    if (i == 0 || xi == windowSize-1) {
-                        // ... except if we are at the left or right border of the display or the spectrum
-                        val = (*it)[xi];
-                    } else {
-
-                        if ((*it)[xi] > (*it)[xi+1]
-                            && x_prev < xi) {
-                            // This is a hack to preserve peaks.
-                            // Consider f = {0, 100, 0}
-                            //          x = {0.5,  1.5}
-                            // Then x is 50 both times, and the 100 peak is lost.
-                            // Get it back here for the first x after the peak.
-                            val = (*it)[xi];
-                        } else {
-                            val =   (xi+1 - x) * (*it)[xi]
-                                  + (x - xi)   * (*it)[xi+1];
-                        }
-                    }
-
-                    // Normalize to [0 1], 1 corresponding to 0 dB and 0 to dbMin dB
+                    // Normalize dB value to [0 1], 1 corresponding to 0 dB and 0 to dbMin dB
                     val = (val-m_dBmax)/(m_dBmax-m_dBmin) + 1;
                     if (val < 0) {
                         val = 0;
                     } else if (val > 1) {
                         val = 1;
                     }
-
                     spectrum.setPixel(leftDist + i, topDist + h-1 - y, qRgba(255, 255, 255, val * 255));
-
-                    x_prev = x;
                 }
 
                 y++;
index 5e11d9a72aa284c74e994ea8a2466a57db8e5244..29a94c0aa080b710901ad5819afc678f286a9eb3 100644 (file)
@@ -68,7 +68,7 @@ private:
     int m_dBmin;
     int m_dBmax;
 
-    uint m_freqMax;
+    int m_freqMax;
     bool m_customFreq;
 
     bool m_parameterChanged;