sdatkinson / AudioDSPTools

A library of basic audio DSP tools
MIT License
27 stars 5 forks source link

[FEATURE] Alternative oversampling algorithms (low latency vs. low alias) #10

Open honkkis opened 5 months ago

honkkis commented 5 months ago

Problem The plugin now oversamples if the input signal is e.g., 48kHz and the capture is e.g., 192kHz. I appreciate that the oversampling algorithm was chosen to be the one with lowest latency, but the problem is that the current low-latency oversampling creates quite a lot of aliasing when compared e.g., to effect instance oversampling in Reaper. There seems to be a lot of spectral components over the nyquist limit (e.g., in case of 48kHz signal, the oversampling algorithm should not produce components that are over 24 kHz). As shown in the attached spectrogram, those components get folded back (aliased) to the produced output.

Proposed solution As an alternative (maybe user selectable), use an improved oversampling algorithm that does not produce higher frequency components that then get aliased back.

Additional context Sine sweep spectrogram, on top using Reaper's per plugin oversampling, below using NeuralAmpModeler oversampling.

Screenshot 2024-01-26 at 9 02 33

nam_plugin_oversampling

Screenshot 2024-01-26 at 9 00 52

olilarkin commented 5 months ago

The actual resampler used in Reaper is available in the WDL codebase that iPlug2/NAM plugin uses: https://github.com/iPlug2/iPlug2/blob/master/WDL/resample.h

In theory this should be useable for the resampling container and then there could be a setting to enable HQ mode. I couldn't work out how to use WDL_Resampler though.

But the current resampler might also be improvable for 192000 sampling rate models. It seems that this is a bit of an edge case right now though. If it really matters to you I suggest you try and get your hands dirty with the code!

I believe you might try changing the number 12 on this line to get a steeper antialiasing filter (but increase the latency): https://github.com/sdatkinson/NeuralAmpModelerPlugin/blob/51e151f1bf908d5709e082feacf603c607f241b4/NeuralAmpModeler/NeuralAmpModeler.h#L192

mikeoliphant commented 5 months ago

I don't think Reaper uses the WDL resampler anymore - they switched to using r8brain. Not sure they are doing real-time resampling, though, except for plugin upsampling (which is powers of two - so a simplified case).

olilarkin commented 5 months ago

r8brain is an option when rendering. don't know what they use for the plugin oversampling image

olilarkin commented 5 months ago

r8brain is an option when rendering. don't know what they use for the plugin oversampling image

honkkis commented 5 months ago

Thank you for the comments! I am C++ enabled, and willing to test different options to get rid of the aliasing here. Could somebody point me to a Mac OS readme on how to compile the plugin. I could not locate a README for that, but probably did not look hard enough.

sdatkinson commented 5 months ago

As the others said above, the place to get me an improvement on this first is for the ResamplingContainer class in AudioDSPTools, which uses a pair of open-source Lanczos filter resamplers.

If one wanted to use a different resampling algorithm, you'd drop it in there. (I quite like the "push/pull" interface that the algorithm uses!)

I'm going to transfer this issue over there since the discussion has centered around the algorithm. Pending the outcome over there, we can talk about the consequences for this plugin. I'm happy to swap out what's over here for something better, but I would rather keep it "optionless"--let's make sure it "just works" instead of adding options for the user.

honkkis commented 5 months ago

@sdatkinson I agree this feature belongs to this DSP project. I can volunteer to try to fix this, since I need it for myself :). I think we could add a multiplier to the filter params based on sampling freq. I would need a pointer to a README that describes how to compile this project and the plugin and run the compiled version on Mac OS, though. Such a document probably exists and I just cannot locate it.

sdatkinson commented 5 months ago

I would need a pointer to a README that describes how to compile this project and the plugin and run the compiled version on Mac OS

Actually, I'm not sure there's such a document--at least I never saw it 😅

To work in the context of NeuralAmpModelerPlugin, you would use XCode with the NeuralAmpModelerPlugin XCode workspace. If you're familiar with XCode, the rest is straightforward...If not, then you're like me and it may take just a little bit to get used to it 😅

honkkis commented 5 months ago

Thanks! Will try it. Might have questions later...

honkkis commented 4 months ago

Okay, got it to compile and I can run the compiled plugin. Some very bad readme started here: https://docs.google.com/document/d/1ONU9hWnotKkTL7M-3O0QkK7XXXjPqghA1PG2iW7mEbE/edit?usp=sharing

Unfortunately just changing the proposed line from 12 to 48 does not change anything. https://github.com/sdatkinson/NeuralAmpModelerPlugin/blob/51e151f1bf908d5709e082feacf603c607f241b4/NeuralAmpModeler/NeuralAmpModeler.h#L192

This is 48kHz project with 192kHz NAM profile. The last one is running with 48, middle is the original 12, and top is reaper oversampling. Any next suggestions? @olilarkin @mikeoliphant Screenshot 2024-02-03 at 17 56 54 Screenshot 2024-02-03 at 17 56 43 Screenshot 2024-02-03 at 17 56 32

olilarkin commented 4 months ago

I can write some instructions for how to compile it, and add it to the iPlug2OOS readme/wiki from where NAMPlugin originates. FYI: The setup-container.sh script is only for containerised development.

honkkis commented 4 months ago

Without running setup-container, the git submodules were not initialized, but I assume they can be initialized in some other way then.

Anyway, I also tried 512 in place of 12, unfortunately no change. Note that the alias artifacts are very clearly audible in sweeps but almost completely gone with reaper oversampling!

I have verified that the plugin I run is correct (the changed one) by modifying the plugin UI texts.

Screenshot 2024-02-03 at 18 22 17

Screenshot 2024-02-03 at 18 19 15

I have not looked at the DSP resampler code, but started to think whether the filter should be different in the upsampling path compared to the downsampling path. Maybe this is already taken into account in the code.

NOTE 3: How could we test this in isolation? Do we need the 192kHz NAM model I trained to produce the huge amount of nonlinearity or could we write a simpler test case and visualize results somehow?

honkkis commented 4 months ago

I think we need to add a low-pass filter before the downsampling step. E.g., if we downsample from 192k to 48k, we should low-pass at e.g., 23k before the resampling. This would remove the components that the non-linear amp model has created above the 24kHz nyquist limit.

Any suggestions on how to implement the low-pass filter here? I could test it.

honkkis commented 4 months ago

I think we fixed it @olilarkin @mikeoliphant ! Thanks for the pointer!

A simple filter fixes the aliasing problem quite dramatically already! https://github.com/sdatkinson/AudioDSPTools/pull/12 Please consider merging it or let me know if further work is needed for this patch!

For example, see here from up to down. 1) reaper 4x effects oversampling 2) original NAM 0.7.8 oversampling 3) This PULL request: input signal 48k -> upsample 192k -> NAM 192k -> lowpass 0.9*24k -> downsample 48k.

Screenshot 2024-02-04 at 12 37 25