Soft Clipping Algorithm

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS
I wanted to run the final output of my synth through a soft clipping algorithm so that its output never exceeds the range [-1,1]. I came up with the algorithm below. It seems to work ok. However, I tend to distrust algorithms I come up with on my own from first principles, so thought I'd run it by here. And of course suggestions for a better approach are appreciated as always.

Code: Select all

``````
// Insider the "tight loop."

if(*leftIn > Threshold)
{
x = Threshold / *leftIn;
*leftOut = (1.0f - x) * (1.0f - Threshold) + Threshold;
}
else if(*leftIn < -Threshold)
{
x = -Threshold / *leftIn;
*leftOut = -((1.0f - x) * (1.0f - Threshold) + Threshold);
}
else
{
*leftOut = *leftIn;
}
``````
I'm just showing the left channel for bevity's sake. Threshold is any value in the range of [0,1]. The algorithm works as follows:

Code: Select all

``````If the input is greater than the threshold.
Divide threshold by the input.
Multiply the inverted result by the inverted threshold.
Assign result to output.

Else if the input is less than negative threshold.
Divide negative threshold by the input.
Multiply the inverted result by the inverted threshold.
Make the result negative.
Assign result to output

Else
``````
Last edited by Leslie Sanford on Sat Oct 20, 2007 8:35 am, edited 2 times in total.

Leslie Sanford wrote:I tend to distrust algorithms I come up with on my own from first principles

well, for sure. i think scripted languages tend to make you self-distrusting by necessity..

you could set it up in synthedit in 30 seconds and view the results on a scope
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Dunno, for soft clip, I hard clip, then use a polynomial to smooth the transition between non clipped and clipped:

Code: Select all

``````if (input > 1)
input = 1;
if (input < -1)
input = -1;
input = 1.5 * input - 0.5 * input * input * input; // Simple f(x) = 1.5x - 0.5x^3 waveshaper
``````

The f(x) = 1.5x - 0.5x^3 waveshaper is chosen so that the derivate of f(x) is 0 at points where hard clipping sets in. In mathematical terms, f'(1) = 0 and f'(-1) = 0. It will also have the side effect of having a gain of roughly 1.5 in non distorted parts.

MadBrain wrote:Dunno, for soft clip, I hard clip, then use a polynomial to smooth the transition between non clipped and clipped
I think thats what most people do. Btw there's a neat trick for doing the hard clip without conditionals..

out = 0.5 * (abs(in + clip) - abs(in - clip));

It's an interesting one.

I looked at saving you some cycles, check my critical path to make sure I didn't screw up...

Code: Select all

``````out=(1-x) * (1-T) +T

x=T/In

out=(1-T/In) * (1-T) + T

= In - T
-------- * 1-T   + T
In

= (In-T)(1-T)
---------------  + T
In

= In - InT - T + T^2  + T
--------------------
In

= In - InT - T + T^2  + TIn
--------------------------
In

= In - T + T^2
------------
In``````
Notice that (-T + T^2) is a constant, so per sample you get a add and a divide, which is less costly than an div, two subs, a mult and an add

I'll have to run that one thru excel to have a look at the shape!

Must confess, my favourite is ripped out of stephancr's Beaver Tracker from a number of years ago. It's a simple thing, a few mults and adds with a divide, but works a treat. Unity comes at at -2.? dB, nothing goes higher than 0dB. It's been really handy with EQ22 and Duckling compressor, both of which internally can push the outputs to +36dB and beyond, but stephs code just nicely shapes it down again. The really high vales (5+ in amp) curve down below what would be a unity output, but no-ones counting!

ATB
DSP

[NB did some editting on a horrendous error in the proof, which turned out to eliminate an add - hoorah!

Also, just looked at it in Excel - not bad at all. Don't but Threshold below 0.5, or you'll get an expansion effect, also anything above about 0.65 and you get a really sudden transition into the compressed region. At most values of T, unity seems to come out in the -2.5->-1dB region which is quite acceptable

To get rid of the sign check, use a bit mask to save the sign bit, and then do the shaper as if +ve, and or the sign bit on again.

eg if using single precision
tmpsgn = in and 0x80000000
in = in and 0x7FFFFFFF
out = shape(in)
out = out or tmpsgn

]

OK, got me sold, I'm using this in my next project.

Been playing in Excel.. even putting 1000(amp) into it doesn't break 1, so I'm guessing it asymptotic there. I suppose I could sit down and solve 0=T(T-1) to be sure what's going on, but I need to go to bed!

But for an add and a divide after a branch [which can be checked by integer arithmetic on the raw IEEE754 value and bypass FPU entirely], it's the cheapest waveshaper I know, and it's good on paper.

I'll probably set T at 0.75 for unity returning at -2.05dB, and a smoothish transition into the compressed zone.

Thx Leslie!

DSP

Leslie Sanford wrote:I wanted to run the final output of my synth through a soft clipping algorithm so that its output never exceeds the range [-1,1].
Hi Leslie,

important is to decide whether your goal is to:

1) make sure that your output never exceeds [-1,1], while preserving the sound that you put into it as much as possible;

OR:

2) get the actual sound of a soft-clipping algorithm.

These are two entirely different things, and need two different solutions!

If it is goal 1 you're after (limiting to [-1,1] while preserving sound) then what you need is a limiter: something that adjusts its gain according to what it gets fed, so that the output level gets limited to [-1,1].

If, on the other hand, it is goal 2, the actual sound of soft-clipping that you're after (because soft-clipping *will* change the sound, since it's a distortion technique) then you need a distortion algorithm. You may want to check out this (mind the red curve):

Source: http://en.wikipedia.org/wiki/Inverse_tr ... c_function

This function, y = arctan(x), soft-clips to [-pi/2,pi/2], so you would have to multiply the output by 2/pi to get [-1,1]. I guess most programming languages will have the arctan function as one of their native functions!

With regards to CPU usage of the arctan function: you would need to test whether it's acceptable. Hopefully/probably any modern CPU (which will typically have an FPU on board to handle floating point operations) will handle it pretty quickly.

Regards,

Heeb.

I'm no coder but you might like to try the function at the top of the Wikipedia page on the Sigmoid Function at http://en.wikipedia.org/wiki/Sigmoid_function

I've been using it in Bidule and it works a treat.

duncanparsons wrote: Thx Leslie!
You're welcome! And thank you for analyzing it for me. I appreciate the optimizations you discovered. I'm glad I posted it.

heeb wrote: important is to decide whether your goal is to:

1) make sure that your output never exceeds [-1,1], while preserving the sound that you put into it as much as possible;

OR:

2) get the actual sound of a soft-clipping algorithm.

These are two entirely different things, and need two different solutions!
That's an important point. Thanks for making this distinction for me.

Here's an example of the algorithm in action:

PowerChord

Threshold set at 67%.

PowerChord am fat. Sound good.

Leslie Sanford wrote:
heeb wrote: important is to decide whether your goal is to:

1) make sure that your output never exceeds [-1,1], while preserving the sound that you put into it as much as possible;

OR:

2) get the actual sound of a soft-clipping algorithm.

These are two entirely different things, and need two different solutions!
That's an important point. Thanks for making this distinction for me.
Another point is that even if you just want clipping and not limiting, the "softer" the clipper is, the more you will notice it saturating the sound. So for such a purpose, I think that maybe using a "quite hard" clipper would be a better idea. Maybe.

OTOH, why do you want to clip/limit the output of your synth? I sometimes do, but when I do, I see it as, well, part of the synths / effects character. The "clean" route is to leave the output alone, imho
Stefan H Singer
Musician, coder and co-founder of We made you look Web agency

stefancrs wrote: OTOH, why do you want to clip/limit the output of your synth? I sometimes do, but when I do, I see it as, well, part of the synths / effects character. The "clean" route is to leave the output alone, imho
If its going straight to the soundcard then it'd probably be better to clip than to allow wrap round distortion.

If it's a VST plugin then you should let the host deal with it.

imo

Agreed.
Stefan H Singer
Musician, coder and co-founder of We made you look Web agency