Hi,
I just made some other changes to this. You can try this patch instead of
that I sent before.

On Sun, May 4, 2008 at 6:57 PM, Albert Santoni <[EMAIL PROTECTED]> wrote:

> Hi Martin,
>
> I have a few comments and questions about your patch.
>
> On Tue, 2008-04-29 at 18:49 +0200, Martin Sakmar wrote:
> > Hi,
> >
> > Most of my mp3s have BPMs stored in tag, so I made some changes to
> > read and use them. Additional changes are especially related to
> > minimum and maximum BPM values in BpmDetect class. When maxBpm is
> > lower than 2*minBpm (passed to BpmDetect constructor), then
> > BpmDetect::getBpm() will sometimes return 0. So default values are
> > used in this constructor (defined in bpmdetect.h) and commented out
> > values passed to it from BpmScheme in BpmDetector. BPM is corrected
> > with correctBPM to be within the limit specified by BpmScheme (or
> > little more, rather than 0).
>
> Ok, so the quirk that the initial BPM detection range must be greater
> than {min, min*2} is something that was in Mixxx before your patch,
> correct?
>

I added a checkbox to dlgprefbpm to enable or disable this. Maybe correctBpm
could be modified to return zero if the BPM can't be within the range, but I
prefer returning a BPM if it can be detected.


> We've received many requests for Mixxx read to BPMs from ID3 tags, so I
> think many people are going to appreciate this.
>
> In track.cpp, in slotLoadPlayer1(), your patch has this chunk:
>
> @@ -886,6 +888,8 @@
>     // Request a new track from the reader:
>     m_pBuffer1->getReader()->requestNewTrack(m_pTrackPlayer1,
> bStartFromEndPos);
>
> +    SoundSourceProxy::ParseHeader(m_pTrackPlayer1);
> +    if(m_pTrackPlayer1->getBpm()) m_pTrackPlayer1->setBpmConfirm(true);
>     // Detect BPM if required
>     if (m_pTrackPlayer1->getBpmConfirm()== false ||
> m_pTrackPlayer1->getBpm() == 0.)
>         m_pTrackPlayer1->sendToBpmQueue();
>
> Why do you call ParseHeader() here? As best as I can tell, ParseHeader()
> gets called when a new TrackInfoObject is created.
>

ParseHeader is required here to read BPM from tag on load. It's called when
TrackInfo is created from filename, but not when you load a song from
library. I added a bool to TrackInfoObject which is set to true, when header
is parsed, and then it won't be called again in slotLoadPlayer if it already
was called.


> Other than that, everything looks pretty good. If you can shed some
> light on my two questions, I'd be happy to slip this into SVN before the
> beta3 release.
>
> Thanks,
> Albert
>

Regards,
Martin
Index: lib/soundtouch/STTypes.h
===================================================================
--- lib/soundtouch/STTypes.h	(revision 1979)
+++ lib/soundtouch/STTypes.h	(working copy)
@@ -47,6 +47,11 @@
 
     typedef  int    BOOL;
 
+#if defined(FALSE) || defined(TRUE)
+    #undef FALSE
+    #undef TRUE
+#endif
+
     #define FALSE   0
     #define TRUE    1
 
Index: src/soundsource.cpp
===================================================================
--- src/soundsource.cpp	(revision 1979)
+++ src/soundsource.cpp	(working copy)
@@ -55,3 +55,10 @@
 {
     return m_qFilename;
 }
+
+float SoundSource::str2bpm( QString sBpm ) {
+  float bpm = sBpm.toFloat();
+  if(bpm < 60) bpm = 0;
+  while( bpm > 300 ) bpm = bpm / 10.;
+  return bpm;
+}
Index: src/dlgprefbpm.cpp
===================================================================
--- src/dlgprefbpm.cpp	(revision 1979)
+++ src/dlgprefbpm.cpp	(working copy)
@@ -45,7 +45,8 @@
     // Connection
     connect(chkDetectOnImport,      SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmDetectOnImport(int)));
     connect(chkWriteID3,            SIGNAL(stateChanged(int)), this, SLOT(slotSetWriteID3Tag(int)));
-    connect(chkEnableBpmDetection,   SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmEnabled(int)));
+    connect(chkEnableBpmDetection,  SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmEnabled(int)));
+    connect(chkAboveRange,          SIGNAL(stateChanged(int)), this, SLOT(slotSetAboveRange(int)));
     
     // TODO: Move this over the the scheme dialog
     
@@ -69,6 +70,12 @@
     else
         chkEnableBpmDetection->setChecked(false);
 
+    int iBpmAboveRange = config->getValueString(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled")).toInt();
+    if (iBpmAboveRange)
+        chkAboveRange->setChecked(true);
+    else
+        chkAboveRange->setChecked(false);
+
     // Set default value for detect BPM on import check box
     int iDetectBpmOnImport = config->getValueString(ConfigKey(CONFIG_KEY,"DetectBPMOnImport")).toInt();
     if (iDetectBpmOnImport)
@@ -145,6 +152,13 @@
 
 }
 
+void DlgPrefBpm::slotSetAboveRange(int) {
+    if (chkAboveRange->isChecked())
+        config->set(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled"), ConfigValue(1));
+    else
+        config->set(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled"), ConfigValue(0));
+}
+
 void DlgPrefBpm::slotSetBpmRangeStart(int begin)
 {
     //config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(begin));
@@ -260,12 +274,14 @@
     {
         chkDetectOnImport->setEnabled(true);
         chkWriteID3->setEnabled(true);
+        chkAboveRange->setEnabled(true);
         grpBpmSchemes->setEnabled(true);
-    }   
+    }
     else
     {
         chkDetectOnImport->setEnabled(false);
         chkWriteID3->setEnabled(false);
+        chkAboveRange->setEnabled(false);
         grpBpmSchemes->setEnabled(false);
     }   
    
Index: src/soundsourcemp3.cpp
===================================================================
--- src/soundsourcemp3.cpp	(revision 1979)
+++ src/soundsourcemp3.cpp	(working copy)
@@ -457,10 +457,10 @@
 {
     QString location = Track->getLocation();
 
-	QFile sizetest( location );
-	if (sizetest.size() == 0) {
-		return ERR;
-	}
+    QFile sizetest( location );
+    if (sizetest.size() == 0) {
+        return ERR;
+    }
 
     Track->setType("mp3");
 
@@ -478,6 +478,15 @@
             getField(tag,"TPE1",&s);
             if (s.length()>2)
                 Track->setArtist(s);
+            s="";
+            getField(tag,"TBPM",&s);
+            float bpm = 0;
+            if (s.length()>1) bpm = str2bpm(s);
+            if(bpm > 0) {
+                Track->setBpm(bpm);
+                Track->setBpmConfirm(true);
+            }
+            Track->setHeaderParsed(true);
 
             /*
                // On some tracks this segfaults. TLEN is very seldom used anyway...
Index: src/soundsourceoggvorbis.cpp
===================================================================
--- src/soundsourceoggvorbis.cpp	(revision 1979)
+++ src/soundsourceoggvorbis.cpp	(working copy)
@@ -182,6 +182,15 @@
         Track->setTitle(vorbis_comment_query(comment, "title", 0));
     if (QString(vorbis_comment_query(comment, "artist", 0)).length()!=0)
         Track->setArtist(vorbis_comment_query(comment, "artist", 0));
+    if (QString(vorbis_comment_query(comment, "TBPM", 0)).length()!=0) {
+        float bpm = str2bpm(vorbis_comment_query(comment, "TBPM", 0));
+        if(bpm > 0) {
+            Track->setBpm(bpm);
+            Track->setBpmConfirm(true);
+        }
+    }
+    Track->setHeaderParsed(true);
+
     Track->setType("ogg");
     Track->setDuration((int)ov_time_total(&vf, -1));
     Track->setBitrate(ov_bitrate(&vf, -1)/1000);
Index: src/bpmdetector.cpp
===================================================================
--- src/bpmdetector.cpp	(revision 1979)
+++ src/bpmdetector.cpp	(working copy)
@@ -101,8 +101,6 @@
 
 void BpmDetector::run()
 {
-    int i = 0;
-
     while (1)
     {
         TrackInfoObject * pTrackInfoObject = NULL;
@@ -152,16 +150,15 @@
         // Check if BPM has been detected in the meantime
         if (pTrackInfoObject->getBpmConfirm() == false || pTrackInfoObject->getBpm() == 0.)
         {
-            #define CHUNKSIZE 4096
+            const int numSamples = 8192;
 
             SoundSourceProxy * pSoundSource = new SoundSourceProxy(pTrackInfoObject);
-            int16_t data16[ CHUNKSIZE*2];      // for 16 bit samples
-            int8_t data8[ CHUNKSIZE ];            // for 8 bit samples
-            soundtouch::SAMPLETYPE samples[ CHUNKSIZE * 2];
+            int16_t data16[numSamples];      // for 16 bit samples
+            soundtouch::SAMPLETYPE samples[ numSamples ];
             unsigned int length = 0, read = 0, totalsteps = 0, pos = 0, end = 0;
-            int channels = 2, bits = 16;
+            int channels = 2;
             float frequency = 44100;
-            
+
             if(pTrackInfoObject->getSampleRate())
             {
                 frequency = pTrackInfoObject->getSampleRate();
@@ -170,12 +167,7 @@
             {
                 channels = pTrackInfoObject->getChannels();
             }
-            if(pTrackInfoObject->getBitrate())
-            {
-                bits = pTrackInfoObject->getBitrate();
-            }
 
-
             length = pSoundSource->length();
 
             if(!pScheme->getAnalyzeEntireSong())
@@ -184,7 +176,7 @@
                 pos = length / 2;
 
             }
-            
+
             if(pos %2 != 0)
             {
                 //Bug Fix: above formula allows iBeatPosStart
@@ -192,35 +184,26 @@
                 pos--;
             }
 
-            totalsteps = ( length / CHUNKSIZE );
+            totalsteps = ( length / numSamples );
             end = pos + length;
 
-            
-            BpmDetect bpmd( channels, ( int ) frequency, pScheme->getMaxBpm(), pScheme->getMinBpm() );
+            // Use default minBpm and maxBpm values?
+            int defaultrange = m_Config->getValueString(ConfigKey("[BPM]","BPMAboveRangeEnabled")).toInt();
+            BpmDetect bpmd( channels, ( int ) frequency, defaultrange ? MIN_BPM : pScheme->getMinBpm(),
+                                                         defaultrange ? MAX_BPM : pScheme->getMaxBpm() );
 
             int cprogress = 0;
             pSoundSource->seek(pos);
             do {
-                read = pSoundSource->read(CHUNKSIZE, data16);
+                read = pSoundSource->read(numSamples, data16);
 
                 if(read >= 2)
                 {
                     pos += read;
-
-                    //****************************************************
-                    // Replace:
-                    //result = FMOD_Sound_ReadData( sound, data16, CHUNKSIZE, &read );
-
-                    //****************************************************
                     for ( unsigned int i = 0; i < read ; i++ ) {
-                        int16_t test = data16[i];
-                        if(test > 0)
-                        {
-                            test = 0;
-                        }
                         samples[ i ] = ( float ) data16[ i ] / 32768;
                     }
-                    bpmd.inputSamples( samples, read / ( channels ) );
+                    bpmd.inputSamples( samples, read / channels );
 
                     cprogress++;
                     if ( cprogress % 250 == 0 ) {
@@ -233,24 +216,25 @@
                         }
                     }
                 }
-            } while (read == CHUNKSIZE && pos <= length);
+            } while (read == numSamples && pos <= end);
 
             float BPM = bpmd.getBpm();
-            if ( BPM != 0. ) {
-                BPM = Correct_BPM( BPM, pScheme->getMaxBpm(), pScheme->getMinBpm() );
+            if ( BPM != 0 ) {
+                BPM = BpmDetect::correctBPM(BPM, pScheme->getMinBpm(), pScheme->getMaxBpm());
                 pTrackInfoObject->setBpm(BPM);
                 pTrackInfoObject->setBpmConfirm();
                 if(pBpmReceiver){
                     pBpmReceiver->setComplete(pTrackInfoObject, false, BPM);
                 }
                 qDebug() << "BPM detection successful for" << pTrackInfoObject->getFilename();
+                qDebug() << "BPM" << BPM;
                 delete pSoundSource;
                 continue;
             }
             else
-            {            
+            {
                 qDebug() << "BPM detection failed, setting to 0.";
-                
+
 #ifdef __C_METRICS__
 		        cm_writemsg_ascii(1, "BPM detection failed, setting to 0.");
 #endif
Index: src/dlgprefbpm.h
===================================================================
--- src/dlgprefbpm.h	(revision 1979)
+++ src/dlgprefbpm.h	(working copy)
@@ -32,6 +32,7 @@
     void slotSetBpmEnabled(int);
     void slotSetBpmRangeStart(int);
     void slotSetBpmRangeEnd(int);
+    void slotSetAboveRange(int);
    
     void slotEditBpmScheme();
     void slotAddBpmScheme();
Index: src/trackinfoobject.h
===================================================================
--- src/trackinfoobject.h	(revision 1979)
+++ src/trackinfoobject.h	(working copy)
@@ -87,6 +87,8 @@
     bool getBpmConfirm() const;
     /** Set BPM confidence */
     void setBpmConfirm(bool confirm=true);
+    bool getHeaderParsed() const;
+    void setHeaderParsed(bool parsed = true);
     /** Returns the user comment */
     QString getComment() const;
     /** Sets the user commnet */
@@ -210,6 +212,8 @@
     float m_fMaxBpm;
     /** True if BPM is confirmed */
     bool m_bBpmConfirm;
+    /** True if header was parsed */
+    bool m_bHeaderParsed;
     /** Position of first beat in song */
     float m_fBeatFirst;
     /** Score. Reflects the relative number of times the track has been played */
@@ -239,7 +243,7 @@
     ControlObject *m_pControlObjectBpm;
     /** Pointer to ControlObject of duration value (only set when the track is loaded in a player) */
     ControlObject *m_pControlObjectDuration;
-	int iTemp;
+    int iTemp;
 
     /** Bpm Detection Queue */
     BpmDetector *m_BpmDetector;
Index: src/soundsource.h
===================================================================
--- src/soundsource.h	(revision 1979)
+++ src/soundsource.h	(working copy)
@@ -39,6 +39,7 @@
     virtual long seek(long) = 0;
     virtual unsigned read(unsigned long size, const SAMPLE*) = 0;
     virtual long unsigned length() = 0;
+    static float str2bpm( QString sBpm );
     static int ParseHeader(TrackInfoObject *);
     virtual int getSrate();
     /** Return a list of cue points stored in the file */
Index: src/dlgprefbpmdlg.ui
===================================================================
--- src/dlgprefbpmdlg.ui	(revision 1979)
+++ src/dlgprefbpmdlg.ui	(working copy)
@@ -6,7 +6,7 @@
     <x>0</x>
     <y>0</y>
     <width>427</width>
-    <height>411</height>
+    <height>395</height>
    </rect>
   </property>
   <property name="windowTitle" >
@@ -68,6 +68,16 @@
         </property>
        </widget>
       </item>
+      <item row="4" column="0" >
+       <widget class="QCheckBox" name="chkAboveRange" >
+        <property name="toolTip" >
+         <string>If BPM can be detected but not within specified range</string>
+        </property>
+        <property name="text" >
+         <string>Allow BPM above the range</string>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
@@ -140,19 +150,6 @@
      </layout>
     </widget>
    </item>
-   <item row="2" column="0" >
-    <spacer>
-     <property name="orientation" >
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" >
-      <size>
-       <width>20</width>
-       <height>20</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
   </layout>
  </widget>
  <layoutdefault spacing="6" margin="11" />
Index: src/bpmdetect.cpp
===================================================================
--- src/bpmdetect.cpp	(revision 1979)
+++ src/bpmdetect.cpp	(working copy)
@@ -95,20 +95,17 @@
 /// Normalization coefficient for calculating RMS sliding average approximation.
 const float avgnorm = (1 - avgdecay);
 
-float Correct_BPM( float BPM, int max, int min) {
-    if ( BPM == 0. )
-        return BPM;
+float BpmDetect::correctBPM( float BPM, int min, int max) {
+    if ( BPM == 0 ) return BPM;
 
-    while ( BPM > max )
-        BPM /= 2;
-    while ( BPM < min )
-        BPM *= 2;
+    if( BPM*2 < max ) BPM *= 2;
+    while ( BPM > max ) BPM /= 2;
+    while ( BPM < min ) BPM *= 2;
 
     return BPM;
 }
 
-
-BpmDetect::BpmDetect(int numChannels, int sampleRate, int _maxBpm, int _minBpm)
+BpmDetect::BpmDetect(int numChannels, int sampleRate, int _minBpm, int _maxBpm)
 {
     xcorr = NULL;
 
Index: src/soundsourceproxy.cpp
===================================================================
--- src/soundsourceproxy.cpp	(revision 1979)
+++ src/soundsourceproxy.cpp	(working copy)
@@ -40,9 +40,9 @@
     m_pSoundSource = new SoundSourceFFmpeg(qFilename);
     return;
 #endif
-    if (qFilename.lower().endsWith(".mp3"))
+    if (qFilename.toLower().endsWith(".mp3"))
         m_pSoundSource = new SoundSourceMp3(qFilename);
-    else if (qFilename.lower().endsWith(".ogg"))
+    else if (qFilename.toLower().endsWith(".ogg"))
         m_pSoundSource = new SoundSourceOggVorbis(qFilename);
     else
 #ifdef __SNDFILE__
@@ -62,9 +62,9 @@
     return;
 #endif
 
-    if (qFilename.lower().endsWith(".mp3"))
+    if (qFilename.toLower().endsWith(".mp3"))
 	m_pSoundSource = new SoundSourceMp3(qFilename);
-    else if (qFilename.lower().endsWith(".ogg"))
+    else if (qFilename.toLower().endsWith(".ogg"))
 	m_pSoundSource = new SoundSourceOggVorbis(qFilename);
     else
     {
@@ -76,7 +76,8 @@
 #endif
     }
 
-    pTrack->setDuration(length()/(2*getSrate()));
+    if(getSrate()) pTrack->setDuration(length()/(2*getSrate()));
+    else pTrack->setDuration(0);
 }
 
 SoundSourceProxy::~SoundSourceProxy()
@@ -103,14 +104,14 @@
 {
     QString qFilename = p->getFilename();
 #ifdef __FFMPEGFILE__
-    return SoundSourceFFmpeg::ParseHeader(p);;
+    return SoundSourceFFmpeg::ParseHeader(p);
 #endif
-    if (qFilename.lower().endsWith(".mp3"))
+    if (qFilename.toLower().endsWith(".mp3"))
 	return SoundSourceMp3::ParseHeader(p);
-    else if (qFilename.lower().endsWith(".ogg"))
+    else if (qFilename.toLower().endsWith(".ogg"))
 	return SoundSourceOggVorbis::ParseHeader(p);
-    else if (qFilename.lower().endsWith(".wav") || qFilename.lower().endsWith(".aif") ||
-	     qFilename.lower().endsWith(".aiff") || qFilename.lower().endsWith(".flac"))
+    else if (qFilename.toLower().endsWith(".wav") || qFilename.toLower().endsWith(".aif") ||
+	     qFilename.toLower().endsWith(".aiff") || qFilename.toLower().endsWith(".flac"))
 #ifdef __SNDFILE__
 	return SoundSourceSndFile::ParseHeader(p);
 #endif
Index: src/track.cpp
===================================================================
--- src/track.cpp	(revision 1979)
+++ src/track.cpp	(working copy)
@@ -48,6 +48,7 @@
 #include "woverview.h"
 #include "playerinfo.h"
 #include "defs_promo.h"
+#include "soundsourceproxy.h"
 
 #include <q3progressdialog.h>
 
@@ -859,6 +860,7 @@
 {
 
     QString filename = pTrackInfoObject->getLocation();
+    qDebug() << "Load to player1:" << filename;
     if (!filename.isEmpty())
     {
         // Check if filename is valid
@@ -890,6 +892,9 @@
     // Request a new track from the reader:
     m_pBuffer1->getReader()->requestNewTrack(m_pTrackPlayer1, bStartFromEndPos);
 
+    // Read the tags if required
+    if(!m_pTrackPlayer1->getHeaderParsed())
+        SoundSourceProxy::ParseHeader(m_pTrackPlayer1);
     // Detect BPM if required
     if (m_pTrackPlayer1->getBpmConfirm()== false || m_pTrackPlayer1->getBpm() == 0.)
         m_pTrackPlayer1->sendToBpmQueue();
@@ -928,6 +933,7 @@
 void Track::slotLoadPlayer2(TrackInfoObject * pTrackInfoObject, bool bStartFromEndPos)
 {
     QString filename = pTrackInfoObject->getLocation();
+    qDebug() << "Load to player2:" << filename;
     if (!filename.isEmpty())
     {
         // Check if filename is valid
@@ -959,6 +965,9 @@
     // Request a new track from the reader:
     m_pBuffer2->getReader()->requestNewTrack(m_pTrackPlayer2, bStartFromEndPos);
 
+    // Read the tags if required
+    if(!m_pTrackPlayer2->getHeaderParsed())
+        SoundSourceProxy::ParseHeader(m_pTrackPlayer2);
     // Detect BPM if required
     if (m_pTrackPlayer2->getBpmConfirm()== false || m_pTrackPlayer2->getBpm() == 0.)
         m_pTrackPlayer2->sendToBpmQueue();
Index: src/mixxx.cpp
===================================================================
--- src/mixxx.cpp	(revision 1979)
+++ src/mixxx.cpp	(working copy)
@@ -821,6 +821,7 @@
 //Note: Can't #ifdef this because MOC doesn't catch it.
 void MixxxApp::slotOptionsVinylControl(bool toggle)
 {
+#ifdef __VINYLCONTROL__
     //qDebug() << "slotOptionsVinylControl: toggle is " << (int)toggle;
 
     QString device1 = config->getValueString(ConfigKey("[VinylControl]","DeviceInputDeck1"));
@@ -842,6 +843,7 @@
         config->set(ConfigKey("[VinylControl]","Enabled"), ConfigValue((int)toggle));
         ControlObject::getControl(ConfigKey("[VinylControl]", "Enabled"))->set((int)toggle);
     }
+#endif
 }
 
 //Also can't ifdef this (MOC again)
Index: src/trackinfoobject.cpp
===================================================================
--- src/trackinfoobject.cpp	(revision 1979)
+++ src/trackinfoobject.cpp	(working copy)
@@ -54,6 +54,7 @@
     m_iTimesPlayed = 0;
     m_fBpm = 0.;
     m_bBpmConfirm = false;
+    m_bHeaderParsed = false;
     m_fBeatFirst = -1.;
     m_iScore = 0;
     m_iId = -1;
@@ -113,6 +114,7 @@
     m_fBpm = XmlParse::selectNodeQString(nodeHeader, "Bpm").toFloat();
     m_bBpmConfirm = XmlParse::selectNodeQString(nodeHeader, "BpmConfirm").toInt();
     m_fBeatFirst = XmlParse::selectNodeQString(nodeHeader, "BeatFirst").toFloat();
+    m_bHeaderParsed = false;
     m_iScore = 0;
     m_iId = XmlParse::selectNodeQString(nodeHeader, "Id").toInt();
 
@@ -517,6 +519,22 @@
     m_qMutex.unlock();
 }
 
+bool TrackInfoObject::getHeaderParsed()  const
+{
+    m_qMutex.lock();
+    bool bParsed = m_bHeaderParsed;
+    m_qMutex.unlock();
+
+    return bParsed;
+}
+
+void TrackInfoObject::setHeaderParsed(bool parsed)
+{
+    m_qMutex.lock();
+    m_bHeaderParsed = parsed;
+    m_qMutex.unlock();
+}
+
 QString TrackInfoObject::getInfo()  const
 {
     m_qMutex.lock();
Index: src/bpmdetect.h
===================================================================
--- src/bpmdetect.h	(revision 1979)
+++ src/bpmdetect.h	(working copy)
@@ -94,14 +94,6 @@
 /// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
 #define MAX_BPM 170
 
-/**
- * @brief Correct BPM
- * if value is lower than MINIMUM_BPM or higher than MAXIMUM_BPM
- * @param BPM BPM to correct
- * @return corrected BPM
- */
-float Correct_BPM( float BPM, int max, int min );
-
 /// Class for calculating BPM rate for audio data.
 class BpmDetect
 {
@@ -171,15 +163,22 @@
 
 public:
     /// Constructor.
-    BpmDetect(int numChannels,  ///< Number of channels in sample data.
-              int sampleRate,   ///< Sample rate in Hz.
-              int _maxBpm,
-			  int _minBpm
-			  );
+    /// @note _maxBpm should be at least 2 * _minBpm, otherwise BPM won't always be detected
+    BpmDetect(int numChannels,          ///< Number of channels in sample data.
+              int sampleRate,           ///< Sample rate in Hz.
+              int _minBpm = MIN_BPM,    ///< Minimum acceptable BPM
+              int _maxBpm = MAX_BPM     ///< Maximum acceptable BPM
+    );
 
     /// Destructor.
     virtual ~BpmDetect();
 
+    /**
+     * Multiplying or dividing BPM by 2 if value is lower than min or greater than max
+     * @return corrected BPM (can be greater than max)
+     */
+    static float correctBPM( float BPM, int min, int max );
+
     /// Inputs a block of samples for analyzing: Envelopes the samples and then
     /// updates the autocorrelation estimation. When whole song data has been input
     /// in smaller blocks using this function, read the resulting bpm with 'getBpm' 
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel

Reply via email to