Hello.

Waveform view on mixxx looks very spiky. This results from peak detection 
algorithm that extract waveform envelop. Since in my eyes rms averaging is the 
better, if programmed it into mixxx. On the links below one can compare peak 
detection and rms averaging on a techno track and a rock song. It doesn't look 
that much better like I had expected but when playing sound files even the 
small spikes are very helpful by getting a feeling of the beats and rhythm 
hidden behind the waveform.

http://img641.imageshack.us/i/mixxxpeak.png/
http://img52.imageshack.us/i/mixxxrms.png/

Since rms averaging requiers a lot cpu time performance is a critical issue. A 
tricky alogrithm can reduce calculation afford with minor loss results. In 
fact my variant is as fast as peak detection.

The attachment contains a patch made from revision 2293 with the changes I've 
applied to implement rms averaging. The code is made with limit checking thus 
at least critical bugs which make mixxx instable are very unlikely.

Also there is an open issue. I'm not a daily C++ programmer but if 
WaveformAnalyser object is destroy QVector<float> is freed as well.


In hope I could help

mik
=== modified file 'mixxx/src/analyserwaveform.cpp'
--- mixxx/src/analyserwaveform.cpp	2009-07-14 19:01:34 +0000
+++ mixxx/src/analyserwaveform.cpp	2010-01-31 16:21:56 +0000
@@ -42,6 +42,7 @@
 
     downsample = new QVector<float>(numDownsamples);
     downsampleVector = downsample->data();
+    downsamplePos = 0;
     int i;
 
     // Set the buffer to zero
@@ -55,11 +56,24 @@
 
     qDebug() << "AnalyserWaveform: f " << sampleRate << " samplesPerDownsample: " << samplesPerDownsample << " downsamples " << numDownsamples << " from " << totalSamples;
 
-    m_iStrideLength = samplesPerDownsample*2;
-    m_iCurPos = 0;
-    m_iBufferPos = 0;
-    m_fLMax = -1.0;
-    m_fRMax = -1.0;
+
+    m_iStrideLength = samplesPerDownsample;
+
+    m_PreBufSize = 40; // must be smaller than samplesPerDownsample
+    m_PreBufPos = 0;
+    m_PreBuf = 0;
+
+    float AveragingTimeInSec = 0.01;
+    m_AveragingBufPos = 0;
+    m_AveragingBufSize = round((float) sampleRate * AveragingTimeInSec/m_PreBufSize); // samplerate in 1/Sec
+    m_AveragingBuf.resize(m_AveragingBufSize);
+    // Set the buffer to zero
+    for(int i=0;i<m_AveragingBufSize;i++) {
+        m_AveragingBuf[i] = 0;
+    }
+
+    m_iCurTracksamplePos = 0; // mono samples
+    m_AnalysedTracksamplesPos = 0; // mono samples
 
     m_iStartTime = clock();
 }
@@ -69,34 +83,55 @@
     if(downsample == NULL) {
         return;
     }
+/**
+  When ever m_StrideLenght in samples is elapsed average of AveragingBuf is
+  calculated. AvegagingBuf averages over a period longer than m_StrideLength.
+  This is intentinally although it shouldn't be to long to get a responsive
+  waveform.
+
+  AveragingBuf is updated with PreBuf asynchron to m_StrideLength this means
+  some few values lately added to PreBuf aren't recognized when calculating
+  average over AveragingBuf. This is no big disatvantage since it is only a
+  small part compared to content AveragingBuf and audio signal doesn't change
+  that fast as well.
+
+  PreBuf contains the sum of many samples thus when calculating the sum of
+  AveragingBuf less values have to be summed up. That is the point where this
+  algorithm speeds up calculation. As well as every sub step in for loop is
+  out lay with as simple as possible if conditions that are fast to evaluate. 
+**/
+    // iLen in total samples
+    int len = iLen - iLen%2; // round down to even value 
 
     //qDebug() << "AnalyserWaveform::process() processing " << iLen << " samples";
-    for(int i=0; i<iLen; i+=2) {
-      
-        if(m_iBufferPos >= m_iStrideLength) {
-            //(*downsample)[m_iCurPos] = m_fLMax;
-            *(downsampleVector++) = m_fLMax;
-            m_iCurPos++;
-
-            //(*downsample)[m_iCurPos] = m_fRMax;
-            *(downsampleVector++) = m_fRMax;
-            m_iCurPos++;
-            
-            m_iBufferPos = 0;
-            m_fLMax = -1.0f;
-            m_fRMax = -1.0f;
-        }
-        CSAMPLE sl = fabs(pIn[i]);
-        CSAMPLE sr = fabs(pIn[i+1]);
-
-        if(m_iBufferPos <= 20) {
-            if(sl > m_fLMax)
-                m_fLMax = sl;
-            if(sr > m_fRMax)
-                m_fRMax = sr;
-        }
-	
-        m_iBufferPos += 2;
+    for(int i=0; i<len; i+=2) {
+        m_PreBuf += pIn[i] * pIn[i];
+        m_PreBuf += pIn[i+1] * pIn[i+1];
+        m_PreBufPos++;
+        if(m_PreBufPos >= m_PreBufSize) {
+            m_AveragingBuf[m_AveragingBufPos++] = m_PreBuf;
+            m_PreBufPos = 0;
+            m_PreBuf = 0;
+            if(m_AveragingBufPos >= m_AveragingBufSize) {
+                m_AveragingBufPos = 0;
+            }
+        }
+
+        m_iCurTracksamplePos++;
+        if(m_iCurTracksamplePos >= m_AnalysedTracksamplesPos+m_iStrideLength) {
+            m_AnalysedTracksamplesPos += m_iStrideLength;
+            float temp = 0;
+            for(int j = 0; j < m_AveragingBufSize;j++) {
+                temp += m_AveragingBuf[j];
+            }
+            temp = sqrt(temp/(m_PreBufSize*m_AveragingBufSize)); // consider numbers get large
+
+            if( downsamplePos < downsample->size()) { // checking limits is a must
+              *(downsampleVector++) = temp;
+              *(downsampleVector++) = temp;
+            }
+            downsamplePos += 2;
+        }
     }
 }
 
@@ -104,7 +139,7 @@
     if(downsample == NULL) {
         return;
     }
-
+ 
     downsample = NULL;
     downsampleVector = NULL;
     

=== modified file 'mixxx/src/analyserwaveform.h'
--- mixxx/src/analyserwaveform.h	2009-02-01 21:40:44 +0000
+++ mixxx/src/analyserwaveform.h	2010-01-31 16:03:52 +0000
@@ -12,15 +12,22 @@
 	void finalise(TrackInfoObject* tio);
 
 private:
-	QVector<float> *downsample;
+    QVector<float> *downsample;
     float *downsampleVector;
+    int downsamplePos;
+
+    QVector<float> m_AveragingBuf;
+    int m_AveragingBufPos;
+    int m_AveragingBufSize;
+
+    float m_PreBuf;
+    int m_PreBufPos;
+    int m_PreBufSize;
     
     int m_iStartTime;
     int m_iStrideLength;
-    int m_iCurPos;
-    int m_iBufferPos;
-    float m_fLMax;
-    float m_fRMax;
+    int m_iCurTracksamplePos; // stereo samples
+    int m_AnalysedTracksamplesPos; // sereo samples
 };
 
 #endif

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel

Reply via email to