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

LinearFadeStrategy fails to detect fade completion for sub-second durations #268

Closed
R0ll1ngSt0ne opened this issue Aug 29, 2017 · 4 comments

Comments

@R0ll1ngSt0ne
Copy link

R0ll1ngSt0ne commented Aug 29, 2017

Depending on sample frequency and specified fade duration (usually, < 500ms), fade volume increment step can become too large and _currentVolument will overshoot the _targetVolume. Fade completion never gets detected and volume keeps increasing infinitely. Here is the fix:

File: LinearFadeStrategy.cs

Original:

private bool IsFadingFinished()
{
   return Math.Abs(_currentVolume - _targetVolume) < 0.00001f;
}

Fixed:

private bool IsFadingFinished()
{
   return Math.Abs(_currentVolume - _targetVolume) < Math.Abs(_step) ||
      _step > 0.0f && _currentVolume > _targetVolume ||
      _step < 0.0f && _currentVolume < _targetVolume;
}
@filoe filoe added the bug label Sep 9, 2017
@filoe filoe added this to the CSCore 1.3 release milestone Sep 9, 2017
filoe added a commit that referenced this issue Sep 9, 2017
@filoe
Copy link
Owner

filoe commented Sep 9, 2017

Thanks for reporting and providing a propper solution! 👍

@filoe filoe closed this as completed Sep 9, 2017
@R0ll1ngSt0ne
Copy link
Author

Sorry, I forgot to cover the case when _step is 0) - fade should finish immediately (probably a check should be added to StartFading so that no cycle is wasted to detect completion:

if (Math.Abs(_step) <= 0.00001f)
... complete fade right away

@filoe
Copy link
Owner

filoe commented Sep 10, 2017

You mean after this line:

_step = delta / durationInBlocks;

we should add the check and eventually call StopFadingInternal()?

I would suggest adding the following:

if(IsFadingFinished())
    StopFadingInternal();

@R0ll1ngSt0ne
Copy link
Author

I rewrote StartFading like this to cover these edge cases:

    public void StartFading(float? from, float to, double duration)
    {
        if (SampleRate <= 0)
            throw new InvalidOperationException("SampleRate property is not set to a valid value.");
        if (Channels <= 0)
            throw new InvalidOperationException("Channels property it not set to a valid value.");
        if (to < 0 || to > 1)
            throw new ArgumentOutOfRangeException("to");

        if (IsFading)
            StopFadingInternal();

        if (!from.HasValue)
            _startVolume = CurrentVolume;
        else
        {
            if (from.Value < 0 || from.Value > 1)
                throw new ArgumentOutOfRangeException("from");
            _startVolume = from.Value;
        }

        _targetVolume = to;
        _currentVolume = _startVolume;

        float delta = _targetVolume - _startVolume;

        // Done immediately if duration is 0 or start end end volumes are the same
        if (Math.Abs(duration) < 1.0 || Math.Abs(delta) < 0.00001f)
        {
            FinalizeFading();
        }
        else
        {
            //calculate the step
            var durationInBlocks = (int)(duration / 1000 * SampleRate);
            _step = delta / durationInBlocks;

            IsFading = true;
        }
    }

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

No branches or pull requests

2 participants