Distortion (waveshaping) effects in Max / MSP

Distortions are used to add harmonics to the original sound. In most cases, waveshapers are used for this. I say “in the majority” because harmonics can also be added using, for example, ring modulation. So, the essence of waveshaping is to convert the signal using a specially selected transfer function. Sounds complicated? Not at all. In fact, squaring a signal is also a transfer function. This is the whole theory we need to know. Let's start patching!

Where will we get the functions from?


We will not reinvent the wheel and take functions from the musicdsp.org website - this is a community of dsp programmers where you can find many ready-made algorithms, however, most of them are listed in C ++ code.

First


Let's start with the simplest example:

z = M_PI * a;
s = 1 / sin (z)
b = 1 / a

if (x> b)
f (x) = 1
else
f (x) = sin (z * x) * s


Here the variable a - controls the degree of signal distortion, and the input the signal is represented as the variable x . Now we implement this in max:

image

First patch


Here, the if role is performed by the construction of the objects > ~ , + ~ and [selector ~ 2 ] . The object > ~ compares the input signal (from cycle ~) with the variable b and displays one if the signal value is greater than the variable b , and zero if it is less. One and zero control the selector ~ object , which only outputs one of the inlets. Accordingly, when the condition x> b is satisfied, 1 is output , otherwise, the output is calculated by the formula cos (z * x) * s. You may notice that we use the cosine function, while in the original formula the sine. The fact is that in max there is no object for calculating the sine, so you have to replace it with cosine, there is no difference, because they differ only in the initial phase.

Second


Code:

x = input in [-1..1]
k = 2 * amount / (1-amount);

f (x) = (1 + k) * x / (1 + k * abs (x))


The author of the code notes that the value of amount should be in the range -1 ... 1 . Of course, you do not need to set the amount equal to 1 , in this case there will be a division by zero. Here we have the input signal - x .

image

There is nothing complicated here, having carefully studied the patch and comparing it with the formula, you can easily figure out how everything works.

Third


Code:

f (x, a) = x * (abs (x) + a) / (x ^ 2 + (a-1) * abs (x) + 1)

It is also in the max:

image

The signal is distorted with the parameter amount> 1 . I noticed a strange effect (at least on a sinusoid) when amount is in the range -1 ... 0 . Try, experiment and there will be happiness! :)

Chebyshev polynomials


Any nonlinear signal transformations create additional harmonics, in most cases an infinite number of them, which causes distortion at high frequencies due to aliasing. Therefore, it is so important to control the added harmonics, fortunately, this is very easily done with the help of Chebyshev polynomials.

They have a very important property: when a harmonic signal with a unit amplitude (for example, a sinusoid) is supplied through them, we will get the same signal, only several times higher. The frequency multiplier will depend on the order of the polynomial.

All polynomials have approximately the following form:

y = f (x) = d0 + d1x + d2x ^ 2 + d3x ^ 3 + ... + dNx ^ N;

That is, it is, in fact, a polynomial. The nth element determines the order of the polynomial. In our case, each element generates a certain harmonic, after which they all add up. The

form of each term is determined by the following recurrence relation: Tk + 1 (x) = 2xTk (x) - Tk – 1 (x);

In it, each term is determined on the basis of the previous one, everything starts from zero, in our case it is equal to one, and the first, which is equal to x:

T0 (x) = 1;

T1 (x) = x;


Knowing them, we can determine the third term:

T2 (x) = 2x * x - 1 = 2x ^ 2 - 1;

And the fourth:

T3 (x) = 2x (2x ^ 2 - 1) - x = 4x ^ 3 - 3x;

As you might guess, the second term is the first harmonic, the third is the second, and so on.

Another feature of the Chebyshev polynomials: when you give a signal through them, with an amplitude less than unity, the output produces a sound with less saturation of harmonics. This allows you to create a drive parameter for distortion.

So, let's move on to practice. It is required to create distortion using Chebyshev polynomials, which will generate eight harmonics, and also allow you to set the amplitude of each component. We will not look for a transfer function for each harmonic, instead we will create a small sub-patch that will generate a new one based on the two previous harmonics.

image

The previous harmonic is fed into the first inlet, the one before the previous one, and the unchanged input signal into the third. As you can see, this subpatcher simply implements a recurrence relationTk + 1 (x) = 2xTk (x) - Tk – 1 (x) , there is nothing complicated.

Now we will create a patch from these blocks that allows you to add up to the eighth harmonic (a high-pass filter at the end of the chain removes DC offset ):

image

This patch allows you to adjust the amplitude of the added harmonics, this can be used to emulate analog devices. So, many tube distortions mainly add even harmonics, odd ones appear only with a high amplitude of the incoming signal. Many low-quality amplifiers can create a third harmonic. Solid-state “Fuzz-Face” distortions distort the signal asymmetrically, they clearly have the second and third harmonics, as well as a bit of the fourth and fifth harmonics. Electro-Harmonix Big Muff PIdistorts symmetrically and produces mainly the fifth and seventh harmonics.

Conclusion


Any amplitude transformations entail an unpleasant consequence - aliasing. It appears when the generated harmonics exceed the maximum signal frequency (Niquist frequency)which is equal to half the sampling rate. To combat it, oversampling is used - the execution of the internal algorithm at a several-fold increased sampling rate, with its subsequent decrease when the signal leaves the device. When using Chebyshev polynomials, it is known exactly how many times it is necessary to increase the sampling frequency in order to completely remove aliasing - this is determined by the highest harmonic generated. When the algorithm is based on other transfer functions, it cannot be completely eliminated, since usually these algorithms generate an infinite number of harmonics, however, oversampling can significantly reduce the effect of aliasing.

Most waveshaper vstin the work do not use formulas for signal conversion, their role is played by tables of values ​​in which the values ​​of formulas are entered in the range -1 ... 1 . This allows not to perform resource-intensive calculations in real time, and also makes it possible to "draw" transfer functions.

I think in one of the following articles I will write about how to do oversampling and table waveshaping in max, so stay tuned.

PS The patch archive also contains the all_in_one.maxpat patch , which contains all the algorithms with the ability to select the algorithm and the source sound.

The archive itself can be downloaded from the link .

Also popular now: