FluidSynth / fluidsynth

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

volume envelope delay is not to spec #1312

Open mrbumpy409 opened 3 months ago

mrbumpy409 commented 3 months ago

FluidSynth's volume envelope delay does not behave according to the SoundFont specification. Currently, FluidSynth starts sample playback at the start of the attack phase rather than the start of the envelope generator. Section 9.1.7 of the SoundFont 2.04 specification defines the envelope generator as such:

[...] An envelope generates a control signal in six phases. When key-on occurs, a delay period begins during which the envelope value is zero. The envelope then rises in a convex curve to a value of one during the attack phase. [...]

Nowhere in the document is it suggested that sample playback should start at the attack phase, and as far as I have seen, only FluidSynth behaves in this manner. In every other SoundFont synth I have tried (including Sound Blaster hardware and also other sampler formats such as SFZ), the sample is actually silently playing during the volume envelope's delay phase.

Now, here is where I have to caveat that I actually prefer FluidSynth's method here, as I have wished for the envelope delay to actually delay the start of sample playback since I started building SoundFonts back in the late '90s. From a sound design perspective, it actually makes more sense to do it this way. How often do I want to delay a sound and lose the start of the sample at the same time? If it weren't for that darned compatibility factor, I'd argue in favor of keeping things as-is. In fact, I'm kind of hating myself right now for reporting this! :laughing:

Here is an audio comparison of a legacy preset that becomes problematic with FluidSynth's delay method, the Roland GS preset 008:014 Church Bells, here demonstrated using GeneralUser GS. The sound you hear is a single press of the note C4. Sobanth plays this correctly, with each of the subsequent echoing bells quieter and more mellow due to the attack phase occurring later in the bell waveform. On Fluidsynth, you clearly hear each bell hit identically as each voice's attack phase is starting at the beginning of the sample.

The preset could be reprogrammed to sound more natural in FluidSynth, but that would break the playback in all other SoundFont synths. And this is the reason why—as much as it pains me to say it—we should consider changing the delay envelope behavior to match the spec.

Thoughts?

FluidSynth version

Any, as far as I know.

derselbst commented 3 months ago

An excellent finding Christian! I was already afraid your report will cause me days of headache. But after a quick look in the code things are looking quite simple: When a voice is processed and found to be in delay, it will trigger this if clause:

https://github.com/FluidSynth/fluidsynth/blob/db86c36bca6a14d661f23adf913abf52708dff73/src/rvoice/fluid_rvoice.c#L36-L39

And the -1 will cause an early return here, i.e. without updating the voice's dsp and related params down below:

https://github.com/FluidSynth/fluidsynth/blob/db86c36bca6a14d661f23adf913abf52708dff73/src/rvoice/fluid_rvoice.c#L356-L360

So I'd guess all we need to do is to move that early return down a bit. How far down? I'd guess right before the switch case with the interpolation calls would be fine?

Doing so would mean there's no more a way to truly delay the sample in the soundfont itself. Other than delaying the noteOn. I agree that is limiting musically freedom and might be questionable. But if the spec says so ;)