Skip to content

Commit

Permalink
Beats: Add mixxx::Bpm in BeatUtils and BeatGrid/BeatMap classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Holzhaus committed Jul 1, 2021
1 parent 83ea374 commit 77d726b
Show file tree
Hide file tree
Showing 21 changed files with 204 additions and 192 deletions.
2 changes: 1 addition & 1 deletion src/analyzer/analyzerbeats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ void AnalyzerBeats::storeResults(TrackPointer pTrack) {
qDebug() << "AnalyzerBeats plugin detected" << beats.size()
<< "beats. Average BPM:" << (pBeats ? pBeats->getBpm() : 0.0);
} else {
float bpm = m_pPlugin->getBpm();
mixxx::Bpm bpm = m_pPlugin->getBpm();
qDebug() << "AnalyzerBeats plugin detected constant BPM: " << bpm;
pBeats = BeatFactory::makeBeatGrid(m_sampleRate, bpm, mixxx::audio::kStartFramePos);
}
Expand Down
5 changes: 3 additions & 2 deletions src/analyzer/plugins/analyzerplugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "audio/frame.h"
#include "track/beats.h"
#include "track/bpm.h"
#include "track/keys.h"
#include "util/types.h"

Expand Down Expand Up @@ -69,8 +70,8 @@ class AnalyzerBeatsPlugin : public AnalyzerPlugin {
~AnalyzerBeatsPlugin() override = default;

virtual bool supportsBeatTracking() const = 0;
virtual float getBpm() const {
return 0.0f;
virtual mixxx::Bpm getBpm() const {
return mixxx::Bpm();
}
virtual QVector<mixxx::audio::FramePos> getBeats() const {
return {};
Expand Down
7 changes: 3 additions & 4 deletions src/analyzer/plugins/analyzersoundtouchbeats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
namespace mixxx {

AnalyzerSoundTouchBeats::AnalyzerSoundTouchBeats()
: m_downmixBuffer(kAnalysisFramesPerChunk), // mono, i.e. 1 sample per frame
m_fResultBpm(0.0f) {
: m_downmixBuffer(kAnalysisFramesPerChunk) {
}

AnalyzerSoundTouchBeats::~AnalyzerSoundTouchBeats() {
}

bool AnalyzerSoundTouchBeats::initialize(int samplerate) {
m_fResultBpm = 0.0f;
m_resultBpm = mixxx::Bpm();
m_pSoundTouch = std::make_unique<soundtouch::BPMDetect>(2, samplerate);
return true;
}
Expand All @@ -42,7 +41,7 @@ bool AnalyzerSoundTouchBeats::finalize() {
if (!m_pSoundTouch) {
return false;
}
m_fResultBpm = m_pSoundTouch->getBpm();
m_resultBpm = mixxx::Bpm(m_pSoundTouch->getBpm());
m_pSoundTouch.reset();
return true;
}
Expand Down
7 changes: 4 additions & 3 deletions src/analyzer/plugins/analyzersoundtouchbeats.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ class AnalyzerSoundTouchBeats : public AnalyzerBeatsPlugin {
return false;
}

float getBpm() const override {
return m_fResultBpm;
mixxx::Bpm getBpm() const override {
return m_resultBpm;
}

private:
std::unique_ptr<soundtouch::BPMDetect> m_pSoundTouch;
/// mono, i.e. 1 sample per frame
SampleBuffer m_downmixBuffer;
float m_fResultBpm;
mixxx::Bpm m_resultBpm;
};

} // namespace mixxx
10 changes: 5 additions & 5 deletions src/engine/controls/bpmcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ void BpmControl::adjustBeatsBpm(double deltaBpm) {
const mixxx::BeatsPointer pBeats = pTrack->getBeats();
if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) {
double bpm = pBeats->getBpm();
double centerBpm = math_max(kBpmAdjustMin, bpm + deltaBpm);
double adjustedBpm = BeatUtils::roundBpmWithinRange(
const auto centerBpm = mixxx::Bpm(math_max(kBpmAdjustMin, bpm + deltaBpm));
mixxx::Bpm adjustedBpm = BeatUtils::roundBpmWithinRange(
centerBpm - kBpmAdjustStep / 2, centerBpm, centerBpm + kBpmAdjustStep / 2);
pTrack->trySetBeats(pBeats->setBpm(adjustedBpm));
pTrack->trySetBeats(pBeats->setBpm(adjustedBpm.getValue()));
}
}

Expand Down Expand Up @@ -257,11 +257,11 @@ 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;
auto averageBpm = mixxx::Bpm(60.0 * 1000.0 / averageLength / rateRatio);
averageBpm = BeatUtils::roundBpmWithinRange(averageBpm - kBpmTabRounding,
averageBpm,
averageBpm + kBpmTabRounding);
pTrack->trySetBeats(pBeats->setBpm(averageBpm));
pTrack->trySetBeats(pBeats->setBpm(averageBpm.getValue()));
}

void BpmControl::slotControlBeatSyncPhase(double value) {
Expand Down
2 changes: 1 addition & 1 deletion src/library/dao/trackdao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,7 @@ bool setTrackAudioProperties(

bool setTrackBeats(const QSqlRecord& record, const int column,
TrackPointer pTrack) {
double bpm = record.value(column).toDouble();
const auto bpm = mixxx::Bpm(record.value(column).toDouble());
QString beatsVersion = record.value(column + 1).toString();
QString beatsSubVersion = record.value(column + 2).toString();
QByteArray beatsBlob = record.value(column + 3).toByteArray();
Expand Down
20 changes: 10 additions & 10 deletions src/library/dlgtrackinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ DlgTrackInfo::DlgTrackInfo(
: QDialog(nullptr),
m_pTrackModel(trackModel),
m_tapFilter(this, kFilterLength, kMaxInterval),
m_dLastTapedBpm(-1.),
m_pWCoverArtLabel(make_parented<WCoverArtLabel>(this)),
m_pWStarRating(make_parented<WStarRating>(nullptr, this)) {
init();
Expand Down Expand Up @@ -583,7 +582,7 @@ void DlgTrackInfo::slotBpmConstChanged(int state) {
CuePosition cue = m_pLoadedTrack->getCuePoint();
m_pBeatsClone =
BeatFactory::makeBeatGrid(m_pLoadedTrack->getSampleRate(),
spinBpm->value(),
mixxx::Bpm(spinBpm->value()),
mixxx::audio::FramePos::fromEngineSamplePos(
cue.getPosition()));
} else {
Expand All @@ -602,18 +601,19 @@ void DlgTrackInfo::slotBpmTap(double averageLength, int numSamples) {
if (averageLength == 0) {
return;
}
double averageBpm = 60.0 * 1000.0 / averageLength;
auto averageBpm = mixxx::Bpm(60.0 * 1000.0 / averageLength);
averageBpm = BeatUtils::roundBpmWithinRange(averageBpm - kBpmTabRounding,
averageBpm,
averageBpm + kBpmTabRounding);
if (averageBpm != m_dLastTapedBpm) {
m_dLastTapedBpm = averageBpm;
spinBpm->setValue(averageBpm);
if (averageBpm != m_lastTapedBpm) {
m_lastTapedBpm = averageBpm;
spinBpm->setValue(averageBpm.getValue());
}
}

void DlgTrackInfo::slotSpinBpmValueChanged(double value) {
if (value <= 0) {
const auto bpm = mixxx::Bpm(value);
if (!bpm.hasValue()) {
m_pBeatsClone.clear();
return;
}
Expand All @@ -622,17 +622,17 @@ void DlgTrackInfo::slotSpinBpmValueChanged(double value) {
CuePosition cue = m_pLoadedTrack->getCuePoint();
m_pBeatsClone = BeatFactory::makeBeatGrid(
m_pLoadedTrack->getSampleRate(),
value,
bpm,
mixxx::audio::FramePos::fromEngineSamplePos(cue.getPosition()));
}

double oldValue = m_pBeatsClone->getBpm();
if (oldValue == value) {
if (oldValue == bpm.getValue()) {
return;
}

if (m_pBeatsClone->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM) {
m_pBeatsClone = m_pBeatsClone->setBpm(value);
m_pBeatsClone = m_pBeatsClone->setBpm(bpm.getValue());
}

// read back the actual value
Expand Down
2 changes: 1 addition & 1 deletion src/library/dlgtrackinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo {
bool m_trackHasBeatMap;

TapFilter m_tapFilter;
double m_dLastTapedBpm;
mixxx::Bpm m_lastTapedBpm;

parented_ptr<WCoverArtLabel> m_pWCoverArtLabel;
parented_ptr<WStarRating> m_pWStarRating;
Expand Down
24 changes: 12 additions & 12 deletions src/test/beatgridtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ TEST(BeatGridTest, Scale) {
int sampleRate = 44100;
TrackPointer pTrack = newTrack(sampleRate);

double bpm = 60.0;
const auto bpm = 60.0;
pTrack->trySetBpm(bpm);

auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(),
QString(),
bpm,
mixxx::Bpm(bpm),
mixxx::audio::kStartFramePos);

EXPECT_DOUBLE_EQ(bpm, pGrid->getBpm());
Expand Down Expand Up @@ -65,7 +65,7 @@ TEST(BeatGridTest, TestNthBeatWhenOnBeat) {

auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(),
QString(),
bpm,
mixxx::Bpm(bpm),
mixxx::audio::kStartFramePos);
// Pretend we're on the 20th beat;
double position = beatLength * 20;
Expand Down Expand Up @@ -107,7 +107,7 @@ TEST(BeatGridTest, TestNthBeatWhenOnBeat_BeforeEpsilon) {

auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(),
QString(),
bpm,
mixxx::Bpm(bpm),
mixxx::audio::kStartFramePos);

// Pretend we're just before the 20th beat.
Expand Down Expand Up @@ -151,7 +151,7 @@ TEST(BeatGridTest, TestNthBeatWhenOnBeat_AfterEpsilon) {

auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(),
QString(),
bpm,
mixxx::Bpm(bpm),
mixxx::audio::kStartFramePos);

// Pretend we're just before the 20th beat.
Expand Down Expand Up @@ -188,10 +188,10 @@ TEST(BeatGridTest, TestNthBeatWhenNotOnBeat) {
int sampleRate = 44100;
TrackPointer pTrack = newTrack(sampleRate);

double bpm = 60.1;
const auto bpm = mixxx::Bpm(60.1);
const int kFrameSize = 2;
pTrack->trySetBpm(bpm);
double beatLength = (60.0 * sampleRate / bpm) * kFrameSize;
pTrack->trySetBpm(bpm.getValue());
double beatLength = (60.0 * sampleRate / bpm.getValue()) * kFrameSize;

auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(),
QString(),
Expand Down Expand Up @@ -229,12 +229,12 @@ TEST(BeatGridTest, FromMetadata) {
int sampleRate = 44100;
TrackPointer pTrack = newTrack(sampleRate);

double bpm = 60.1;
ASSERT_TRUE(pTrack->trySetBpm(bpm));
EXPECT_DOUBLE_EQ(pTrack->getBpm(), bpm);
const auto bpm = mixxx::Bpm(60.1);
ASSERT_TRUE(pTrack->trySetBpm(bpm.getValue()));
EXPECT_DOUBLE_EQ(pTrack->getBpm(), bpm.getValue());

auto pBeats = pTrack->getBeats();
EXPECT_DOUBLE_EQ(pBeats->getBpm(), bpm);
EXPECT_DOUBLE_EQ(pBeats->getBpm(), bpm.getValue());

// Invalid bpm resets the bpm
ASSERT_TRUE(pTrack->trySetBpm(-60.1));
Expand Down
6 changes: 3 additions & 3 deletions src/test/beatstranslatetest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class BeatsTranslateTest : public MockedEngineBackendTest {

TEST_F(BeatsTranslateTest, SimpleTranslateMatch) {
// Set up BeatGrids for decks 1 and 2.
const double bpm = 60.0;
const auto bpm = mixxx::Bpm(60.0);
constexpr auto firstBeat = mixxx::audio::kStartFramePos;
auto grid1 = mixxx::BeatGrid::makeBeatGrid(
m_pTrack1->getSampleRate(), QString(), bpm, firstBeat);
Expand All @@ -33,8 +33,8 @@ TEST_F(BeatsTranslateTest, SimpleTranslateMatch) {
// doesn't get set naturally, but this will do for now.
auto pBpm1 = std::make_unique<ControlProxy>(m_sGroup1, "bpm");
auto pBpm2 = std::make_unique<ControlProxy>(m_sGroup1, "bpm");
pBpm1->set(bpm);
pBpm2->set(bpm);
pBpm1->set(bpm.getValue());
pBpm2->set(bpm.getValue());
ProcessBuffer();

// Push the button on deck 2.
Expand Down
4 changes: 2 additions & 2 deletions src/test/bpmcontrol_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ TEST_F(BpmControlTest, BeatContext_BeatGrid) {
mixxx::audio::Bitrate(),
mixxx::Duration::fromSeconds(180));

const double bpm = 60.0;
const auto bpm = mixxx::Bpm(60.0);
const int kFrameSize = 2;
const double expectedBeatLength = (60.0 * sampleRate / bpm) * kFrameSize;
const double expectedBeatLength = (60.0 * sampleRate / bpm.getValue()) * kFrameSize;

const mixxx::BeatsPointer pBeats = BeatFactory::makeBeatGrid(
pTrack->getSampleRate(), bpm, mixxx::audio::kStartFramePos);
Expand Down
Loading

0 comments on commit 77d726b

Please sign in to comment.