-
-
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
KeyControl: fix keylock/unlock bugs, reset pitch_adjust #4710
Conversation
back to draft because I am also looking into another issue with key un/lock and out-of-bounds rate changes (pitch/key can not be reset easily) |
The other issue I'm attempting to fix is this:
See 0a6d00d |
ping. Any more comments? |
I've just split the last commit into two to make it easier to review. I'll also manual testing again with all 4 keylock/unlock combinations. |
src/engine/controls/keycontrol.cpp
Outdated
#define ENABLE_DEBUG_OUTPUT false | ||
|
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.
since C++17, conditional compilation is usually better done using if constexpr
instead
#define ENABLE_DEBUG_OUTPUT false | |
constexpr bool kEnableDebugOutput = true; |
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.
The difference is that the code in #if is ignored by the compiler, the code in "if constexpr" is checked and optimized away later.
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.
True, but it doesn't make much of a difference in terms of what ends up in the binary... Metaprogramming using the C++ preprocessor is discouraged from (in C++) AFAIK.
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.
Alright, thanks!
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.
The preprocessor variant is not type safe. But the preprocessor has the benefit, that you can define these macros from outside (compiler commandline call). But here the define is in the source file.
src/engine/controls/keycontrol.cpp
Outdated
// If we just unlocked the original key with speed != +-1.0 we may encounter wrong | ||
// decimals (e.g. 1 - 1.73123e-09) after pitchRatio calculation round-trip. | ||
// Round to 1.0 to avoid false positive pitch offset (pitchOctaves != 0). | ||
double pitchRatioDiffTo1 = fabs(1.0 - m_pitchRateInfo.pitchRatio); | ||
if (0.0 < pitchRatioDiffTo1 && pitchRatioDiffTo1 < pow(10, -9)) { // 0.000000001 | ||
m_pitchRateInfo.pitchRatio = 1.0; | ||
} |
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'm struggling to understand the reasoning behind this because I struggle to understand the surrounding code. m_pitchRateInfo.pitchRatio
is basically imprecise because of rounding errors? But only around 1.0?
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.
Basically roundtrip rounding erros, yes.
Tbh I didn't manage to understand how all the ratios relate in all situations either because I'm still confused by the naming, but with debug output enabled it's at least easy to trace how the m_pitchRateInfo
values change. In #4710 (comment) I outlined the circumstances and the procedure to reproduce the imprecision.
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.
The issue is that the new statement in line 216 is designed to make m_pitchRateInfo.pitchRatio = 1, but it is done indirect via other variables. It would be straight forward and more easy to understand to set it 1 explicit. This would require more changes in the code though.
src/engine/controls/keycontrol.cpp
Outdated
// If we just unlocked the original key with speed != +-1.0 we may encounter wrong | ||
// decimals (e.g. 1 - 1.73123e-09) after pitchRatio calculation round-trip. | ||
// Round to 1.0 to avoid false positive pitch offset (pitchOctaves != 0). | ||
double pitchRatioDiffTo1 = fabs(1.0 - m_pitchRateInfo.pitchRatio); | ||
if (0.0 < pitchRatioDiffTo1 && pitchRatioDiffTo1 < pow(10, -9)) { // 0.000000001 | ||
m_pitchRateInfo.pitchRatio = 1.0; | ||
} |
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.
The issue is that the new statement in line 216 is designed to make m_pitchRateInfo.pitchRatio = 1, but it is done indirect via other variables. It would be straight forward and more easy to understand to set it 1 explicit. This would require more changes in the code though.
Uff, there is another bug:
I'll go with
in order to rebase this whole thing. |
When I fix that bug by setting both
The test assumes that @daschuer Unfortunately some rules aren't clear to me from the code comments / manual (pitch_adjust) and I'd appreciate if you could clarify:
This is very confusing. To be clear, in this stable banch I don't necessarily want to refactor I don't want to open a can of worms and refactor the stable branch just to fix that bug (and make tests still pass).
Edit
Edit 2 |
I have just tested with the 2.3 and the control is implemented on top of keylock. It is not changed if the pitch is adjusted by keylock. For my understanding this behavior is desired, because you will touch the control likely to adjust the pitch from what you have currently.
First snap the control from soft-takeover and then notice that the range of +-3 Semitones has already been reached would feel cumbersome. Soft-Takover is required in mapping though, because the control is reset after loading new tracks. The behavior is described here: mixxx/src/engine/enginebuffer.cpp Line 937 in 74ec345
and here mixxx/src/engine/controls/keycontrol.cpp Line 37 in eff27ab
The manual is not clear and can make use of an update:
|
Here is the manual update: mixxxdj/manual#480 |
That can be expected, since the pitch_adjust is applied to all other. Did you expect that the knob is reset and goes out of sync, in such situation? I can imagine to change that behavior, since the adjusted pitch becomes pointless in that case.
We need an instance that holds the remaining offset. I can confirm that this is confusing, because the know goes out of sync and there is no indicator at all (except in Shade) that we are in such a blended situation
That the knob is moving after match key can be expected in the same way the rate slider moves when using sync. The "unlock, keep current key" mode is part of an "allow toggling keylock during playback" use case. It allows to adjust the tempo without the pitch, and without a pitch jump during enabling. Not sure if this is used at all in the wild. During keylock enabled, the the rate slider becomes temporary a tempo only slider. I think the user user expects that the pitch_adjust control is an independent pitch control for that state. If we use pitch_adjust purely for the distance to the linear pitch, it will move out of sync whenever you move the rate slider. I think this was the main reason to apply it on top of keylock to avoid this. |
Yes, I'd expect that that the pitch is reset to default, exactly as labeled in the preferences: Keylock mode "Original key". That would be an easy way to reset the key if you don't have Also, this fixes the key shift bug with "lock original" + "unlock keep current".
I use it : ) The motivation to implement it was that I have keylock enabled pretty much all the time, but sometimes I want to produce smooth pitchbend effects just with the jog wheel (or with the tempo slider). Then lock again, if necessary re-sync the beats with the jogwheel. |
OK, I have no objection to this change. It may actually feel more natural, even though it is a point release of a mature branch. Can we still consider it as part of a bugfix?
Great to hear. It this an unique selling point of Mixxx? Maybe a topic of a future news post ;-) |
I started DJing on Linux so don't and didn't use any other soft than Mixxx : )
It fixes the continuous key shift when toggling keylock repeatedly with "Lock original" and "Unlock, keep current".
I think only users who have So I think it's the same situation as with the crossfader reset after AutoDJ runs out: |
I noticed another bug (and I have no idea why we/I implemented it that way in #1222): |
Furthermore I noticed the pitch/keylock tests don't consider the unlock mode, thus they are partially pointless (assuming the default unlock mode). |
Considering I started this to fix a small initialization bug and minor anoyance with my use case this is growing rather big... |
I think I will split this up:
So the simple fixes can go to the next bugfix release asap. |
Yes, I did also consider this. This way we can get out 2.3.2 in de upcoming week or such. |
2.3.3, yes. |
This PR is marked as stale because it has been open 90 days with no activity. |
Oh, sorry this has stalled. Can you resolve it the conflicts? |
The conflicts are only in the testing skin. |
Is the track load behavior still in the desired state? |
Everything still looks okay when testing with my script. I added a simple test for KeepLockedKey mode and removed the skin commit. |
I'm not that much into what I did here after my last edit months ago X), please give my some steps to reproduce / understand what you mean. |
?? |
In a manual test though I ended up with pitch_adjust != 0 again (couldn't reproduce until now, but I didn't do many runs):
🤷 Will see if I can reproduce with my controller. |
Anyone has a clue what's going on? |
Alright, @daschuer wanna take a final look? |
don't have time for a detailed review, but after taking a quick glance, I have not found any obvious issues.
// If 'current' aka 'not original' key was locked | ||
// TODO(ronso0) Why does it depend on keylock mode? | ||
if (m_keylockMode->get() == kLockCurrentKey) { | ||
// reset to linear pitch |
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.
it's not that we reset to linear pitch, it's that we allow rate slider changes to affect the musical pitch. But 0.0 rate adjustment may no longer the original key.
EDIT: nevermind I misread the switch-case
I wrote a lot of text that was all wrong -- I think this fix is correct! thank you <3 |
🎉 |
Fixes unintented pitch shift when un/locking repeatedly with "lock original key" and "unlock, keep current key", see #4710 (comment) by resetting
pitch_adjust
when unlocking to linear pitch and locking to original key.