From 93ef4ffe8737b707718295530c9bf333b7f785e9 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 6 Jul 2021 23:06:51 +0200 Subject: [PATCH 1/2] Bpm: Add method to to divide by another Bpm --- src/track/bpm.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/track/bpm.h b/src/track/bpm.h index e5986a09718..93800ce2b2e 100644 --- a/src/track/bpm.h +++ b/src/track/bpm.h @@ -152,6 +152,11 @@ inline Bpm operator/(Bpm bpm, double divisor) { return Bpm(bpm.value() / divisor); } +/// Bpm can be divided by another Bpm to get a ratio (represented as a double). +inline double operator/(Bpm bpm, Bpm otherBpm) { + return bpm.value() / otherBpm.value(); +} + inline bool operator==(Bpm bpm1, Bpm bpm2) { if (!bpm1.isValid() && !bpm2.isValid()) { return true; From 9dc9d2655d5993c2b6be1ec7d0358f5b96f00950 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 6 Jul 2021 21:33:16 +0200 Subject: [PATCH 2/2] EngineBuffer: Return Bpm type from getBpm/getLocalBpm methods This also fixes a potential division by zero, in case `thisLocalBpm` is invalid. --- src/engine/controls/bpmcontrol.cpp | 26 +++++++++++++------------- src/engine/controls/bpmcontrol.h | 7 +++++-- src/engine/enginebuffer.cpp | 4 ++-- src/engine/enginebuffer.h | 9 +++++---- src/engine/sync/enginesync.cpp | 2 +- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 35f1d501bce..9c18ae109a5 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -162,8 +162,8 @@ BpmControl::~BpmControl() { delete m_pAdjustBeatsSlower; } -double BpmControl::getBpm() const { - return m_pEngineBpm->get(); +mixxx::Bpm BpmControl::getBpm() const { + return mixxx::Bpm(m_pEngineBpm->get()); } void BpmControl::adjustBeatsBpm(double deltaBpm) { @@ -311,14 +311,14 @@ bool BpmControl::syncTempo() { return false; } - double fThisBpm = m_pEngineBpm->get(); - double fThisLocalBpm = m_pLocalBpm->get(); + const auto thisBpm = getBpm(); + const auto thisLocalBpm = getLocalBpm(); - double fOtherBpm = pOtherEngineBuffer->getBpm(); - double fOtherLocalBpm = pOtherEngineBuffer->getLocalBpm(); + const auto otherBpm = pOtherEngineBuffer->getBpm(); + const auto otherLocalBpm = pOtherEngineBuffer->getLocalBpm(); - //qDebug() << "this" << "bpm" << fThisBpm << "filebpm" << fThisLocalBpm; - //qDebug() << "other" << "bpm" << fOtherBpm << "filebpm" << fOtherLocalBpm; + //qDebug() << "this" << "bpm" << thisBpm << "filebpm" << thisLocalBpm; + //qDebug() << "other" << "bpm" << otherBpm << "filebpm" << otherLocalBpm; //////////////////////////////////////////////////////////////////////////// // Rough proof of how syncing works -- rryan 3/2011 @@ -346,21 +346,21 @@ bool BpmControl::syncTempo() { // // thisRateScale = ((otherFileBpm * (1.0 + otherRate)) / thisFileBpm - 1.0) / (thisRateDir * thisRateRange) - if (fOtherBpm > 0.0 && fThisBpm > 0.0) { + if (otherBpm.isValid() && thisBpm.isValid() && thisLocalBpm.isValid()) { // The desired rate is the other decks effective rate divided by this // deck's file BPM. This gives us the playback rate that will produce an // effective BPM equivalent to the other decks. - double desiredRate = fOtherBpm / fThisLocalBpm; + double desiredRate = otherBpm / thisLocalBpm; // Test if this buffer's bpm is the double of the other one, and adjust // the rate scale. I believe this is intended to account for our BPM // algorithm sometimes finding double or half BPMs. This avoids drastic // scales. - double fFileBpmDelta = fabs(fThisLocalBpm - fOtherLocalBpm); - if (fabs(fThisLocalBpm * 2.0 - fOtherLocalBpm) < fFileBpmDelta) { + const double fileBpmDelta = fabs(thisLocalBpm - otherLocalBpm); + if (fabs(thisLocalBpm * 2.0 - otherLocalBpm) < fileBpmDelta) { desiredRate /= 2.0; - } else if (fabs(fThisLocalBpm - 2.0 * fOtherLocalBpm) < fFileBpmDelta) { + } else if (fabs(thisLocalBpm - otherLocalBpm * 2.0) < fileBpmDelta) { desiredRate *= 2.0; } diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index 699d642b74d..d178683e0bd 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -25,8 +25,11 @@ class BpmControl : public EngineControl { BpmControl(const QString& group, UserSettingsPointer pConfig); ~BpmControl() override; - double getBpm() const; - double getLocalBpm() const { return m_pLocalBpm ? m_pLocalBpm->get() : 0.0; } + mixxx::Bpm getBpm() const; + mixxx::Bpm getLocalBpm() const { + return m_pLocalBpm ? mixxx::Bpm(m_pLocalBpm->get()) : mixxx::Bpm(); + } + // When in master sync mode, ratecontrol calls calcSyncedRate to figure out // how fast the track should play back. The returned rate is usually just // the correct pitch to match bpms. The usertweak argument represents diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 6a429d59ace..6bbd5b2c08d 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -363,11 +363,11 @@ void EngineBuffer::enableIndependentPitchTempoScaling(bool bEnable, } } -double EngineBuffer::getBpm() const { +mixxx::Bpm EngineBuffer::getBpm() const { return m_pBpmControl->getBpm(); } -double EngineBuffer::getLocalBpm() const { +mixxx::Bpm EngineBuffer::getLocalBpm() const { return m_pBpmControl->getLocalBpm(); } diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index bc2695a3d6f..a043d3ef104 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -11,6 +11,7 @@ #include "engine/engineobject.h" #include "engine/sync/syncable.h" #include "preferences/usersettings.h" +#include "track/bpm.h" #include "track/track_decl.h" #include "util/rotary.h" #include "util/types.h" @@ -97,10 +98,10 @@ class EngineBuffer : public EngineObject { double getSpeed() const; bool getScratching() const; bool isReverse() const; - // Returns current bpm value (not thread-safe) - double getBpm() const; - // Returns the BPM of the loaded track around the current position (not thread-safe) - double getLocalBpm() const; + /// Returns current bpm value (not thread-safe) + mixxx::Bpm getBpm() const; + /// Returns the BPM of the loaded track around the current position (not thread-safe) + mixxx::Bpm getLocalBpm() const; /// Sets a beatloop for the loaded track (not thread safe) void setBeatLoop(double startPosition, bool enabled); /// Sets a loop for the loaded track (not thread safe) diff --git a/src/engine/sync/enginesync.cpp b/src/engine/sync/enginesync.cpp index 7be0f0fe283..3b7c83eb2cc 100644 --- a/src/engine/sync/enginesync.cpp +++ b/src/engine/sync/enginesync.cpp @@ -471,7 +471,7 @@ Syncable* EngineSync::pickNonSyncSyncTarget(EngineChannel* pDontPick) const { // mix, and are primary decks. if (pChannel->isActive() && pChannel->isMasterEnabled() && pChannel->isPrimaryDeck()) { EngineBuffer* pBuffer = pChannel->getEngineBuffer(); - if (pBuffer && pBuffer->getBpm() > 0) { + if (pBuffer && pBuffer->getBpm().isValid()) { if (pBuffer->getSpeed() != 0.0) { if (pSyncable->getSyncMode() != SYNC_NONE) { // Second choice: first playing sync deck