Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/track/beatgrid.cpp

Go to the documentation of this file.
00001 #include <QMutexLocker>
00002 #include <QDebug>
00003 
00004 #include "track/beatgrid.h"
00005 #include "mathstuff.h"
00006 
00007 static int kFrameSize = 2;
00008 
00009 struct BeatGridData {
00010         double bpm;
00011         double firstBeat;
00012 };
00013 
00014 BeatGrid::BeatGrid(TrackPointer pTrack, const QByteArray* pByteArray)
00015         : QObject(),
00016           m_mutex(QMutex::Recursive),
00017           m_iSampleRate(pTrack->getSampleRate()),
00018           m_dBpm(0.0),
00019           m_dFirstBeat(0.0f),
00020           m_dBeatLength(0.0f) {
00021     connect(pTrack.data(), SIGNAL(bpmUpdated(double)),
00022             this, SLOT(slotTrackBpmUpdated(double)),
00023             Qt::DirectConnection);
00024     slotTrackBpmUpdated(pTrack->getBpm());
00025 
00026     qDebug() << "New BeatGrid";
00027     if (pByteArray != NULL) {
00028         readByteArray(pByteArray);
00029     }
00030 }
00031 
00032 BeatGrid::~BeatGrid() {
00033 
00034 }
00035 
00036 void BeatGrid::setGrid(double dBpm, double dFirstBeatSample) {
00037     QMutexLocker lock(&m_mutex);
00038     m_dBpm = dBpm;
00039     m_dFirstBeat = dFirstBeatSample;
00040     // Calculate beat length as sample offsets
00041     m_dBeatLength = (60.0 * m_iSampleRate / m_dBpm) * kFrameSize;
00042 }
00043 
00044 QByteArray* BeatGrid::toByteArray() const {
00045     QMutexLocker locker(&m_mutex);
00046     BeatGridData blob = { m_dBpm, (m_dFirstBeat / kFrameSize) };
00047     QByteArray* pByteArray = new QByteArray((char *)&blob, sizeof(blob));
00048     // Caller is responsible for delete
00049     return pByteArray;
00050 }
00051 
00052 void BeatGrid::readByteArray(const QByteArray* pByteArray) {
00053     if ( pByteArray->size() != sizeof(BeatGridData))
00054         return;
00055     BeatGridData *blob = (BeatGridData *)pByteArray->data();
00056     // We serialize into frame offsets but use sample offsets at runtime
00057     setGrid(blob->bpm, blob->firstBeat * kFrameSize);
00058 }
00059 
00060 QString BeatGrid::getVersion() const {
00061     QMutexLocker locker(&m_mutex);
00062     return "BeatGrid-1.0";
00063 }
00064 
00065 // internal use only
00066 bool BeatGrid::isValid() const {
00067     return m_iSampleRate > 0 && m_dBpm > 0;
00068 }
00069 
00070 // This could be implemented in the Beats Class itself.
00071 // If necessary, the child class can redefine it.
00072 double BeatGrid::findNextBeat(double dSamples) const {
00073     return findNthBeat(dSamples, +1);
00074 }
00075 
00076 // This could be implemented in the Beats Class itself.
00077 // If necessary, the child class can redefine it.
00078 double BeatGrid::findPrevBeat(double dSamples) const {
00079     return findNthBeat(dSamples, -1);
00080 }
00081 
00082 // This is an internal call. This could be implemented in the Beats Class itself.
00083 double BeatGrid::findClosestBeat(double dSamples) const {
00084     QMutexLocker locker(&m_mutex);
00085     if (!isValid()) {
00086         return -1;
00087     }
00088     double nextBeat = findNextBeat(dSamples);
00089     double prevBeat = findPrevBeat(dSamples);
00090     return (nextBeat - dSamples > dSamples - prevBeat) ? prevBeat : nextBeat;
00091 }
00092 
00093 double BeatGrid::findNthBeat(double dSamples, int n) const {
00094     QMutexLocker locker(&m_mutex);
00095     if (!isValid() || n == 0) {
00096         return -1;
00097     }
00098 
00099     double beatFraction = (dSamples - m_dFirstBeat) / m_dBeatLength;
00100     double prevBeat = floorf(beatFraction);
00101     double nextBeat = ceilf(beatFraction);
00102 
00103     // If the position is within 1/100th of the next or previous beat, treat it
00104     // as if it is that beat.
00105     const double kEpsilon = .01;
00106 
00107     if (fabs(nextBeat - beatFraction) < kEpsilon) {
00108         beatFraction = nextBeat;
00109     } else if (fabs(prevBeat - beatFraction) < kEpsilon) {
00110         beatFraction = prevBeat;
00111     }
00112 
00113     double dClosestBeat;
00114     if (n > 0) {
00115         // We're going forward, so use ceilf to round up to the next multiple of
00116         // m_dBeatLength
00117         dClosestBeat = ceilf(beatFraction) * m_dBeatLength + m_dFirstBeat;
00118         n = n - 1;
00119     } else {
00120         // We're going backward, so use floorf to round down to the next multiple
00121         // of m_dBeatLength
00122         dClosestBeat = floorf(beatFraction) * m_dBeatLength + m_dFirstBeat;
00123         n = n + 1;
00124     }
00125 
00126     double dResult = dClosestBeat + n * m_dBeatLength;
00127     if (!even(dResult)) {
00128         dResult--;
00129     }
00130     return dResult;
00131 }
00132 
00133 void BeatGrid::findBeats(double startSample, double stopSample, QList<double>* pBeatsList) const {
00134     QMutexLocker locker(&m_mutex);
00135     if (!isValid() || startSample > stopSample) {
00136         return;
00137     }
00138     double curBeat = findNextBeat(startSample);
00139     while (curBeat <= stopSample) {
00140         pBeatsList->append(curBeat);
00141         curBeat += m_dBeatLength;
00142     }
00143 }
00144 
00145 bool BeatGrid::hasBeatInRange(double startSample, double stopSample) const {
00146     QMutexLocker locker(&m_mutex);
00147     if (!isValid() || startSample > stopSample) {
00148         return false;
00149     }
00150     double curBeat = findNextBeat(startSample);
00151     if (curBeat <= stopSample) {
00152         return true;
00153     }
00154     return false;
00155 }
00156 
00157 double BeatGrid::getBpm() const {
00158     QMutexLocker locker(&m_mutex);
00159     if (!isValid()) {
00160         return 0;
00161     }
00162     return m_dBpm;
00163 }
00164 
00165 double BeatGrid::getBpmRange(double startSample, double stopSample) const {
00166     QMutexLocker locker(&m_mutex);
00167     if (!isValid() || startSample > stopSample) {
00168         return -1;
00169     }
00170     return m_dBpm;
00171 }
00172 
00173 void BeatGrid::addBeat(double dBeatSample) {
00174     //QMutexLocker locker(&m_mutex);
00175     return;
00176 }
00177 
00178 void BeatGrid::removeBeat(double dBeatSample) {
00179     //QMutexLocker locker(&m_mutex);
00180     return;
00181 }
00182 
00183 void BeatGrid::moveBeat(double dBeatSample, double dNewBeatSample) {
00184     //QMutexLocker locker(&m_mutex);
00185     return;
00186 }
00187 
00188 void BeatGrid::translate(double dNumSamples) {
00189     QMutexLocker locker(&m_mutex);
00190     if (!isValid()) {
00191         return;
00192     }
00193     m_dFirstBeat += dNumSamples;
00194     locker.unlock();
00195     emit(updated());
00196 }
00197 
00198 void BeatGrid::scale(double dScalePercentage) {
00199     QMutexLocker locker(&m_mutex);
00200     if (!isValid()) {
00201         return;
00202     }
00203     m_dBpm *= dScalePercentage;
00204     locker.unlock();
00205     emit(updated());
00206 }
00207 
00208 void BeatGrid::slotTrackBpmUpdated(double dBpm) {
00209     QMutexLocker locker(&m_mutex);
00210     m_dBpm = dBpm;
00211     m_dBeatLength = (60.0 * m_iSampleRate / m_dBpm) * kFrameSize;
00212 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines