Skip to content

Conversation

@m1macrophage
Copy link
Contributor

Detecting the special case of a filter with high resonance and no input waveforms, and generating a sine wave to implement self-oscillation.

Fixes the regression reporter here. Also fixes patches 98 and 99 on the sixtrak, and enables ever more sounds in sente6vb .

Finally, corrected the value of m_pulse_width when PW is at 100%. Though this does not make a difference, since m_pulse_width is not used when the PW is 100%.

@galibert
Copy link
Member

That's kinda gross...

@m1macrophage
Copy link
Contributor Author

m1macrophage commented Dec 16, 2025

Open to other ideas.

I tried a few things before resorting to this. For context, the problematic case is when the filter is configured with no input and full resonance. The fixes below, and in this PR, were only applied in this configuration.

I tried exciting the filter with noise and a pulse wave. Both fixed self-oscillation, but in both cases, the fake input came through to the output. As an aside, an incorrect pulse input seems to be why self-oscillation was (sometimes) working before #14497.

I also tried just using DC as an input, but that didn't work.

The "least gross" approach that worked was to avoid clamping the resonance to 0.99 when there are no inputs.

double res = m_filter_resonance;
if (res > 0.99)
res = 0.99, outscale = 0.5;

But AFAICT, that's not guaranteed to always work (though it did in my tests). Furthermore, it looks like the clamping was done for stability, and removing it might increase the risk of the filter exploding and losing audio. So it felt a bit risky.

@m1macrophage
Copy link
Contributor Author

The "least gross" approach that worked was to avoid clamping the resonance to 0.99 when there are no inputs [...] it felt a bit risky.

If the risk is acceptable, I can go with this approach after doing some more testing. And can revisit if there are reports of lost audio or missing sounds.

There seem to be additional safeguards for filter stability, which might help mitigate the risk:

// if we go out of range, scale down to 1.0 and also scale our
// feedback terms to help us stay in control
else if (fabs(output) > 1.0)
{
double scale = 1.0 / fabs(output);
output *= scale;
m_filter_out[0] *= scale;
m_filter_out[1] *= scale;
}

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.

2 participants