Skip to content

Commit

Permalink
BeatGrid: Remove fuzzy behavior from findNthBeat
Browse files Browse the repository at this point in the history
  • Loading branch information
Holzhaus committed Jul 12, 2021
1 parent d77c4f7 commit 95f7d36
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 115 deletions.
94 changes: 0 additions & 94 deletions src/test/beatgridtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,100 +99,6 @@ TEST(BeatGridTest, TestNthBeatWhenOnBeat) {
EXPECT_NEAR(position.value(), pGrid->findPrevBeat(position).value(), kMaxBeatError);
}

TEST(BeatGridTest, TestNthBeatWhenOnBeat_BeforeEpsilon) {
constexpr int sampleRate = 44100;
TrackPointer pTrack = newTrack(sampleRate);

constexpr double bpm = 60.1;
pTrack->trySetBpm(bpm);
constexpr double beatLengthFrames = 60.0 * sampleRate / bpm;

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

// Pretend we're just before the 20th beat.
constexpr mixxx::audio::FramePos kClosestBeat(20 * beatLengthFrames);
const mixxx::audio::FramePos position(kClosestBeat - beatLengthFrames * 0.005);

// The spec dictates that a value of 0 is always invalid and returns an invalid position
EXPECT_FALSE(pGrid->findNthBeat(position, 0).isValid());

// findNthBeat should return exactly the current beat if we ask for 1 or
// -1. For all other values, it should return n times the beat length.
for (int i = 1; i < 20; ++i) {
EXPECT_NEAR((kClosestBeat + beatLengthFrames * (i - 1)).value(),
pGrid->findNthBeat(position, i).value(),
kMaxBeatError);
EXPECT_NEAR((kClosestBeat + beatLengthFrames * (-i + 1)).value(),
pGrid->findNthBeat(position, -i).value(),
kMaxBeatError);
}

// Also test prev/next beat calculation.
mixxx::audio::FramePos prevBeat, nextBeat;
pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, true);
EXPECT_NEAR(kClosestBeat.value(), prevBeat.value(), kMaxBeatError);
EXPECT_NEAR((kClosestBeat + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError);

// Also test prev/next beat calculation without snapping tolerance
pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, false);
EXPECT_NEAR((kClosestBeat - beatLengthFrames).value(), prevBeat.value(), kMaxBeatError);
EXPECT_NEAR(kClosestBeat.value(), nextBeat.value(), kMaxBeatError);

// Both previous and next beat should return the closest beat.
EXPECT_NEAR(kClosestBeat.value(), pGrid->findNextBeat(position).value(), kMaxBeatError);
EXPECT_NEAR(kClosestBeat.value(), pGrid->findPrevBeat(position).value(), kMaxBeatError);
}

TEST(BeatGridTest, TestNthBeatWhenOnBeat_AfterEpsilon) {
constexpr int sampleRate = 44100;
TrackPointer pTrack = newTrack(sampleRate);

constexpr double bpm = 60.1;
pTrack->trySetBpm(bpm);
constexpr double beatLengthFrames = 60.0 * sampleRate / bpm;

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

// Pretend we're just before the 20th beat.
constexpr mixxx::audio::FramePos kClosestBeat(20 * beatLengthFrames);
const mixxx::audio::FramePos position(kClosestBeat + beatLengthFrames * 0.005);

// The spec dictates that a value of 0 is always invalid and returns an invalid position
EXPECT_FALSE(pGrid->findNthBeat(position, 0).isValid());

// findNthBeat should return exactly the current beat if we ask for 1 or
// -1. For all other values, it should return n times the beat length.
for (int i = 1; i < 20; ++i) {
EXPECT_NEAR((kClosestBeat + beatLengthFrames * (i - 1)).value(),
pGrid->findNthBeat(position, i).value(),
kMaxBeatError);
EXPECT_NEAR((kClosestBeat + beatLengthFrames * (-i + 1)).value(),
pGrid->findNthBeat(position, -i).value(),
kMaxBeatError);
}

// Also test prev/next beat calculation.
mixxx::audio::FramePos prevBeat, nextBeat;
pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, true);
EXPECT_NEAR(kClosestBeat.value(), prevBeat.value(), kMaxBeatError);
EXPECT_NEAR((kClosestBeat + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError);

// Also test prev/next beat calculation without snapping tolerance
pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, false);
EXPECT_NEAR(kClosestBeat.value(), prevBeat.value(), kMaxBeatError);
EXPECT_NEAR((kClosestBeat + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError);

// Both previous and next beat should return the closest beat.
EXPECT_NEAR(kClosestBeat.value(), pGrid->findNextBeat(position).value(), kMaxBeatError);
EXPECT_NEAR(kClosestBeat.value(), pGrid->findPrevBeat(position).value(), kMaxBeatError);
}

TEST(BeatGridTest, TestNthBeatWhenNotOnBeat) {
constexpr int sampleRate = 44100;
TrackPointer pTrack = newTrack(sampleRate);
Expand Down
24 changes: 3 additions & 21 deletions src/track/beatgrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,27 +184,9 @@ audio::FramePos BeatGrid::findNthBeat(audio::FramePos position, int n) const {
return audio::kInvalidFramePos;
}

double beatFraction = (position - firstBeatPosition()) / m_beatLengthFrames;
double prevBeat = floor(beatFraction);
double nextBeat = ceil(beatFraction);

// If the position is within 1/100th of the next or previous beat, treat it
// as if it is that beat.
const double kEpsilon = .01;

if (fabs(nextBeat - beatFraction) < kEpsilon) {
// If we are going to pretend we were actually on nextBeat then prevBeat
// needs to be re-calculated. Since it is floor(beatFraction), that's
// the same as nextBeat. We only use prevBeat so no need to increment
// nextBeat.
prevBeat = nextBeat;
} else if (fabs(prevBeat - beatFraction) < kEpsilon) {
// If we are going to pretend we were actually on prevBeat then nextBeat
// needs to be re-calculated. Since it is ceil(beatFraction), that's
// the same as prevBeat. We will only use nextBeat so no need to
// decrement prevBeat.
nextBeat = prevBeat;
}
const double beatFraction = (position - firstBeatPosition()) / m_beatLengthFrames;
const double prevBeat = floor(beatFraction);
const double nextBeat = ceil(beatFraction);

audio::FramePos closestBeatPosition;
if (n > 0) {
Expand Down

0 comments on commit 95f7d36

Please sign in to comment.