-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Beats: Refactor getBpm() into getBpmInRange(startPos, endPos) #4361
Conversation
50dcde0
to
1ab61f5
Compare
|
@@ -145,7 +145,10 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer pTrack) const { | |||
if (!pBeats) { | |||
return true; | |||
} | |||
if (!pBeats->getBpm().isValid()) { | |||
if (!pBeats->getBpmInRange(mixxx::audio::kStartFramePos, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now a very expensive check for a valid BPM. Maybe caching the nominal bpm is not such a bad idea.
What are the alternatives?
Can we add a getNominalBpm() for the whole track? We also have getBpmAroundPosition() which is the average, I can imagine confusion that on in the nominal BPM and the other the average. |
No, for the reasons I explained in the commit message. We simply don't know how long the track is.
I don't know. Right now, we always use the start/end position.
I don't really know what you mean. Both essentially do the same, it's just that:
|
I don't understand that. We have currently a well working nominal value. It is independednt from the total track length.
I cant think of one as well, so we can remove this feature and simplify the API. I propose to keep |
I am doubtful that "nominal BPM" is a concept that should exist in Mixxx. |
We need it for the value shown in the library. |
It's my primary sorting criteria for search results when DJing. |
I think a nominal bpm is not accurate and not that helpful in the library. A BPM range of the min-max bpms in the track would make more sense. Representing a track with changing bpm the same as a track with constant bpm in the library is also misleading IMO. |
I don't understand what you're proposing if you don't want to remove the overall Bpm entirely. Should I remove support for legacy beatgrids/beatmaps in #4255 and always force a reanalysis instead? Or do you have another solution? |
I suppose there are better ways to handle this, but it is out of scope for this PR. I just wanted to make our current bpm retrieval work with #4255, not redesign the BPM column in the library ;-) |
Do not only consider use cases of playing a single genre with a very limited tempo range. A single value is perfectly accurate if you play a broad range of music between 60 and 180 bpm. I don't want to see 2 values and decide which one to choose for sorting and display both of them, information overload. Not needed for 99.9% of all the tracks. Min/max is useless if you don't know to which part of the track they apply to. If a track starts with a lower or higher bpm I could take a note. KISS! |
I suppose a nominal bpm value is fine as a stop gap solution then.
You misunderstood, but we can discuss this more when we actually decide to redesign this. |
This lays some groundwork for a future, sparse representation of beats in a track. At the moment, we have two kinds of beats implementations: 1. The `BeatMap` representation is simply a list of every single beat position in a track. Hence, changing tempos are supported, but memory intensive to work with. 2. The `BeatGrid` representation is actually sparse (only stores the offset and bpm instead of actual beat positions), but only supports a single constant tempo. Both are not sufficient. A future implementation should be both sparse and support multiple tempos per track. To make this possible, we need to know the track duration for calculating the average BPM of a track. There are two ways to handle this: We could either store the track duration in a beats object, or we change the `getBpm()` method signature to require passing the position range of the track that we want to know the BPM for. This commit implements the latter solution, because it's fully backwards-compatible and - in contrast to the former - can be implemented *without* modifying the protobuf format of the `BeatGrid` class (which currently doesn't store the track end position). Related Zulip discussion: https://mixxx.zulipchat.com/#narrow/stream/109171-development/topic/beat.20grid.20revamp.20re.3A.20pr.20.232961/near/251702242
1ab61f5
to
883cea1
Compare
@daschuer To clarify, let's consider a non-const track with 3 different tempo sections:
The corresponding beat object would have the following data structure:
Here, position A is the start of the track (or rather the position of the Now to the problem: To compute the average BPM of the track, I need to know how Hence the two options:
|
Passing the duration of the track as a parameter from the outer context instead of storing it redundantly and needlessly inside the grid is correct, imho. If the first section always starts at position 0 then storing the end instead of the start position for each section could be an alternative representation. This representation would then be self-contained. I didn't check the code yet: Does the representation support sections with unknown tempo, i.e. 0 bpm? These sections should be skipped when calculating an average bpm. |
No, the first section may start anywhere (the track could begin with silence). The first section should start at the first Downbeat.
No. This isn't possible because internally, because the new beats implementation uses a random access iterator to navigate between beats. If there were unknown sections, this wouldn't work. |
First of all, I think we need to define two terms to understand each other's. Average BPM: the math correct average of a certain number of beats. Nominal BPM: the single number displayed in the library, significant for sorting and comparing When importing const BeatGrids, both values are the same, there is no need for the track length. When importing BeatMaps let's say a ~120 BPM track with a speed up section of 160 BPM. |
For me it is mandatory to have the nominal value "somewhere" in Mixxx. We need it only for display purpose, in the library and the track metadata, where we are limited to a single value. |
The issue you mention raises because of the missing last beat in your model. The problem does not exist during the initial import, but will come up whenever you edit the BeatGrid, because you cannot recreate the nominal value. Introducing a final beat is not possible in case of BeatMaps, because of the missing track length in the current data. So we need something tricky around this dead lock. I have an Idea! |
For a nominal BPM you need at least two beats. I have no use case for the Average overall BPM. |
Isn't this a drop in replacement, which covers all use cases currently implemented in Mixxx 1:1? |
I agree. It is important to keep the scope of these refactoring PRs as small as possible without introducing regressions. |
The current solution looks a bit cluttered to me, but OK we can change that at any time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Is this ready to merge?
Did you consider my idea?
Yes, it's ready to merge. I'm not sure i understood your idea correctly, but I suppose it's easier to discuss this over at #4255 where we can discuss the code. |
Thank you. |
This lays some groundwork for a future, sparse representation of beats
in a track.
At the moment, we have two kinds of beats implementations:
BeatMap
representation is simply a list of every single beatposition in a track. Hence, changing tempos are supported, but memory
intensive to work with.
BeatGrid
representation is actually sparse (only stores theoffset and bpm instead of actual beat positions), but only supports a
single constant tempo.
Both are not sufficient. A future implementation should be both sparse
and support multiple tempos per track. To make this possible, we need to
know the track duration for calculating the average BPM of a track.
There are two ways to handle this: We could either store the track
duration in a beats object, or we change the
getBpm()
method signatureto require passing the position range of the track that we want to know
the BPM for.
This commit implements the latter solution, because it's fully
backwards-compatible and - in contrast to the former - can be
implemented without modifying the protobuf format of the
BeatGrid
class (which currently doesn't store the track end position).
Related Zulip discussion:
https://mixxx.zulipchat.com/#narrow/stream/109171-development/topic/beat.20grid.20revamp.20re.3A.20pr.20.232961/near/251702242