]> git.sesse.net Git - kdenlive/blobdiff - src/audioscopes/audiospectrum.cpp
Audio Spectrum: Increased performance by 25 % by directly painting lines instead...
[kdenlive] / src / audioscopes / audiospectrum.cpp
index ef0e3c68bfd677d15bc3f917d0f6ebbb6001a700..a92f6f5d5244577c9d71ed05beec824f11bd89e7 100644 (file)
 
 #include <iostream>
 
-// Enables debugging, like writing a GNU Octave .m file to /tmp
-//#define DEBUG_AUDIOSPEC
-
+// (defined in the header file)
 #ifdef DEBUG_AUDIOSPEC
 #include <QDebug>
 #endif
 
+// Draw lines instead of single pixels.
+// This is about 25 % faster, especially when enlarging the scope to e.g. 1680x1050 px.
+#define AUDIOSPEC_LINES
+
 #define MIN_DB_VALUE -120
 #define MAX_FREQ_VALUE 96000
 #define MIN_FREQ_VALUE 1000
@@ -36,16 +38,23 @@ AudioSpectrum::AudioSpectrum(QWidget *parent) :
         m_fftTools(),
         m_lastFFT(),
         m_lastFFTLock(1)
+  #ifdef DEBUG_AUDIOSPEC
+        ,m_timeTotal(0)
+        ,m_showTotal(0)
+  #endif
 {
     ui = new Ui::AudioSpectrum_UI;
     ui->setupUi(this);
 
 
     m_aResetHz = new QAction(i18n("Reset maximum frequency to sampling rate"), this);
+    m_aTrackMouse = new QAction(i18n("Track mouse"), this);
+    m_aTrackMouse->setCheckable(true);
 
 
     m_menu->addSeparator();
     m_menu->addAction(m_aResetHz);
+    m_menu->addAction(m_aTrackMouse);
     m_menu->removeAction(m_aRealtime);
 
 
@@ -78,6 +87,7 @@ AudioSpectrum::~AudioSpectrum()
     writeConfig();
 
     delete m_aResetHz;
+    delete m_aTrackMouse;
 }
 
 void AudioSpectrum::readConfig()
@@ -89,6 +99,7 @@ void AudioSpectrum::readConfig()
 
     ui->windowSize->setCurrentIndex(scopeConfig.readEntry("windowSize", 0));
     ui->windowFunction->setCurrentIndex(scopeConfig.readEntry("windowFunction", 0));
+    m_aTrackMouse->setChecked(scopeConfig.readEntry("trackMouse", true));
     m_dBmax = scopeConfig.readEntry("dBmax", 0);
     m_dBmin = scopeConfig.readEntry("dBmin", -70);
     m_freqMax = scopeConfig.readEntry("freqMax", 0);
@@ -107,6 +118,7 @@ void AudioSpectrum::writeConfig()
 
     scopeConfig.writeEntry("windowSize", ui->windowSize->currentIndex());
     scopeConfig.writeEntry("windowFunction", ui->windowFunction->currentIndex());
+    scopeConfig.writeEntry("trackMouse", m_aTrackMouse->isChecked());
     scopeConfig.writeEntry("dBmax", m_dBmax);
     scopeConfig.writeEntry("dBmin", m_dBmin);
     if (m_customFreq) {
@@ -170,6 +182,8 @@ QImage AudioSpectrum::renderAudioScope(uint, const QVector<int16_t> audioFrame,
         m_lastFFTLock.release();
 
 
+        QTime drawTime = QTime::currentTime();
+
         // Draw the spectrum
         QImage spectrum(m_scopeRect.size(), QImage::Format_ARGB32);
         spectrum.fill(qRgba(0,0,0,0));
@@ -179,6 +193,11 @@ QImage AudioSpectrum::renderAudioScope(uint, const QVector<int16_t> audioFrame,
         const uint topDist = m_innerScopeRect.top() - m_scopeRect.top();
         int yMax;
 
+#ifdef AUDIOSPEC_LINES
+        QPainter davinci(&spectrum);
+        davinci.setPen(AbstractScopeWidget::penThin);
+#endif
+
         for (uint i = 0; i < w; i++) {
             yMax = (dbMap[i] - m_dBmin) / (m_dBmax-m_dBmin) * (h-1);
             if (yMax < 0) {
@@ -186,11 +205,21 @@ QImage AudioSpectrum::renderAudioScope(uint, const QVector<int16_t> audioFrame,
             } else if (yMax >= (int)h) {
                 yMax = h-1;
             }
+#ifdef AUDIOSPEC_LINES
+            davinci.drawLine(leftDist + i, topDist + h-1, leftDist + i, topDist + h-1 - yMax);
+#else
             for (int y = 0; y < yMax && y < (int)h; y++) {
                 spectrum.setPixel(leftDist + i, topDist + h-y-1, qRgba(225, 182, 255, 255));
             }
+#endif
         }
 
+#ifdef DEBUG_AUDIOSPEC
+        m_showTotal++;
+        m_timeTotal += drawTime.elapsed();
+        qDebug() << widgetName() << " took " << drawTime.elapsed() << " ms for drawing. Average: " << ((float)m_timeTotal/m_showTotal) ;
+#endif
+
         emit signalScopeRenderingFinished(start.elapsed(), 1);
 
 
@@ -268,7 +297,7 @@ QImage AudioSpectrum::renderHUD(uint)
         }
     }
 
-    if (m_mouseWithinWidget && mouseX < m_innerScopeRect.width()-1) {
+    if (m_aTrackMouse->isChecked() && m_mouseWithinWidget && mouseX < m_innerScopeRect.width()-1) {
         davinci.setPen(AbstractScopeWidget::penThin);
 
         x = leftDist + mouseX;
@@ -278,7 +307,9 @@ QImage AudioSpectrum::renderHUD(uint)
         bool drawDb = false;
 
         m_lastFFTLock.acquire();
-        if (m_lastFFT.size() > 0) {
+        // We need to test whether the mouse is inside the widget
+        // 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) * (m_lastFFT.size() - 1);
             QVector<float> dbMap = AudioSpectrum::interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -120);
 
@@ -434,6 +465,10 @@ 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;
     }
@@ -490,6 +525,10 @@ const QVector<float> AudioSpectrum::interpolatePeakPreserving(const QVector<floa
         out[i] = fill;
     }
 
+#ifdef DEBUG_AUDIOSPEC
+    qDebug() << "Interpolated " << targetSize << " nodes from " << in.size() << " input points in " << start.elapsed() << " ms";
+#endif
+
     return out;
 }