prof-spock / FluidSynthPlugin

Simple Wrappers Around the FluidSynth Library as DAW Plugin and Pedantic Command Line Processor
5 stars 0 forks source link

Allow Setting of the Sample Interpolation Method #4

Closed prof-spock closed 5 months ago

prof-spock commented 5 months ago

mrbumpy409 wrote in issue #2:

_FluidSynth allows setting the sample interpolation method per midi channel via fluid_synth_set_interpmethod() (API link). Normally this can be accessed via the FluidSynth console commands, but there doesn't appear to be a setting for it (e.g., "settings.interp"). So, I'm not sure if it would be possible to add support for this feature to the plugin, but if so, it would be nice to be able to select the highest sample interpolation (7th order) rather than the default (4th order) to avoid aliasing artifacts in some cases. Is this something that would be feasible?

prof-spock commented 5 months ago

Hello @mrbumpy409,

I have implemented the change via an artificial parameter synth.interpolation-method with values 0 (for none), 1 (for linear), 4 (for fourth-order) and 7 (for seventh-order).

Null-testing via the test project (from the repository) against the external fluidsynth rendering - which is fourth-order - is a bit disappointing: the difference from none in the DAW to fourth order by fluidsynth is about -90dB and the difference between seventh order in the DAW to fourth order by fluidsynth is about -85dB (see enclosed figures).

InterpolationMethod-settings Figure 1: Setting the interpolation method

NoneVsFourthOrder Figure 2: No Interpolation in DAW vs. Fourth Order Interpolation in External Fluidsynth

SeventhOrderVsFourthOrder Figure 3: Seventh Order Interpolation in DAW vs. Fourth Order Interpolation in External Fluidsynth

This test might be biased, because the instrument is an electric bass with a limited high frequency spectrum. But in my opinion the differences between all those interpolation methods are inaudible unless you have very subtle soundfonts with significant high frequency content.

You can find all the changes on branch sampleInterpolation.

I am looking forward to hearing your opinion and also test results...

Best regards, Prof. Spock

mrbumpy409 commented 5 months ago

With the new synth.interpolation-method specified in the plugin parameters, I get a 1 in 5 chance of the plugin crashing REAPER upon hitting "confirm" in both Linux and Windows (either when initializing the plugin or changing its settings later). If I don't include that parameter, I do not have any stability issues. In case it matters, I am compiling using the libraries included with the latest FluidSynth release (v2.3.4).

When the plugin crashes REAPER, a 0 KB FluidSynthPlugin.log file is left. By running the plugin in a separate process (right-click on plugin name in the "add fx" window → Run as → Separate process), when the plugin crashes, it no longer brings down REAPER and creates a log file, which is attached to this bug report.

The attached log file was created by adding FluidSynthPlugin to a track, adding the following settings, and clicking "confirm", leading to an immediate crash:

soundfont = ${SCCSamples}/SoundFonts/Fluidity/work/instruments/keyboard/FM Electric Piano/Fluidity FM EP 6.sf2
program = 000:005

synth.gain = 1.0

synth.reverb.active = 1
synth.reverb.damp = 0.3
synth.reverb.level = 0.7
synth.reverb.room-size = 0.5
synth.reverb.width = 0.8

synth.chorus.active = 1
synth.chorus.depth = 3.6
synth.chorus.level = 0.5
synth.chorus.nr = 4
synth.chorus.speed = 0.36

synth.interpolation-method = 7

Beyond that, the new interpolation settings work great and do make a big difference. I'll try to work through the crashes to get some good comparison audio for you.

mrbumpy409 commented 5 months ago

One other thing I should add: I have had previous versions of the plugin crash on me, but those crashes were much rarer. However, those crashes had the same behavior, bringing down REAPER upon hitting "confirm". This makes me wonder if there is some timing issue on synth initialization that is exacerbated when the new interpolation setting is used.

prof-spock commented 5 months ago

Hello @mrbumpy409,

that's unfortunate, I'll have to investigate that.

My first working hypothesis is that since the synthesizer object is recreated for some of the settings (for synth.verbose, synth.interpolation-method and synth.sample-rate), this might lead to a problem when the synthesizer is not fully initialized and gets some API calls. So timing issues could be a good assumption.

On the other hand all calls to the FluidSynth API are fully synchronous (and also using the so-called "thread-safe API"), so I do not see why there should be problems.

Anyway: I'll find out.

Best regards, Prof. Spock

DaforLynx commented 5 months ago

I thought this was already possible using the interp command? At least, I can tell the plugin interp 0 and it works. I haven't tried higher order interpolation but it's really hard to tell the difference with those.

mrbumpy409 commented 5 months ago

I thought this was already possible using the interp command? At least, I can tell the plugin interp 0 and it works. I haven't tried higher order interpolation but it's really hard to tell the difference with those.

How are you inputting this? If I add interp 0 into the text box with either the current or previous plugin version, nothing changes, at least in my time live auditioning via MIDI keyboard. I haven't tried rendering.

mrbumpy409 commented 5 months ago

@prof-spock Interestingly, the complexity of the SoundFont seems to have some bearing on whether setting synth.interpolation-method will crash the plugin. When loading simple SoundFonts, I at least sometimes have success changing the interpolation method, but when loading something like GeneralUser GS containing lots of presets, it crashes every time.

DaforLynx commented 5 months ago

@mrbumpy409 Ok, this is exceedingly strange. It was working just a month ago. Then I updated the plugin last week and didn't try it again until now. You can hear it working in my piece here. So whatever was done in the latest update stopped it from working...

mrbumpy409 commented 5 months ago

Interesting. I can definitely hear the lack of sample interpolation in that track. Looks like at one point the plugin was passing unrecognized commands through to the FluidSynth terminal? Cool track, BTW! Makes me nostalgic for some tracker music. :D

prof-spock commented 5 months ago

Dear all,

@DaforLynx wrote:

[interp 0 had worked in some previous version of the FluidSynthPlugin]

Well, this sounds completely strange to me.

First of all: interp 0 should not work nor has it ever worked in previous versions of the plugin. There is a list of accepted "keywords" and this is documented in the official plugin documentation.

Any other keyword should be rejected. That rejection does not work in all cases, but I have corrected the bug in the upcoming version. Nevertheless even though there is no error message, "interp 0" is not handed over to the fluidsynth API.

Even if it were, the fluidsynth library would also in my opinion not recognize that keyword (see the code in fluid_synth.c).

Are you sure that the rendering of your song has been done by the FluidSynthPlugin and not by the fluidsynth command-line program?

@mrbumpy409 wrote:

the complexity of the SoundFont seems to have some bearing on whether setting synth.interpolation-method will crash the plugin

That seems plausible and substantiates your hypothesis about the timing issue. I'll have a look into that: a reproducible test case is very helpful.

Best regards, Prof. Spock

DaforLynx commented 5 months ago

@prof-spock I am absolutely certain I rendered it using FluidSynthPlugin instances. I checked the project file to be sure, and indeed I had the text box saying:

soundfont = "C:\Users\...soundfont.sf2" (not showing the whole path here)
synth.reverb.level = 0.0
synth.gain = 1.0
interp 0
program = 0:2

And regarding:

the fluidsynth library would also in my opinion not recognize that keyword

I have a batch file which opens fluidsynth in command prompt with the -f "config.txt" argument, with the config file reading:

interp 0
prog 0 0

which just inputs those commands into the fluidsynth runtime right after loading. I'm using Fluidsynth version 2.3.3. I figured FluidSynthPlugin just hosts a runtime of the Fluidsynth console, and I thought I was correct until now.

DaforLynx commented 5 months ago

Just to test, I replaced the plugin with the older version which I still had in my downloads, and voila, the interp 0 thing works again.

prof-spock commented 5 months ago

Hello @DaforLynx,

thanks for your clarification!

I am absolutely certain I rendered it using FluidSynthPlugin instances. I checked the project file to be sure, and indeed I had the text box saying: soundfont = "C:\Users...soundfont.sf2" (not showing the whole path here) synth.reverb.level = 0.0 synth.gain = 1.0 interp 0 program = 0:2

Nevertheless you leave me completely baffled. The above settings should work, but they should not select a different interpolation method ("interp 0" is simply ignored and the default fourth-order interpolation is done).

Maybe you use an older version of fluidsynth which allows that? But I am very surprised that the FluidSynth library used by the FluidSynthPlugin should understand the "interp 0" as a setting.

I checked the current API documentation and the source code for version 2.3.4 of the FluidSynth library: it does not know the "interp" settings string (at least not in the settings module). It might be undocumented there, of course, but if they offer it: why not document it?

And to be fair, the library contains a command line module, which mimics the command line of a fluidsynth program; but I am not using that.

I have a batch file which opens fluidsynth in command prompt with the -f "config.txt" argument, with the config file reading: interp 0 prog 0 0

Well, things are completely different when you are using the command line version of fluidsynth itself. Here the settings are further interpreted before being fed to the settings module and clearly there is a handler for "interp" that calls the function fluid_synth_set_interp_method.

So the latter does not at all surprise me. But the former surprises me: by magic your "interp 0" gets through to the settings module and effectively changes something. I'll have to check with the FluidSynth people.

Anyway, now I have used the "official" way to select the sample interpolation method; I just have to iron out the instabilities...

Best regards, Prof. Spock

prof-spock commented 5 months ago

Hello @mrbumpy409,

sorry, you're - as always - the guinea pig :wink:

The branch sampleInterpolation contains a fix for the crash tendency and hopefully for the missing update of the editor after loading a preset.

I do not get crashes any longer, but your mileage may vary.

The first one was fixed by introducing a gatekeeper, such that nobody uses the synthesizer while we are tinkering with its parameters in the editor or even recreating it. The second one was an omission: I had stored presets, but never used them 😞

Could you kindly have a look on that?

Best regards, Prof. Spock

mrbumpy409 commented 5 months ago

The latest code has eliminated the crashes. I have yet to encounter a single issue. :grin:

I made an interpolation comparison test, which you can download here. The download contains audio of the same project rendered with the four different interpolation methods. In the audio, you will hear:

  1. High chromatic notes on Fluidity FM electric piano — There is a bit of high frequency aliasing and the highest two notes have a pronounced subharmonic "clunk". Both of these artifacts are greatly reduced when 7th order interpolation is used.
  2. GeneralUser GS Percussive Organ — Low bitrate samples have lots of high frequency aliasing at 4th order and below.
  3. GeneralUser GS Orchestra Hit — Low bitrate samples have lots of high frequency aliasing at 4th order and below.
  4. GeneralUser GS Timpani — Low bitrate samples have lots of high frequency aliasing at 4th order and below.

Thank you so much for implementing this feature, Prof, and for all the time you've spent working out the bugs! I am very grateful. :smile:

prof-spock commented 5 months ago

Hello @mrbumpy409,

some differences between the interpolation methods I guess you have golden ears 😉

I am more visual/analytical guy and merely check the spectrum. But you are absolutely right: in principle one has to look at the frequency distribution over time (a three-dimensional function) to detect the artifacts you describe.

Thank you so much for implementing this feature, Prof, and for all the time you've spent working out the bugs! I am very grateful.

It's been a pleasure. I am so grateful that somebody is using my plugin. And this person is not just somebody, but the grandmaster of soundfonts...

So any time spent on this is well spent 😄

Unless you find any bugs/crashes in the next few days related to the interpolation method, I'll close the current issue ...

Best regards, Prof. Spock

prof-spock commented 5 months ago

included in release 0.6