-
-
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
Fuzzy beats fix. #4366
Fuzzy beats fix. #4366
Conversation
…use it interferes with its own snapping logic.
…cause the snapped beat is the closes anyway.
This fixes a regressions from 8ef9dd3
The CI error is unrelated:
|
I restarted CI. |
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.
Some first comments
src/track/beatgrid.cpp
Outdated
const double nextBeat = ceil(beatFraction); | ||
|
||
audio::FramePos closestBeatPosition; | ||
double startBeat = (position - firstBeatPosition()) / m_beatLengthFrames; |
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.
I think the naming is a bit confusing. Maybe something like this?
double startBeat = (position - firstBeatPosition()) / m_beatLengthFrames; | |
double beatIndex = (position - firstBeatPosition()) / m_beatLengthFrames; |
@@ -49,7 +49,22 @@ BeatsPointer Beats::fromBeatPositions( | |||
return BeatMap::makeBeatMap(sampleRate, subVersion, beatPositions); | |||
} | |||
|
|||
audio::FramePos Beats::snapPosToNearBeat(audio::FramePos position) const { |
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 method is very similar to Beats::findClosestBeat
. Can we unify this? https://github.com/mixxxdj/mixxx/blob/main/src/track/beats.cpp#L73
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.
that code is a little dangerous for beatmap tracks which have no beats before the beginning. Loops will always snap to the first beat even if the loop start is before the beginning (i.e., no prev beat). (I have tracks where that's necessary because the track starts on an off-beat)
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.
I think we could either
- introduce a maxDelta argument to prevent this, or
- make this method call
findClosestBeat
and then return the closest beat position ifabs(position - closestBeatPosition) > kEpsilon
andposition
otherwise.
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.
I think for now it's acceptable to have loops snap to the first available beat. Note that with the current code, loops initiated before the first beat don't get created at all, so we should at least fix that. Reusing this existing function might fix that.
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 method is very similar to Beats::findClosestBeat.
Beats::snapPosToNearBeat snaps only if a beat is within the snapping range. Beats::findClosestBeat finds the beat in any range. I think the description in the header file is already explaining this difference.
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.
that code is a little dangerous for beatmap tracks which have no beats before the beginning. Loops will always snap to the first beat even if the loop start is before the beginning (i.e., no prev beat). (I have tracks where that's necessary because the track starts on an off-beat)
You can't set beat loops in beatmap tracks before the first beat. However loops are snapped to the next beat when you are in the snapping region. Extrapolating into the preroll would be a new feature. I think We should postpone it to a follow up PR.
@@ -1266,20 +1266,21 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable | |||
} else { | |||
newloopInfo.startPosition = currentPosition; | |||
} | |||
} else { | |||
} else if (m_pQuantizeEnabled->toBool()) { |
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.
I can see that you moved this here to avoid an unnecessary beats lookup. This nesting is getting deep and confusing, is there a way we can rearrange the logic to simplify it? I think the whole block could be pulled into a new small function ("findLoopStart"?) that takes the current start position and loop length and returns a new one. That would allow us to return as soon as we find the new start position, which I think is the only output of this block:
ex:
if (!m_pQuantizeEnabled->toBool()) { return currentPosition; }
…first beat by using the beat length of the fist beat.
Review comments are integrated. A bug when playing reverse was fixed and we can now set a beat loop one beat before the first beat. |
This still doesn't create any loop if the playhead is before the first beat in a beatmap track. Can we make it round up to the first beat in that situation? (see my previous comment) |
The feature is limited in the region of one beat length before the first beat. This PR does not fix the issue when you are way before the first beat. A solution is more complicated, because normally the first beats is not really significant for a suitable tempo in an initial loop. We need a more sophisticated solution that consideres all other beats in the loop. A topic for another PR. |
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.
Yeah I would still like something where we propagate the first beat length backward in time to work around these issues.
OK I see how this still works when the playhead is slightly before the first beat. That is good enough for now. thanks! LGTM
Please check out #4255 which does exactly that :D |
I have reviewed all edge case for the beat snapping algorithm and adjusted it as it makes most sense.
Normally the functions should not snap to a beat. In most cases this creates exceptional code paths which are hard to maintain, because snapping of an inner function is not expected when reading the code.
We have two exceptions where snapping is still applied:
The additional double rounding issue of the BeatGrid code should be fixed now.
I am unsure about the BeatGridIterator it is implemented by repeated
m_currentPosition += m_beatLengthFrames
. I am unsure if it is exactly the same if we usen * m_beatLengthFrames
. I am afraid not. Does anyone know?Luckily it is only used for visual beats.
This should make #4334 obsolete and fix https://bugs.launchpad.net/mixxx/+bug/1945238