Saturation Models (Neve, Tweaker, Oxford Inflator) in FAUST
-
@Morphoice how did you arrive at these values/algorithms?
-
The Inflator yes, is a completely a linear transfer function, split into 3 bands.
You can create programs to measure and derive the transfer functions. -
Thank you for sharing these!
the inflator algorithm looks a lil bit weird, i think it should be like this:
a1=1+(curve+50)/100
a2=curve/50
a3=(curve-50)/100
a4=0.0625-curve/400+curve^2/40000x=a1・x+a2・x^2+a3・x^3-a4・(x^2-2・x^3+x^4)
the curve value should be in the range of -50 to 50 but you could intentionally set it to somewhere over 50 to achieve some weird distortion effect.
also, the inflator is mainly control by input gain and curve so you may need to add a input gain by doing something like:
x=x0・preGain
(the effect param in the original plugin is actually a little bit misleading, it's just a dry wet mix and seems like it was only designed to be set to 100% or 0% to make it sounds "natural")
I'm sure several inflator clone use this algorithm and with linear phase oversampling it somehow even sounds better then the original one :)
-
I’m a simple person—I like loudness!
I’ve been experimenting with an inflator-like idea these past few days, and here’s the code I came up with:
declare name "Inflator-like test1)"; import("stdfaust.lib"); // Interface input_slider = hslider("Input (dB)", 0, -6, 12, 0.01); effect_slider = hslider("Effect (%)", 0, 0, 100, 0.1); curve_slider = hslider("Curve", 0, -50, 50, 0.1); clip_slider = checkbox("Clip 0 dB"); band_split_slider = checkbox("Band Split"); effect_in_slider = checkbox("Effect In"); output_slider = hslider("Output (dB)", 0, -12, 0, 0.01); // Utility functions clamp(x, minv, maxv) = min(maxv, max(minv, x)); sign(x) = (x > 0) - (x < 0); // Convert UI values to processing parameters pre = input_slider : ba.db2linear; post = output_slider : ba.db2linear; wet = effect_slider * 0.01 * 0.99999955296; dry = 1 - (effect_slider * 0.01); // Curve coefficients A = (curve_slider * 0.01 + 1.5); B = (curve_slider * -0.02); C = (curve_slider * 0.01 - 0.5); D = (0.0625 - curve_slider * 0.0025 + (curve_slider * curve_slider) * 0.000025); // SVF Filter implementation svf_coefficient(cutoff) = tan(ma.PI * (cutoff/ma.SR - 0.25)) * 0.5 + 0.5; svf_lpf(cutoff) = _ : fi.tf2(b0, b1, b2, a1, a2) with { c = svf_coefficient(cutoff); b0 = c * c; b1 = 2 * b0; b2 = b0; a1 = 2 * (b0 - 1); a2 = 1 - 2 * c + b0; }; svf_hpf(cutoff) = _ : fi.tf2(b0, b1, b2, a1, a2) with { c = svf_coefficient(cutoff); b0 = 1; b1 = -2; b2 = 1; a1 = 2 * (c * c - 1); a2 = 1 - 2 * c + c * c; }; // Band splitting with integrated gain calculation band_split(x) = low, (mid * mid_gain), high with { low_cutoff = 240; high_cutoff = 2400; c_low = svf_coefficient(low_cutoff); c_high = svf_coefficient(high_cutoff); mid_gain = c_high * (1 - c_low) / (c_high - c_low); low = x : svf_lpf(low_cutoff); high = x : svf_hpf(high_cutoff); mid = x - low - high; }; // Waveshaping function waveshaper(x) = select2(abs(x) < 1, select2(abs(x) < 2, x, // > 2 (2 * abs(x) - abs(x) * abs(x)) * sign(x)), // 1 < x < 2 (A * abs(x) + B * (abs(x) * abs(x)) + C * abs(x) * (abs(x) * abs(x)) - D * ((abs(x) * abs(x)) - 2 * (abs(x) * abs(x)) * abs(x) + (abs(x) * abs(x) * abs(x) * abs(x)))) * sign(x)) // x < 1 * wet + x * dry; // Main processing function process = par(i, 2, channel_process) with { channel_process(x) = x : input_stage : effect_stage : output_stage; input_stage(x) = x * pre <: select2(clip_slider, clamp(_, -2, 2), clamp(_, -1, 1)); effect_stage(x) = select2(effect_in_slider, x, select2(band_split_slider, waveshaper(x), band_split_process(x))); band_split_process(x) = band_split(x) : (waveshaper, waveshaper, waveshaper) :> _; output_stage(x) = select2(abs(x) < 0.0000000000000000555111512312578270211815834045, x * post, 0); };
-
@Mighty23 looks complicated but sounds nice as far as I can tell. just the band split does nothing
-
@Morphoice
abs(x) < 0.0000000000000000555111512312578270211815834045
hum seems like a non human intervention here ?
-
@sletz
Yes, it's not just a non-human intervention—it's a lifesaving one :)I’ve been dealing with crashes, and after investigating, I realized I need denormal protection. I received several suggestions and implemented the one that made the most intuitive sense to me—though perhaps I’m falling into some cognitive biases?
How can I test for denormal issues?
Can you explain real-world methods for denormal protection? -
We have tools to help debugging, read:
https://faustdoc.grame.fr/manual/debugging/#debugging-at-runtime
https://faustdoc.grame.fr/tutorials/debugging/This interp-tracer tool is currently to be used in the terminal, so requires a local installation. But in theory this kind of tool could be integrated in HISE , since the libfaust library used in HISE also embeds the needed Interpreter backend.
For more local NAN protection, using ma.EPSILON is a more portable solution, since is adapts the single/double compilation option.
-
@Mighty23
Nice work!
For the band split, you may want to use the linkwitz riley instead of svf.About the denormal protection, may I know what CPU you're are running this code on? Does this directly cause the crashing?
This might be useful for some legacy CPUs and it won't likely really be a problem for modern x64 CPU afaik. -
@Mighty23 Very interesting, and thank you for sharing. Am I correct that this is multiband distortion, or is there also some dynamics processing as well?
-
@Morphoice Thank you for sharing. Not a whacking, but I work with two of these companies; could I ask you to pls characterise these as more "…in the spirit of…" and not "…copies of…"?
-
@Allen I assume nobody is here posting actual transfer functions they measured.
-
@clevername27 said in Saturation Models (Neve, Tweaker, Oxford Inflator) in FAUST:
or is there also some dynamics processing as well?
there is no compressor/limiter/gate in the processing. I would consider it 100% multiband waveshaping.
@Allen said in Saturation Models (Neve, Tweaker, Oxford Inflator) in FAUST:
For the band split, you may want to use the linkwitz riley instead of svf.
Yes, for sure. Many Thanks.
@Allen said in Saturation Models (Neve, Tweaker, Oxford Inflator) in FAUST:
may I know what CPU you're are running this code on?
10510u i7 on Windows
Late 2016 Mini Mac overclocked and open-core operating system. -
@clevername27 they're not measured, someone on reddit reverse enginered them so they are somewhat common knowledge among the DSP community, I'm not claiming any of those is a copy of something, it's just knowledge I gathered off the web. This is an old post though, I'm making my own functions for saturation now, and I'm using desmos to create them, closely matching stuff I can indeed measure from real hardware and then bring them over in faust. Unfortunately it's all done by hand, I have no Idea on how to "automatically" transfer measurements into transfer functions. It's a lot of guesswork until the curve looks somewhat similar
Those are the two waveshaper curves I find most pleasing, sonically, anything in between those is great and much faster calculated than the popular tanh for saturation
-
@Morphoice Thank you for sharing.
-
If you want to find the functions automatically it's not that hard I can show you. It can be done with python or MATLAB very easily.
You'll quicky discover that a static waveshaper cannot represent the measurements of analog distortion, but you can however create the 'best fit' automatically.
-
@griffinboy it's probably a good idea to morph between waveshaping curves according to signal strength but then again here we are considering hysteresis again ;)
-
yeah no, morphing a waveshaper based on signal strength doesn't really have much effect unless it has memory or smoothing. Else you've just done a static transformation of the curve and created another static curve. It has to have memory / hysteresis to actually represent anything nonlinear.
But collecting transfer function data from analog devices can still be super useful and can inform approximations.
-
@Morphoice Where can I learn how to apply this? Maybe you can tell me what this is and I can do y research. Thanks brotha.