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

EngineFilterDelay: clamp wrong delay values #4869

Merged
merged 2 commits into from
Jul 26, 2022

Conversation

davidchocholaty
Copy link
Contributor

This PR moves the delay value checking into a setter in EngineFilterDelay. The reason, why the delay value checking should be updated is, that the previous version allows working with a huge not acceptable delay, but which is after inner calculation allowed due to it is a k-multiple (on the left side of the modulo operator) of the delay buffer size (on the right side of the modulo operator). Three examples for which is in previous version delay allowed, and should not be:

Let's work with the used size of the delay buffer as SIZE = 3300.

  1. The first example works with delay size as 4*3300 = 13200
    int delaySourcePos = (m_delayPos + SIZE - m_delaySamples) % SIZE = (0 + 3300 - 13200) % 3300 = -9900 % 3300 = 0

  2. The second example works with a huge delay, but which is the same as m_delayPos + SIZE.
    int delaySourcePos = (m_delayPos + SIZE - m_delaySamples) % SIZE = (2426 + 3300 - 5726) % 3300 = 0 % 3300 = 0

  3. The third example works with the situation similar to 1, anyway, it shows that the position has not to be zero.
    int delaySourcePos = (m_delayPos + SIZE - m_delaySamples) % SIZE = (1024 + 3300 - 7624) % 3300 = -3300 % 3300 = 0

Based on the delay value checking in the setter, the situation, that the previous used VERIFY_OR_DEBUG_ASSERT will be violated should not occur.

@@ -29,6 +29,13 @@ class EngineFilterDelay : public EngineObjectConstIn {

void setDelay(unsigned int delaySamples) {
m_delaySamples = delaySamples;

// When mixxx will support other channel count variants than stereo,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may put a static_assert for this condition as well. That will fail the build in that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also assert here that the delay is devide-able by the channel count?
This way we can below just use < SIZE which is easier to understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, that is really more clear way.

// the kMaxDelay has to be divisible by the number of channels.
// Otherwise, channels may be swapped.
VERIFY_OR_DEBUG_ASSERT(m_delaySamples <= SIZE - mixxx::kEngineChannelCount) {
m_delaySamples = SIZE - mixxx::kEngineChannelCount;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code just performs a. copy.
(Delay = 0) in that case. Since we are anyway In an anti crash backup path, I find mind, I just want to pint it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, that's right. This PR just offers another point of view for the problem, that the wrong delay values can be clamped in the setter. This version should be anti-crash too. Of course, I will be okay, if the PR won't be merged. It is just proposed to use a more similar approach as in EngineDelay or the future used EngineEffectsDelay.

// When mixxx will support other channel count variants than stereo,
// the kMaxDelay has to be divisible by the number of channels.
// Otherwise, channels may be swapped.
VERIFY_OR_DEBUG_ASSERT(m_delaySamples <= SIZE - mixxx::kEngineChannelCount) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this condition correct, or do we need to substract the engine buffer size?

Copy link
Contributor Author

@davidchocholaty davidchocholaty Jul 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain more about why you think of substracting the engine buffer size instead and which "engine buffer size" you think of? The size of the input buffer? The reason, why the number of channels is subtracted is, that the delay size can't be equal to the size of the delay buffer (m_buf). It can be smaller and subtracting the number of channels ensures, that the channels won't be swapped between. IMO the assertion shouldn't go wrong as original, because it doesn't allow the delay values greater than possible (greater or equal to buffer size), so the m_delaySamples values from the examples wouldn't be allowed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I have misread the code. In case of 0 delay, you but one frame into the buffer and read it back immediately.
That is why - mixxx::kEngineChannelCount is sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. Perfect.

Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we need to subtract the engine buffer size, so the assertion where wrong original as well.

This commit moves the correctness evaluation of the delay value
into a setter and the set value is directly checked
instead of calculated index values.
@davidchocholaty davidchocholaty force-pushed the fix_delay_value_checking branch from c792d31 to 855be72 Compare July 26, 2022 06:30
This commit adds two assertions. The first one is a static_assert
which tests if the templated SIZE is divisible
by the number of channels. The second one is VERIFY_OR_DEBUG_ASSERT
in EngineFilterDelay::setDelay. It tests if the number of delay samples
is divisible by the number of channels. If the delay size
is not aligned, the unaligned samples are cropped (rounded
to the previous multiple of the number of channel count).
Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. LGTM

@daschuer daschuer merged commit 5f5e92f into mixxxdj:main Jul 26, 2022
@davidchocholaty
Copy link
Contributor Author

Thank you very much for merging.

@Swiftb0y
Copy link
Member

thanks for taking care @daschuer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants