diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 92a53954d3b..67f49c758ac 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -10,6 +10,7 @@ #include "engine/enginebuffer.h" #include "engine/enginemaster.h" #include "moc_bpmcontrol.cpp" +#include "track/beatutils.h" #include "track/track.h" #include "util/assert.h" #include "util/duration.h" @@ -28,12 +29,13 @@ constexpr double kBpmRangeSmallStep = 0.1; constexpr double kBpmAdjustMin = kBpmRangeMin; constexpr double kBpmAdjustStep = 0.01; +constexpr double kBpmTabRounding = 1 / 12.0; // Maximum allowed interval between beats (calculated from kBpmTapMin). constexpr double kBpmTapMin = 30.0; const mixxx::Duration kBpmTapMaxInterval = mixxx::Duration::fromMillis( static_cast(1000.0 * (60.0 / kBpmTapMin))); -constexpr int kBpmTapFilterLength = 5; +constexpr int kBpmTapFilterLength = 80; // The local_bpm is calculated forward and backward this number of beats, so // the actual number of beats is this x2. @@ -164,10 +166,7 @@ double BpmControl::getBpm() const { return m_pEngineBpm->get(); } -void BpmControl::slotAdjustBeatsFaster(double v) { - if (v <= 0) { - return; - } +void BpmControl::adjustBeatsBpm(double deltaBpm) { const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack(); if (!pTrack) { return; @@ -175,25 +174,25 @@ void BpmControl::slotAdjustBeatsFaster(double v) { const mixxx::BeatsPointer pBeats = pTrack->getBeats(); if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) { double bpm = pBeats->getBpm(); - double adjustedBpm = bpm + kBpmAdjustStep; + double centerBpm = math_max(kBpmAdjustMin, bpm + deltaBpm); + double adjustedBpm = BeatUtils::roundBpmWithinRange( + centerBpm - kBpmAdjustStep / 2, centerBpm, centerBpm + kBpmAdjustStep / 2); pTrack->trySetBeats(pBeats->setBpm(adjustedBpm)); } } -void BpmControl::slotAdjustBeatsSlower(double v) { +void BpmControl::slotAdjustBeatsFaster(double v) { if (v <= 0) { return; } - const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack(); - if (!pTrack) { + adjustBeatsBpm(kBpmAdjustStep); +} + +void BpmControl::slotAdjustBeatsSlower(double v) { + if (v <= 0) { return; } - const mixxx::BeatsPointer pBeats = pTrack->getBeats(); - if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) { - double bpm = pBeats->getBpm(); - double adjustedBpm = math_max(kBpmAdjustMin, bpm - kBpmAdjustStep); - pTrack->trySetBeats(pBeats->setBpm(adjustedBpm)); - } + adjustBeatsBpm(-kBpmAdjustStep); } void BpmControl::slotTranslateBeatsEarlier(double v) { @@ -259,6 +258,9 @@ void BpmControl::slotTapFilter(double averageLength, int numSamples) { // (60 seconds per minute) * (1000 milliseconds per second) / (X millis per // beat) = Y beats/minute double averageBpm = 60.0 * 1000.0 / averageLength / rateRatio; + averageBpm = BeatUtils::roundBpmWithinRange(averageBpm - kBpmTabRounding, + averageBpm, + averageBpm + kBpmTabRounding); pTrack->trySetBeats(pBeats->setBpm(averageBpm)); } diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index 62b2fe83673..738990b71f9 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -107,6 +107,7 @@ class BpmControl : public EngineControl { } bool syncTempo(); double calcSyncAdjustment(bool userTweakingSync); + void adjustBeatsBpm(double deltaBpm); friend class SyncControl; diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index f73d915859e..bd6c01975b2 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -12,6 +12,7 @@ #include "preferences/colorpalettesettings.h" #include "sources/soundsourceproxy.h" #include "track/beatfactory.h" +#include "track/beatutils.h" #include "track/keyfactory.h" #include "track/keyutils.h" #include "track/track.h" @@ -24,14 +25,16 @@ #include "widget/wstarrating.h" namespace { + +constexpr double kBpmTabRounding = 1 / 12.0; constexpr int kFilterLength = 80; constexpr int kMinBpm = 30; -} // namespace - // Maximum allowed interval between beats (calculated from kMinBpm). const mixxx::Duration kMaxInterval = mixxx::Duration::fromMillis( static_cast(1000.0 * (60.0 / kMinBpm))); +} // namespace + DlgTrackInfo::DlgTrackInfo( const TrackModel* trackModel) // No parent because otherwise it inherits the style parent's @@ -545,7 +548,9 @@ void DlgTrackInfo::slotBpmTap(double averageLength, int numSamples) { return; } double averageBpm = 60.0 * 1000.0 / averageLength; - // average bpm needs to be truncated for this comparison: + averageBpm = BeatUtils::roundBpmWithinRange(averageBpm - kBpmTabRounding, + averageBpm, + averageBpm + kBpmTabRounding); if (averageBpm != m_dLastTapedBpm) { m_dLastTapedBpm = averageBpm; spinBpm->setValue(averageBpm); diff --git a/src/track/beatgrid.cpp b/src/track/beatgrid.cpp index 61b4887b8e7..5ef701eb46c 100644 --- a/src/track/beatgrid.cpp +++ b/src/track/beatgrid.cpp @@ -3,16 +3,22 @@ #include #include +#include "track/beatutils.h" #include "track/track.h" #include "util/math.h" -static const int kFrameSize = 2; +namespace { struct BeatGridData { double bpm; double firstBeat; }; +constexpr int kFrameSize = 2; +constexpr double kBpmScaleRounding = 0.001; + +} // namespace + namespace mixxx { class BeatGridIterator : public BeatIterator { @@ -326,8 +332,9 @@ BeatsPointer BeatGrid::scale(enum BPMScale scale) const { if (bpm > getMaxBpm()) { return BeatsPointer(new BeatGrid(*this)); } - grid.mutable_bpm()->set_bpm(bpm); + bpm = BeatUtils::roundBpmWithinRange(bpm - kBpmScaleRounding, bpm, bpm + kBpmScaleRounding); + grid.mutable_bpm()->set_bpm(bpm); double beatLength = (60.0 * m_sampleRate / bpm) * kFrameSize; return BeatsPointer(new BeatGrid(*this, grid, beatLength)); } diff --git a/src/track/beatutils.h b/src/track/beatutils.h index 2d875966e28..5a4df420e1d 100644 --- a/src/track/beatutils.h +++ b/src/track/beatutils.h @@ -37,6 +37,5 @@ class BeatUtils { static QVector getBeats(const QVector& constantRegions); - private: static double roundBpmWithinRange(double minBpm, double centerBpm, double maxBpm); };