FluidSynth / fluidsynth

Software synthesizer based on the SoundFont 2 specifications
https://www.fluidsynth.org
GNU Lesser General Public License v2.1
1.89k stars 259 forks source link

IIR filter: potential for producing clicks and cracks #1415

Open derselbst opened 1 month ago

derselbst commented 1 month ago

FluidSynth version

2.4.0 (recent master), 2.3.x is not affected, because it doesn't implement #1342

Describe the bug

Even though I have attempted to fix several clicks produced by the IIR filter on rapid fc changes in #1345 , there still seems to be a potential for clicks and cracks.

Expected behavior

Clean audio.

Steps to reproduce

  1. Checkout and compile recent master (or 2.4.0 when it's released)
  2. Grab the ZIP below
  3. fluidsynth -F render.wav -R 0 -C 0 "The Nervous Filter trimmed.mid" "GeneralUser GS v1.471.sf2"

The first 5 seconds of the MIDI are sufficient. The original untrimmed MIDI is provided as well. The click may be more audible when reverb is enabled.

Additional context

To my understanding, fluidsynth's implementation of the IIR filter is the result of an analog transformation of a 2nd order Butterworth filter into the z-domain. The exact cause of the clicks is currently unknown.

The Nervous Filter.zip

Screenshot_20241031_132723

klerg commented 4 weeks ago

Well, the clicks are quite obvious in this short The Nervous Filter trimmed.ogg

mrbumpy409 commented 3 weeks ago

IIR filters causing pops when modulated very quickly is a known issue. See here as an example. FluidSynth's filter seems to handle this better than most. Unfortunately, #1345 introduces audible distortions (as I reported in bug #1417).

In all of my SoundFont programming, I have only ever created very slight occasional pops on my most extreme presets (such as 008:038 Acid Bass in GeneralUser GS 2.0), and nothing that would really be perceivable in a mix. If NRPN control of filter cutoff is causing pops, you might want to incorporate "smoothing" logic to limit the speed at which a NRPN or modulator can increase/decrease the cutoff, though I would advise against also applying this smoothing logic to modulation from the modulation envelope, as this may mess with the sound of presets.

I worked recently with Ian Luck on updates to BASSMIDI, and he had incorporated a minimum filter movement speed to avoid pops in his own filter implementation. The pops in his filter were much easier to trigger than FluidSynth's, and his methods to avoid the pops caused many of the presets in GeneralUser GS to sound incorrect, particularly regarding the convex modulation attack envelope phase with short values. We were able to work out a compromise (cheating the mod envelope attack curve in some cases), but FluidSynth never needed such a compromise in my testing.

Beyond smoothing, I understand there are different filter algorithms that can be used to avoid popping, but I'm guessing that may also change the sound of the filter a bit. Personally, I love the sound of FluidSynth's filter, so I hope that never regresses.

ReinholdH commented 3 weeks ago

I can confirm the distortions of the sample of #1417 and the cracking of the sample "The Nervous Filter trimmed.mid" with fluidsynth-2.4.0 which is very obvious. fluidsynth-2.3.7 is OK for all these samples.

derselbst commented 3 weeks ago

Thanks for the input Chris.

the cracking of the sample "The Nervous Filter trimmed.mid" with fluidsynth-2.4.0 which is very obvious. fluidsynth-2.3.7 is OK for all these samples

2.3.7 doesn't use NRPNs to manipulate the filter whereas 2.4.0 does, so that's unrelated.

klerg commented 3 weeks ago

I did not know that the "IIR" filter is known to make noises when it is fast modulated. Yes, Fluidsynth does sound very well compared to other filters of this type, I just had time to look at this and it looks like a bug for sure.

It is the same way for me only what you call "extreme" presets like Acid Bass or something along those lines give any clicks or pops but it is hardly audible and as such is not really an issue to bring up at all then. This is very good advice and had no clue the NRPN control of the filter cutoff can be "smoothed" although not sure how this is going to effect the sound of the filter in the long run. Good point, if the "smoothing" cannot work with modulation then I wonder if anything can be done for the Mod Env or it must be left alone it looks like.

That is very nice to hear you worked with the dev of BASSMIDI, yes will need to check out the new BASSMIDI when it comes out in any new music player or software. Well, I have no clue why the noise is easier to spot in BASSMIDI than FluidSynth. And I cannot begin to guess what was used to get rid of the clicks and cracks but glad it worked out in the end somehow. And I have no idea what is meant by "convex" in the modulation envelope. Again, no clue how you were able to "cheat" the mod envelope attack but hope it did not result in a sound that bypasses the modulation envelope effect. And it is very interesting to note that FluidSynth has no need for any of this compromise or workaround.

I hope FluidSynth will try "smoothing" but yes I wonder what filter design is used in BASSMIDI if is not an IIR. Sure, but if no more clicks and cracks it may not be such a big deal. Same here it has a odd quality to it, and know it cannot sound any worse.

mrbumpy409 commented 2 weeks ago

I had noticed that the latest filter changes in the iir-tests branch made the clicks in GeneralUser GS preset 008:038 Acid Bass (shared above) worse, so I decided to investigate. Turns out the clicks in that preset were not caused by filter cutoff changes at all, but the voice on note release was being killed while the filter was still resonating. I filed a separate bug report here: #1427

So, this means that I have yet to be able to cause any pops or clicks via envelope modulation of the filter (with the old code), even when using very short attack or decay values. The note release clicks got worse with the iir-tests changes because those changes put a speed limit on the envelope's filter cutoff modulation. The Acid Bass preset drops the filter cutoff very quickly on note release, but this doesn't happen as fast with iir-tests, which leaves the filter cutoff at a higher frequency when the voice is killed. This just so happens to result in a higher sound level remaining in the filter when the voice is killed.

Sorry if I'm butchering any terminology here. 😆

mrbumpy409 commented 2 weeks ago

I have been testing the current iir-tests branch with the new smoothing algorithm, and everything seems to be working pretty well with the modulation envelope. I can measure that the envelope isn't quite as fast as it was previously at low phase times, but it is still so quick that I think it would be hard or maybe even impossible for most people to tell the difference in actual presets. As a preset designer, there are a few cases where I can kind-of tell, but I have yet to find it to be to the detriment of the preset's sound, and I would imagine there are very few presets that use such short values expecting an immediate "snap" to a new filter position. As long as the smoothing isn't made any slower, I think it should be fine.

One could possibly make an argument for keeping the old interpolation logic when using the modulation envelope and using the new logic for other modulation sources. The old logic never seemed to result in pops for the modulation envelope (although there probably had to be some way of getting it to happen), and was technically a more accurate rendering of the short envelope values encoded in the SoundFont. However, this might be in splitting hairs territory, and would surely create more complexity within FluidSynth's code for likely little gain.

I'd like to hear others' thoughts on this, but I can't say I am unhappy with the compromise.

derselbst commented 2 weeks ago

Thanks for looking into this Christian, I hope to find more time coming back to this on this weekend. Sorry if I'm biasing anybody's opinion here, but there are a few things that I would like to comment on:

The old logic never seemed to result in pops for the modulation envelope [...] and was technically a more accurate rendering of the short envelope values encoded in the SoundFont

The previous linear smoothing of the filter coefficients is broken mathematically: The coefficients are very sensitive to quantization errors and they must always change in a sinusoidal way. There is no chance for the filter to remain a stable state when the coefficients are smoothed individually in a linear way. I have also discussed this with one of my colleagues, who himself very much into integrals and mathematics in general, and before I explained my (new) approach, he instantly said "what you want to smooth out are the filter parameters (=fc and Q), but not the coefficients". The only thing that is truly surprising here, is that this broken logic was working pretty well in practice. Yet, I must really reject the claim, that the old logic was "more accurate" in any way.

Btw, the previous linear smoothing of the filter coefficients also introduced hard a delay of 64 samples (=FLUID_BUFSIZE) for the filter to change its state.

The smoothing logic that I'm now using (as of 7c3dcf7d851262314ef590cbf297cedefc2a8c37) makes the "smoothing speed" dependent on Q, where it can go up to 8 * 64 samples. It should at least have 64 samples - as before - but generally, I'm open to change this. The intention behind this approach here is with higher values of Q the filter's phase gets steeper, so a slower change of fc is desired (=longer smoothing delay). Yet, I agree that this delay should be kept as short as possible. I'll need to better understand if or how this smoothing correlates with your recent finding in #1427.

mrbumpy409 commented 2 weeks ago

Yet, I must really reject the claim, that the old logic was "more accurate" in any way.

I only meant that super short mod envelope attack/decay/release values measured slightly shorter / less ramped in my tests under the old logic, but I am not bothered by this, personally, and I can't really tell the difference in real-world presets. Here is what 0.01 sec mod envelope attack + 40 dB filter Q looks like compared between the old logic (top) and new logic (bottom): image

Each tick in the time ruler above is 0.05 seconds, so you can see that the old logic's attack finishes closer to the indicated 0.01 seconds than the new logic.

I'll need to better understand if or how this smoothing correlates with your recent finding in #1427.

I don't think there is any correlation. It is only by coincidence that the new logic made the note-off popping more consistent to produce in GeneralUser GS preset 008:038 Acid Bass, not because of anything wrong with the new smoothing logic. (The smoothing changes where the cutoff frequency last sits after note release compared to the old logic.)

mrbumpy409 commented 2 weeks ago

@derselbst Just letting you know that I edited the above comment with a visual comparison and further notes.