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;
}

@galibert
Copy link
Member

I'm quite surprised you can have zero input in the first place. The oscillators are usually free-running and the envelope/gating happens after the filter. Checking the 3394 schematics, it seems to be the case. The VCA only switches between external and internal, but other than that there's always some signal doing through as far as I can see. Am I wrong?

The self-oscillation filters out the input, so it's not a problem to get the sine if the digital implementation of the filter manages self-resonance in the first place.

@m1macrophage
Copy link
Contributor Author

Thanks for taking a closer look.

I'm quite surprised you can have zero input in the first place.

Yeah, it is a bit unexpected. Zero input is possible because of how waveform selection works. The waveform CV selects between "none", "triangle", "triangle + saw" and "saw" (note the switches drawn as open in the block diagram). The pulse waveform is controlled by a pulse-width CV, and is zero (well, constant) if PW is 0% or 100%.

So when the waveform CV is "none", PW CV is 0% (or 100%), and the external input is switched off, there will be zero AC to the filter.

That zero input + max resonance configuration is used as a sine oscillator, for some of the FM patches. Those are the ones currently not working.

The self-oscillation filters out the input, so it's not a problem to get the sine if the digital implementation of the filter manages self-resonance in the first place.

The existing implementation works well when there is an input, though it doesn't seem to cancel the input completely. This might be due to the resonance clamping I mentioned in the previous post.

It is the zero input configuration that does not work.

Removing resonance clamping (when the input is zero) seems to fix that. But It feels a bit more risky. Nonetheless, I could pursue this "no clamp" approach (with some more testing), instead of the "explicit sine oscillator" approach in this PR, and revisit if there are reported issues. Let me know if that's preferable.

@galibert
Copy link
Member

I don't think you should resonance-clamp, like, ever. There's no reason for it, I think...

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