Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BeatsImporter: Return Beats object instead of frame position vector #4342

Merged
merged 1 commit into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions src/test/seratobeatgridtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,19 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) {
mixxx::SeratoBeatsImporter beatsImporter(
seratoBeatGrid.nonTerminalMarkers(),
seratoBeatGrid.terminalMarker());
const QVector<mixxx::audio::FramePos> importedBeatPositionsFrames =
beatsImporter.importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo);
ASSERT_EQ(beatPositionsFrames.size(), importedBeatPositionsFrames.size());
const auto pImportedBeats =
beatsImporter.importBeatsAndApplyTimingOffset(
timingOffsetMillis, signalInfo);
auto pBeatsIterator =
pImportedBeats->findBeats(beatPositionsFrames.first() - 1000,
beatPositionsFrames.last() + 1000);
for (int i = 0; i < beatPositionsFrames.size(); i++) {
const auto importedPosition = pBeatsIterator->next();
EXPECT_NEAR(beatPositionsFrames[i].value(),
importedBeatPositionsFrames[i].value(),
importedPosition.value(),
kEpsilon);
}
ASSERT_FALSE(pBeatsIterator->hasNext());
}

constexpr int kNumBeats60BPM = 4;
Expand Down Expand Up @@ -218,14 +223,19 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) {
mixxx::SeratoBeatsImporter beatsImporter(
seratoBeatGrid.nonTerminalMarkers(),
seratoBeatGrid.terminalMarker());
const QVector<mixxx::audio::FramePos> importedBeatPositionsFrames =
beatsImporter.importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo);
ASSERT_EQ(beatPositionsFrames.size(), importedBeatPositionsFrames.size());
const auto pImportedBeats =
beatsImporter.importBeatsAndApplyTimingOffset(
timingOffsetMillis, signalInfo);
auto pBeatsIterator =
pImportedBeats->findBeats(beatPositionsFrames.first() - 1000,
beatPositionsFrames.last() + 1000);
for (int i = 0; i < beatPositionsFrames.size(); i++) {
const auto importedPosition = pBeatsIterator->next();
EXPECT_NEAR(beatPositionsFrames[i].value(),
importedBeatPositionsFrames[i].value(),
importedPosition.value(),
kEpsilon);
}
ASSERT_FALSE(pBeatsIterator->hasNext());
}

qInfo() << "Step 3: Add" << kNumBeats120BPM << "beats at 100 bpm to the beatgrid";
Expand Down Expand Up @@ -274,14 +284,19 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) {
mixxx::SeratoBeatsImporter beatsImporter(
seratoBeatGrid.nonTerminalMarkers(),
seratoBeatGrid.terminalMarker());
const QVector<mixxx::audio::FramePos> importedBeatPositionsFrames =
beatsImporter.importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo);
ASSERT_EQ(beatPositionsFrames.size(), importedBeatPositionsFrames.size());
const auto pImportedBeats =
beatsImporter.importBeatsAndApplyTimingOffset(
timingOffsetMillis, signalInfo);
auto pBeatsIterator =
pImportedBeats->findBeats(beatPositionsFrames.first() - 1000,
beatPositionsFrames.last() + 1000);
for (int i = 0; i < beatPositionsFrames.size(); i++) {
const auto importedPosition = pBeatsIterator->next();
EXPECT_NEAR(beatPositionsFrames[i].value(),
importedBeatPositionsFrames[i].value(),
importedPosition.value(),
kEpsilon);
}
ASSERT_FALSE(pBeatsIterator->hasNext());
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/track/beatsimporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "audio/frame.h"
#include "audio/streaminfo.h"
#include "track/beats.h"

namespace mixxx {

Expand All @@ -16,9 +17,8 @@ class BeatsImporter {

virtual bool isEmpty() const = 0;

/// Determines the timing offset and returns a Vector of frame positions
/// to use as input for the BeatMap constructor
virtual QVector<mixxx::audio::FramePos> importBeatsAndApplyTimingOffset(
/// Determines the timing offset and returns a Beats object.
virtual BeatsPointer importBeatsAndApplyTimingOffset(
const QString& filePath, const audio::StreamInfo& streamInfo) = 0;
};

Expand Down
16 changes: 9 additions & 7 deletions src/track/serato/beatsimporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ bool SeratoBeatsImporter::isEmpty() const {
return !m_pTerminalMarker;
};

QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOffset(
BeatsPointer SeratoBeatsImporter::importBeatsAndApplyTimingOffset(
const QString& filePath, const audio::StreamInfo& streamInfo) {
const audio::SignalInfo& signalInfo = streamInfo.getSignalInfo();
const double timingOffsetMillis = SeratoTags::guessTimingOffsetMillis(
Expand All @@ -31,10 +31,10 @@ QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOf
return importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo);
}

QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOffset(
BeatsPointer SeratoBeatsImporter::importBeatsAndApplyTimingOffset(
double timingOffsetMillis, const audio::SignalInfo& signalInfo) {
VERIFY_OR_DEBUG_ASSERT(!isEmpty()) {
return {};
return nullptr;
}

QVector<mixxx::audio::FramePos> beats;
Expand All @@ -45,7 +45,7 @@ QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOf
beatPositionMillis = static_cast<double>(pMarker->positionSecs()) * 1000;
VERIFY_OR_DEBUG_ASSERT(pMarker->positionSecs() >= 0 &&
pMarker->beatsTillNextMarker() > 0) {
return {};
return nullptr;
}
const double nextBeatPositionMillis =
static_cast<double>(i == (m_nonTerminalMarkers.size() - 1)
Expand All @@ -54,7 +54,7 @@ QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOf
->positionSecs()) *
1000;
VERIFY_OR_DEBUG_ASSERT(nextBeatPositionMillis > beatPositionMillis) {
return {};
return nullptr;
}
const double beatLengthMillis =
(nextBeatPositionMillis - beatPositionMillis) /
Expand All @@ -78,7 +78,7 @@ QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOf
// | | | | | | | | |[###### Remaining range ######]
const double beatLengthMillis = 60000.0 / static_cast<double>(m_pTerminalMarker->bpm());
VERIFY_OR_DEBUG_ASSERT(m_pTerminalMarker->positionSecs() >= 0 && beatLengthMillis > 0) {
return {};
return nullptr;
}

const double rangeEndBeatPositionMillis =
Expand Down Expand Up @@ -109,7 +109,9 @@ QVector<mixxx::audio::FramePos> SeratoBeatsImporter::importBeatsAndApplyTimingOf
m_nonTerminalMarkers.clear();
m_pTerminalMarker.reset();

return beats;
return Beats::fromBeatPositions(
signalInfo.getSampleRate(),
beats);
}

} // namespace mixxx
5 changes: 3 additions & 2 deletions src/track/serato/beatsimporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <QList>

#include "track/beats.h"
#include "track/beatsimporter.h"
#include "track/serato/beatgrid.h"

Expand All @@ -18,14 +19,14 @@ class SeratoBeatsImporter : public BeatsImporter {
~SeratoBeatsImporter() override = default;

bool isEmpty() const override;
QVector<mixxx::audio::FramePos> importBeatsAndApplyTimingOffset(
BeatsPointer importBeatsAndApplyTimingOffset(
const QString& filePath,
const audio::StreamInfo& streamInfo) override;

private:
FRIEND_TEST(SeratoBeatGridTest, SerializeBeatMap);

QVector<mixxx::audio::FramePos> importBeatsAndApplyTimingOffset(
BeatsPointer importBeatsAndApplyTimingOffset(
double timingOffsetMillis, const audio::SignalInfo& signalInfo);

QList<SeratoBeatGridNonTerminalMarkerPointer> m_nonTerminalMarkers;
Expand Down
5 changes: 2 additions & 3 deletions src/track/track.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1081,10 +1081,9 @@ bool Track::importPendingBeatsWhileLocked() {
// The sample rate is supposed to be consistent
DEBUG_ASSERT(m_record.getStreamInfoFromSource()->getSignalInfo().getSampleRate() ==
m_record.getMetadata().getStreamInfo().getSignalInfo().getSampleRate());
const auto pBeats = mixxx::Beats::fromBeatPositions(
m_record.getStreamInfoFromSource()->getSignalInfo().getSampleRate(),
const auto pBeats =
m_pBeatsImporterPending->importBeatsAndApplyTimingOffset(
getLocation(), *m_record.getStreamInfoFromSource()));
getLocation(), *m_record.getStreamInfoFromSource());
DEBUG_ASSERT(m_pBeatsImporterPending->isEmpty());
m_pBeatsImporterPending.reset();
return setBeatsWhileLocked(pBeats);
Expand Down