


2 Wave shaping things
References : Posted by Frederic Petrot
Notes : Makes nice saturations effects that can be easilly computed using cordic
First using a atan function:
y1 using k=16
max is the max value you can reach (32767 would be a good guess)
Harmonics scale down linealy and not that fast
Second using the hyperbolic tangent function:
y2 using k=2
Harmonics scale down linealy very fast
Code : y1 = (max>>1) * atan(k * x/max)
y2 = max * th(x/max)
14 comment(s)  add a comment  nofrills version 






Band Limited PWM Generator
Type : PWM generator References : Posted by paul_sernine75 AT hotmail DOT fr
Notes : This is a commented and deobfuscated version of my 1st April fish. It is based on a tutorial code by Thierry Rochebois. I just translated and added comments.
Regards,
Paul Sernine.
Code : // SelfPMpwm.cpp
// Antialised PWM oscillator
// Based on a tutorial code by Thierry Rochebois (98).
// Itself inspired by US patent 4249447 by Norio Tomisawa (81).
// Comments added/translated by P.Sernine (06).
// This program generates a 44100HzrawPCMmonowavefile.
// It is based on Tomisawa's selfphasemodulated sinewave generators.
// Rochebois uses a common phase accumulator to feed two halfTomisawa
// oscillators. Each halfTomisawaoscillator generates a bandlimited
// sawtooth (band limitation depending on the feedback coeff B).
// These half oscillators are phase offseted according to the desired
// pulse width. They are finally combined to obtain the PW signal.
// Note: the anti"hunting" filter is a critical feature of a good
// implementation of Tomisawa's method.
#include <math.h>
#include <stdio.h>
const float pi=3.14159265359f;
int main()
{
float freq,dphi; //!< frequency (Hz) and phase increment(rad/sample)
float dphif=0; //!< filtered (anti click) phase increment
float phi=pi; //!< phase
float Y0=0,Y1=0; //!< feedback memories
float PW=pi; //!< pulse width ]0,2pi[
float B=2.3f; //!< feedback coef
FILE *f=fopen("SelfPMpwm.pcm","wb");
// séquence ('a'=mi=E)
// you can edit this if you prefer another melody.
static char seq[]="aiakahiafahadfaiakahiahafahadf"; //!< sequence
int note=sizeof(seq)2; //!< note number in the sequence
int octave=0; //!< octave number
float env,envf=0; //!< envelopped and filtered envelopped
for(int ns=0;ns<8*(sizeof(seq)1)*44100/6;ns++)
{
//waveform control 
//Frequency
//freq=27.5f*powf(2.0f,8*ns/(8*30*44100.0f/6)); //sweep
freq=27.5f*powf(2.0f,octave+(seq[note]'a'5)/12.0f);
//freq*=(1.0f+0.01f*sinf(ns*0.0015f)); //vibrato
dphi=freq*(pi/22050.0f); // phase increment
dphif+=0.1f*(dphidphif);
//notes and enveloppe trigger
if((ns%(44100/6))==0)
{
note++;
if(note>=(sizeof(seq)1))// sequence loop
{
note=0;
octave++;
}
env=1; //env set
//PW=pi*(0.4+0.5f*(rand()%1000)/1000.0f); //random PW
}
env*=0.9998f; // exp enveloppe
envf+=0.1f*(envenvf); // declicked enveloppe
B=1.0f; // feedback coefficient
//try this for a nice bass sound:
//B*=envf*envf; // feedback controlled by enveloppe
B*=2.3f*(10.0001f*freq); // feedback limitation
if(B<0)
B=0;
//waveform generation 
//Common phase
phi+=dphif; // phase increment
if(phi>=pi)
phi=2*pi; // phase wrapping
// "phase" half Tomisawa generator 0
// B*Y0 > self phase modulation
float out0=cosf(phi+B*Y0); // halfoutput 0
Y0=0.5f*(out0+Y0); // anti "hunting" filter
// "phase+PW" half Tomisawa generator 1
// B*Y1 > self phase modulation
// PW > phase offset
float out1=cosf(phi+B*Y1+PW); // halfoutput 1
Y1=0.5f*(out1+Y1); // anti "hunting" filter
// combination, enveloppe and output
short s=short(15000.0f*(out0out1)*envf);
fwrite(&s,2,1,f); // file output
}
fclose(f);
return 0;
}
7 comment(s)  add a comment  nofrills version 






Bit quantization/reduction effect
Type : Bitlevel noisegenerating effect References : Posted by Jon Watte
Notes : This function, run on each sample, will emulate half the effect of running your signal through a SpeakNSpell or similar lowbitdepth circuitry.
The other half would come from downsampling with no aliasing control, i e replicating every Nth sample N times in the output signal.
Code : short keep_bits_from_16( short input, int keepBits ) {
return (input & (1 << (16keepBits)));
}
3 comment(s)  add a comment  nofrills version 






Class for waveguide/delay effects
Type : IIR filter References : Posted by arguru[AT]smartelectronix.com
Notes : Flexibletime, nonsample quantized delay , can be used for stuff like waveguide synthesis or timebased (chorus/flanger) fx.
MAX_WG_DELAY is a constant determining MAX buffer size (in samples)
Code : class cwaveguide
{
public:
cwaveguide(){clear();}
virtual ~cwaveguide(){};
void clear()
{
counter=0;
for(int s=0;s<MAX_WG_DELAY;s++)
buffer[s]=0;
}
inline float feed(float const in,float const feedback,double const delay)
{
// calculate delay offset
double back=(double)counterdelay;
// clip lookback bufferbound
if(back<0.0)
back=MAX_WG_DELAY+back;
// compute interpolation leftfloor
int const index0=floor_int(back);
// compute interpolation rightfloor
int index_1=index01;
int index1=index0+1;
int index2=index0+2;
// clip interp. bufferbound
if(index_1<0)index_1=MAX_WG_DELAY1;
if(index1>=MAX_WG_DELAY)index1=0;
if(index2>=MAX_WG_DELAY)index2=0;
// get neighbourgh samples
float const y_1= buffer [index_1];
float const y0 = buffer [index0];
float const y1 = buffer [index1];
float const y2 = buffer [index2];
// compute interpolation x
float const x=(float)back(float)index0;
// calculate
float const c0 = y0;
float const c1 = 0.5f*(y1y_1);
float const c2 = y_1  2.5f*y0 + 2.0f*y1  0.5f*y2;
float const c3 = 0.5f*(y2y_1) + 1.5f*(y0y1);
float const output=((c3*x+c2)*x+c1)*x+c0;
// add to delay buffer
buffer[counter]=in+output*feedback;
// increment delay counter
counter++;
// clip delay counter
if(counter>=MAX_WG_DELAY)
counter=0;
// return output
return output;
}
float buffer[MAX_WG_DELAY];
int counter;
};
no comments on this item  add a comment  nofrills version 






Compressor
Type : Hardknee compressor with RMS lookahead envelope calculation and adjustable attack/decay References : Posted by flashinc[AT]mail[DOT]ru
Notes : RMS is a true way to estimate _musical_ signal energy,
our ears behaves in a same way.
to making all it work,
try this values (as is, routine accepts percents and milliseconds) for first time:
threshold = 50%
slope = 50%
RMS window width = 1 ms
lookahead = 3 ms
attack time = 0.1 ms
release time = 300 ms
This code can be significantly improved in speed by
changing RMS calculation loop to 'running summ'
(keeping the summ in 'window' 
adding next newest sample and subtracting oldest on each step)
Code : void compress
(
float* wav_in, // signal
int n, // N samples
double threshold, // threshold (percents)
double slope, // slope angle (percents)
int sr, // sample rate (smp/sec)
double tla, // lookahead (ms)
double twnd, // window time (ms)
double tatt, // attack time (ms)
double trel // release time (ms)
)
{
typedef float stereodata[2];
stereodata* wav = (stereodata*) wav_in; // our stereo signal
threshold *= 0.01; // threshold to unity (0...1)
slope *= 0.01; // slope to unity
tla *= 1e3; // lookahead time to seconds
twnd *= 1e3; // window time to seconds
tatt *= 1e3; // attack time to seconds
trel *= 1e3; // release time to seconds
// attack and release "per sample decay"
double att = (tatt == 0.0) ? (0.0) : exp (1.0 / (sr * tatt));
double rel = (trel == 0.0) ? (0.0) : exp (1.0 / (sr * trel));
// envelope
double env = 0.0;
// sample offset to lookahead wnd start
int lhsmp = (int) (sr * tla);
// samples count in lookahead window
int nrms = (int) (sr * twnd);
// for each sample...
for (int i = 0; i < n; ++i)
{
// now compute RMS
double summ = 0;
// for each sample in window
for (int j = 0; j < nrms; ++j)
{
int lki = i + j + lhsmp;
double smp;
// if we in bounds of signal?
// if so, convert to mono
if (lki < n)
smp = 0.5 * wav[lki][0] + 0.5 * wav[lki][1];
else
smp = 0.0; // if we out of bounds we just get zero in smp
summ += smp * smp; // square em..
}
double rms = sqrt (summ / nrms); // rootmeansquare
// dynamic selection: attack or release?
double theta = rms > env ? att : rel;
// smoothing with capacitor, envelope extraction...
// here be aware of pIV denormal numbers glitch
env = (1.0  theta) * rms + theta * env;
// the very easy hard knee 1:N compressor
double gain = 1.0;
if (env > threshold)
gain = gain  (env  threshold) * slope;
// result  two hard kneed compressed channels...
float leftchannel = wav[i][0] * gain;
float rightchannel = wav[i][1] * gain;
}
}
6 comment(s)  add a comment  nofrills version 






Decimator
Type : Bitreducer and sample&hold unit References : Posted by tobyear[AT]web[DOT]de
Notes : This is a simple bit and sample rate reduction code, maybe some of you can use it. The parameters are bits (1..32) and rate (0..1, 1 is the original samplerate).
Call the function like this:
y=decimate(x);
A VST plugin implementing this algorithm (with full Delphi source code included) can be downloaded from here:
http://tobybear.phreque.com/decimator.zip
Comments/suggestions/improvements are welcome, send them to: tobybear@web.de
Code : // bits: 1..32
// rate: 0..1 (1 is original samplerate)
********** Pascal source **********
var m:longint;
y,cnt,rate:single;
// call this at least once before calling
// decimate() the first time
procedure setparams(bits:integer;shrate:single);
begin
m:=1 shl (bits1);
cnt:=1;
rate:=shrate;
end;
function decimate(i:single):single;
begin
cnt:=cnt+rate;
if (cnt>1) then
begin
cnt:=cnt1;
y:=round(i*m)/m;
end;
result:=y;
end;
********** C source **********
int bits=16;
float rate=0.5;
long int m=1<<(bits1);
float y=0,cnt=0;
float decimate(float i)
{
cnt+=rate;
if (cnt>=1)
{
cnt=1;
y=(long int)(i*m)/(float)m;
}
return y;
}
9 comment(s)  add a comment  nofrills version 






Delay time calculation for reverberation
References : Posted by Andy Mucho
Notes : This is from some notes I had scribbled down from a while back on
automatically calculating diffuse delays. Given an intial delay line gain
and time, calculate the times and feedback gain for numlines delay lines..
Code : int numlines = 8;
float t1 = 50.0; // d0 time
float g1 = 0.75; // d0 gain
float rev = 3*t1 / log10 (g1);
for (int n = 0; n < numlines; ++n)
{
float dt = t1 / pow (2, (float (n) / numlines));
float g = pow (10, ((3*dt) / rev));
printf ("d%d t=%.3f g=%.3f\n", n, dt, g);
}
The above with t1=50.0 and g1=0.75 yields:
d0 t=50.000 g=0.750
d1 t=45.850 g=0.768
d2 t=42.045 g=0.785
d3 t=38.555 g=0.801
d4 t=35.355 g=0.816
d5 t=32.421 g=0.830
d6 t=29.730 g=0.843
d7 t=27.263 g=0.855
To go more diffuse, chuck in dual feedback paths with a one cycle delay
effectively creating a phaseshifter in the feedback path, then things get
more exciting.. Though what the optimum phase shifts would be I couldn't
tell you right now..
1 comment(s)  add a comment  nofrills version 






DIRAC  Free C/C++ Library for Time and Pitch Manipulation of Audio Based on TimeFrequency Transforms
Type : Time Stretch / Pitch Shift References : Posted by Stephan M. Bernsee
Notes : This is an availability notification for a free object library, no source code.
Code : Past research has shown time domain [pitch] synchronized overlapadd ([P]SOLA) algorithms for independent time and pitch manipulation of audio ("time stretching" and "pitch shifting") to be the method of choice for singlepitched sounds such as voice and musically monophonic instrument recordings due to the prominent periodicity at the fundamental period. On the other hand, frequency domain methods have recently evolved around the concept of the phase vocoder that have proven to be vastly superior for multipitched sounds and entire musical pieces.
"Dirac" is a free crossplatform C/C++ object library that exploits the good localization of timefrequency transforms in both domains to build an algorithm for time and pitch manipulation that uses an arbitrary timefrequency tiling depending on the underlying signal. Additionally, the time and frequency localization parameter of the basis can be userdefined, making the algorithm smoothly scalable to provide either the phase coherence properties of a time domain process or the good frequency resolution of the phase vocoder.
The basic "Dirac" library comes as a free download off the DSPdimension web site and is currently available for Microsoft Visual C6+, CodeWarrior 8.x on Windows and MacOS, and for Xcode 2.x on MacOS X. Optional "Studio" and "Pro" versions with increased feature set are available commercially from the author.
More information and download at http://www.dspdimension.com
8 comment(s)  add a comment  nofrills version 






dynamic convolution
Type : a naive implementation in C++ References : Posted by Risto Holopainen
Notes : This class illustrates the use of dynamic convolution with a set of IR:s consisting of exponentially damped sinusoids with glissando. There's lots of things to improve for efficiency.
Code : #include <cmath>
class dynaconv
{
public:
// sr=sample rate, cf=resonance frequency,
// dp=frq sweep or nonlinearity amount
dynaconv(const int sr, float cf, float dp);
double operator()(double);
private:
// steps: number of amplitude regions, L: length of impulse response
enum {steps=258, dv=steps2, L=200};
double x[L];
double h[steps][L];
int S[L];
double conv(double *x, int d);
};
dynaconv::dynaconv(const int sr, float cfr, float dp)
{
for(int i=0; i<L; i++)
x[i] = S[i] = 0;
double sc = 6.0/L;
double frq = twopi*cfr/sr;
// IR's initialised here.
// h[0] holds the IR for samples with lowest amplitude.
for(int k=0; k<steps; k++)
{
double sum = 0;
double theta=0;
double w;
for(int i=0; i<L; i++)
{
// IR of exp. decaying sinusoid with glissando
h[k][i] = sin(theta)*exp(sc*i);
w = (double)i/L;
theta += frq*(1 + dp*w*(k  0.4*steps)/steps);
sum += fabs(h[k][i]);
}
double norm = 1.0/sum;
for(int i=0; i<L; i++)
h[k][i] *= norm;
}
}
double dynaconv::operator()(double in)
{
double A = fabs(in);
double a, b, w, y;
int sel = int(dv*A);
for(int j=L1; j>0; j)
{
x[j] = x[j1];
S[j] = S[j1];
}
x[0] = in;
S[0] = sel;
if(sel == 0)
y = conv(x, 0);
else if(sel > 0)
{
a = conv(x, 0);
b = conv(x, 1);
w = dv*A  sel;
y = w*a + (1w)*b;
}
return y;
}
double dynaconv::conv(double *x, int d)
{
double y=0;
for(int i=0; i<L; i++)
y += x[i] * h[ S[i]+d ][i];
return y;
}
2 comment(s)  add a comment  nofrills version 






fold back distortion
Type : distortion References : Posted by hellfire[AT]upb[DOT]de
Notes : a simple foldback distortion filter.
if the signal exceeds the given thresholdlevel, it mirrors at the positive/negative thresholdborder as long as the singal lies in the legal range (threshold..+threshold).
there is no range limit, so inputs doesn't need to be in 1..+1 scale.
threshold should be >0
depending on use (low thresholds) it makes sense to rescale the input to full amplitude
performs approximately the following code
(just without the loop)
while (in>threshold  in<threshold)
{
// mirror at positive threshold
if (in>threshold) in= threshold  (inthreshold);
// mirror at negative threshold
if (in<threshold) in= threshold + (thresholdin);
}
Code : float foldback(float in, float threshold)
{
if (in>threshold  in<threshold)
{
in= fabs(fabs(fmod(in  threshold, threshold*4))  threshold*2)  threshold;
}
return in;
}
1 comment(s)  add a comment  nofrills version 






Guitar feedback
References : Posted by Sean Costello
Notes : It is fairly simple to simulate guitar feedback with a simple KarplusStrong algorithm (this was described in a CMJ article in the early 90's):
Code : Run the output of the KarplusStrong delay lines into a nonlinear shaping function for distortion (i.e. 6 parallel delay lines for 6 strings, going into 1 nonlinear shaping function that simulates an overdriven amplifier, fuzzbox, etc.);
Run part of the output into a delay line, to simulate the distance from the amplifier to the "strings";
The delay line feeds back into the KarplusStrong delay lines. By controlling the amount of the output fed into the delay line, and the length of the delay line, you can control the intensity and pitch of the feedback note.
13 comment(s)  add a comment  nofrills version 






LoFi Crusher
Type : Quantizer / Decimator with smooth control References : Posted by David Lowenfels
Notes : Yet another bitcrusher algorithm. But this one has smooth parameter control.
Normfreq goes from 0 to 1.0; (freq/samplerate)
Input is assumed to be between 0 and 1.
Output gain is greater than unity when bits < 1.0;
Code : function output = crusher( input, normfreq, bits );
step = 1/2^(bits);
phasor = 0;
last = 0;
for i = 1:length(input)
phasor = phasor + normfreq;
if (phasor >= 1.0)
phasor = phasor  1.0;
last = step * floor( input(i)/step + 0.5 ); %quantize
end
output(i) = last; %sample and hold
end
end
3 comment(s)  add a comment  nofrills version 






Lookahead Limiter
Type : Limiter References : Posted by Christian at savioursofsoul dot de
Notes : I've been thinking about this for a long time and this is the best I came up with so far. I might be all wrong, but according to some simulations this looks quite nice (as I want it to be).
The below algorithm is written in prosa. It's up to you to transfer it into code.
Code : Ingredients:

1 circular buffers (size of the look ahead time)
2 circular buffers (half the size of the look ahead time)
4 parameters ('Lookahead Time [s]', 'Input Gain [dB]', 'Output Gain [dB]' and 'Release Time [s])
a handfull state variables
Recipe:

0. Make sure all buffers are properly initialized and do not contain any dirt (pure zeros are what we need).
For each sample do the following procedure:
1. Store current sample in the lookahead time circular buffer, for later use (and retrieve the value that falls out as the preliminary 'Output')
2. Find maximum within this circular buffer. This can also be implemented efficiently with an hold algorithm.
3. Gain this maximum by the 'Input Gain [dB]' parameter
4. Calculate necessary gain reduction factor (=1, if no gain reduction takes place and <1 for any signal above 0 dBFS)
5. Eventually subtract this value from 1 for a better numerical stability. (MUST BE UNDONE LATER!)
6. Add this gain reduction value to the first of the smaller circular buffers to calculate the short time sum (add this value to a sum and subtract the value that felt out of the circular buffer).
7. normalize the sum by dividing it by the length of the circular buffer (> / ('Lookahead Time' [samples] / 2))
8. repeat step 6 & 7 with this sum in the second circular buffer. The reason for these steps is to transform dirac impulses to a triangle (dirac > rect > triangle)
9. apply the release time (release time > release slew rate 'factor' > multiply by that factor) to the 'Maximum Gain Reduction' state variable
10. check whether the currently calculated gain reduction is higher than the 'Maximum Gain Reduction'. If so, replace!
11. eventually remove (1  x) from step 5 here
12. calculate effective gain reduction by the above value gained by input and output gain.
13. Apply this gain reduction to the preliminary 'Output' from step 1
Repeat the above procedure (step 113) for all samples!
2 comment(s)  add a comment  nofrills version 






Most simple and smooth feedback delay
Type : Feedback delay References : Posted by antiprosynthesis[AT]hotmail[DOT]com
Notes : fDlyTime = delay time parameter (01)
i = input index
j = delay index
Code : if( i >= SampleRate )
i = 0;
j = i  (fDlyTime * SampleRate);
if( j < 0 )
j += SampleRate;
Output = DlyBuffer[ i++ ] = Input + (DlyBuffer[ j ] * fFeedback);
4 comment(s)  add a comment  nofrills version 






Most simple static delay
Type : Static delay References : Posted by antiprosynthesis[AT]hotmail[DOT]com
Notes : This is the most simple static delay (just delays the input sound an amount of samples). Very useful for newbies also probably very easy to change in a feedback delay (for comb filters for example).
Note: fDlyTime is the delay time parameter (0 to 1)
i = input index
j = output index
Code : if( i >= SampleRate )
i = 0;
DlyBuffer[ i ] = Input;
j = i  (fDlyTime * SampleRate);
i++;
if( j < 0 )
j = SampleRate + j;
Output = DlyBuffer[ j ];
9 comment(s)  add a comment  nofrills version 






Parallel combs delay calculation
References : Posted by Juhana Sadeharju ( kouhia[AT]nic[DOT]funet[DOT]fi )
Notes : This formula can be found from a patent related to parallel combs structure. The formula places the first echoes coming out of parallel combs to uniformly distributed sequence. If T_ ,...,T_n are the delay lines in increasing order, the formula can be derived by setting T_(k1)/T_k = Constant and T_n/(2*T_1) = Constant, where 2*T_1 is the echo coming just after the echo T_n.
I figured this out myself as it is not told in the patent. The formula is not the best which one can come up. I use a search method to find echo sequences which are uniform enough for long enough time. The formula is uniform for a short time only.
The formula doesn't work good for series allpass and FDN structures, for which a similar formula can be derived with the same idea. The search method works for these structures as well.
no comments on this item  add a comment  nofrills version 






Polynominal Waveshaper
Type : (discrete harmonics) References : Posted by Christian[AT]savioursofsoul[DOT]de
Notes : The following code will describe how to excite discrete harmonics and only these harmonics. A simple polynominal waveshaper for processing the data is included as well. However the code don't claim to be optimized. Using a horner scheme with precalculated coefficients should be your choice here.
Also remember to oversample the data (optimal in the order of the harmonics) to have them alias free.
Code : We assume the input is a sinewave (works for any input signal, but this makes everything more clear). Then we have x = sin(a)
the first harmonic is plain simple (using trigonometric identities):
cos(2*a)= cos^2(a)  sin^2(a) = 1  2 sin^2(a)
using the general trigonometric identities:
sin(x + y) = sin(x)*cos(y) + sin(y)*cos(x)
cos(x + y) = cos(x)*cos(y)  sin(y)*sin(x)
together with some math, you can easily calculate: sin(3x), cos(4x), sin(5x), and so on...
Here's how the resulting waveshaper may look like:
// o = output, i = input
o = fPhase[1]* i * fGains[0]+
fPhase[1]*( 2*i*i  1 ) * fGains[1]+
fPhase[2]*( 4*i*i*i  3*i ) * fGains[2]+
fPhase[3]*( 8*i*i*i*i  8*i*i + 1 ) * fGains[3]
fPhase[4]*( 16*i*i*i*i*i  20*i*i*i + 5 * i ) * fGains[4]+
fPhase[5]*( 32*i*i*i*i*i*i  48*i*i*i*i + 18 * i*i  1 ) * fGains[5]
fPhase[6]*( 64*i*i*i*i*i*i*i  112*i*i*i*i*i + 56 * i*i*i  7 * i ) * fGains[6]+
fPhase[7]*(128*i*i*i*i*i*i*i*i  256*i*i*i*i*i*i + 160 * i*i*i*i  32 * i*i + 1 ) * fGains[7];
fPhase[..] is the sign array and fGains[..] is the gain factor array.
P.S.: I don't want to see a single comment about the fact that the code above is unoptimized. I know that!
8 comment(s)  add a comment  nofrills version 






Reverberation Algorithms in Matlab
References : Posted by Gautham J. Mysore (gauthamjm [AT] yahoo [DOT] com) Linked file : MATLABReverb.zip
Notes : These Mfiles implement a few reverberation algorithms (based on Schroeder's and Moorer's algorithms). Each of the Mfiles include a short description.
There are 5 Mfiles that implement reverberation. They are:
 schroeder1.m
 schroeder2.m
 schroeder3.m
 moorer.m
 stereoverb.m
The remaining 8 Mfiles implement filters, delay lines etc. Most of these are used in the above Mfiles. They can also be used as building blocks for other reverberation algorithms.
2 comment(s)  add a comment  nofrills version 






Reverberation techniques
References : Posted by Sean Costello
Notes : * Parallel comb filters, followed by series allpass filters. This was the original design by Schroeder, and was extended by Moorer. Has a VERY metallic sound for sharp transients.
* Several allpass filters in serie (also proposed by Schroeder). Also suffers from metallic sound.
* 2ndorder comb and allpass filters (described by Moorer). Not supposed to give much of an advantage over first order sections.
* Nested allpass filters, where an allpass filter will replace the delay line in another allpass filter. Pioneered by Gardner. Haven't heard the results.
* Strange allpass amp delay line based structure in Jon Dattorro article (JAES). Four allpass filters are used as an input to a cool "figure8" feedback loop, where four allpass reverberators are used in series with
a few delay lines. Outputs derived from various taps in structure. Supposedly based on a Lexicon reverb design. Modulating delay lines are used in some of the allpass structures to "spread out" the eigentones.
* Feedback Delay Networks. Pioneered by Puckette/Stautner, with Jot conducting extensive recent research. Sound VERY good, based on initial experiments. Modulating delay lines and feedback matrixes used to spread out eigentones.
* Waveguidebased reverbs, where the reverb structure is based upon the junction of many waveguides. Julius Smith developed these. Recently, these have been shown to be essentially equivalent to the feedback delay network reverbs. Also sound very nice. Modulating delay lines and scattering values used to spread out eigentones.
* Convolutionbased reverbs, where the sound to be reverbed is convolved with the impulse response of a room, or with exponentiallydecaying white noise. Supposedly the best sound, but very computationally expensive, and not very flexible.
* FIRbased reverbs. Essentially the same as convolution. Probably not used, but shorter FIR filters are probably used in combination with many of the above techniques, to provide early reflections.
4 comment(s)  add a comment  nofrills version 






Simple Compressor class (C++)
Type : stereo, feedforward, peak compressor References : Posted by Citizen Chunk Linked file : http://www.chunkware.com/opensource/SimpleComp.zip
Notes : Everyone seems to want to make their own compressor plugin these days, but very few know where to start. After replying to so many questions on the KVR Dev Forum, I figured I might as well just post some readytouse C++ source code.
This is a C++ implementation of a simple, stereo, peak compressor. It uses a feedforward topology, detecting the sidechain level pregain reduction. The sidechain detects the rectified peak level, with stereo linking to preserve imaging. The attack/release uses the EnvelopeDetector class (posted in the Analysis section).
Notes:
 Make sure to call initRuntime() before processing starts (i.e. call it in resume()).
 The process function takes a stereo input.
 VST params must be mapped to a practical range when setting compressor parameters. (i.e. don't try setAttack( 0.f ).)
(see linked files)
11 comment(s)  add a comment  nofrills version 






Soft saturation
Type : waveshaper References : Posted by Bram de Jong
Notes : This only works for positive values of x. a should be in the range 0..1
Code : x < a:
f(x) = x
x > a:
f(x) = a + (xa)/(1+((xa)/(1a))^2)
x > 1:
f(x) = (a+1)/2
4 comment(s)  add a comment  nofrills version 






Stereo Enhancer
References : Posted by kurmisk[at]inbox[DOT]lv
Notes :
Stereo Enhanca
Code :
// WideCoeff 0.0 .... 1.5
#define StereoEnhanca(SamplL,SamplR,MonoSign, \
DeltaLeft,WideCoeff ) \
MonoSign = (SamplL + SamplR)/2.0; \
DeltaLeft = SamplL  MonoSign; \
DeltaLeft = DeltaLeft * WideCoeff; \
SamplL=SamplL + DeltaLeft; \
SamplR=SamplR  DeltaLeft;
15 comment(s)  add a comment  nofrills version 






Stereo Field Rotation Via Transformation Matrix
Type : Stereo Field Rotation References : Posted by Michael Gruhn
Notes : This work is hereby placed in the public domain for all purposes, including use in commercial applications.
'angle' is the angle by which you want to rotate your stereo field.
Code : // Calculate transformation matrix's coefficients
cos_coef = cos(angle);
sin_coef = sin(angle);
// Do this per sample
out_left = in_left * cos_coef  in_right * sin_coef;
out_right = in_left * sin_coef + in_right * cos_coef;
17 comment(s)  add a comment  nofrills version 






Stereo Width Control (Obtained Via Transfromation Matrix)
Type : Stereo Widener References : Posted by Michael Gruhn
Notes : (I was quite surprised that this wasn't already in the archive, so here it is.)
This work is hereby placed in the public domain for all purposes, including use in commercial applications.
'width' is the stretch factor of the stereo field:
width < 1: decrease in stereo width
width = 1: no change
width > 1: increase in stereo width
width = 0: mono
Code : // calculate scale coefficient
coef_S = width*0.5;
// then do this per sample
m = (in_left + in_right)*0.5;
s = (in_right  in_left )*coef_S;
out_left = m  s;
out_right = m + s;
10 comment(s)  add a comment  nofrills version 






transistor differential amplifier simulation
Type : Waveshaper References : Posted by Christian[at]savioursofsoul[dot]de
Notes : Writting an exam about electronic components, i learned several equations about simulating that stuff. One simplified equation was the tanh(x) formula for the differential amplifier. It is not exact, but since the amplifiers are driven with only small amplitudes the behaviour is most often even advanced linear.
The fact, that the amp is differential, means, that the 2n order is eliminated, so the sound is also similar to a tube.
For a very fast use, this code is in pure assembly language (not optimized with SSECode yet) and performs in VSTPlugins very fast.
The code was written in delphi and if you want to translate the assembly code, you should know, the the parameters passing is done via registers. So pinp=EAX pout=EDX sf=ECX.
Code : procedure Transistor(pinp,pout : PSingle; sf:Integer; Faktor: Single);
asm
fld Faktor
@Start:
fld [eax].single
fmul st(0),st(1)
fldl2e
fmul
fld st(0)
frndint
fsub st(1),st
fxch st(1)
f2xm1
fld1
fadd
fscale { result := z * 2**i }
fstp st(1)
fld st(0)
fmulp
fld st(0)
fld1
faddp
fld1
fsubp st(2),st(0)
fdivp
fstp [edx].single
add eax,4
add edx,4
loop @Start
fstp st(0)
end;
7 comment(s)  add a comment  nofrills version 






UniVox Univibe Emulator
Type : 4 Cascaded allpass filters and optocoupler approximation References : Posted by ryjobil *@* gmail *dot* com
Notes : This is a class and class member functions for a 'Vibe derived by means of bilinear transform of the allpass filter stages in a UniVibe. Some unique things happen as this filter is modulated, so this has been somewhat involved computation of filter coefficients, and is based on summation of 1rstorder filter stages as algebraically decoupled during circuit analysis. A second part is an approximated model of the Vactrol used to modulate the filters, including its time response to hopefully recapture the modulation shape. It is likely there is a more efficient way to recreate the LFO shape, and perhaps would be best with a lookup table. Keeping the calculation in the code makes it possible for other people to modify and improve the algorithm.
Notice no wet/dry mix is implemented in this code block's "out" function. Originally this was implemented in the calling routine, but if you use it as a standalone function you may want to add summation to the input signal as it is an important part of the "chorus" mode on the Vibe. The code as is represents only the Vibrato (warble) mode.
This is a module found in the Rakarrack guitar effects program. It is GPL, so please give credit due and keep it free. You can find any of the omitted parts to see more precisely how it is implemented with JACK on Linux by looking at the original sources at sourceforge.net/projects/rakarrack.
Code : /*
Copyright (C) 20082010 Ryan Billing
Author: Ryan Billing
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License
(version2) along with this program; if not, write to the Free Software
Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA
*/
class Vibe
{
public:
Vibe (float * efxoutl_, float * efxoutr_);
~Vibe ();
//note some of these functions not pasted below to improve clarity
//and to save space
void out (float * smpsl, float * smpsr);
void setvolume(int value);
void setpanning(int value);
void setpreset (int npreset);
void changepar (int npar, int value);
int getpar (int npar);
void cleanup ();
float outvolume;
float *efxoutl;
float *efxoutr;
private:
int Pwidth;
int Pfb;
int Plrcross;
int Pdepth;
int Ppanning;
int Pvolume;
//all the ints above are the parameters to modify with a proper function.
float fwidth;
float fdepth;
float rpanning, lpanning;
float flrcross, fcross;
float fb;
EffectLFO lfo; //EffectLFO is an object that calculates the next sample from the LFO each time it's called
float Ra, Rb, b, dTC, dRCl, dRCr, lampTC, ilampTC, minTC, alphal, alphar, stepl, stepr, oldstepl, oldstepr;
float fbr, fbl;
float dalphal, dalphar;
float lstep,rstep;
float cperiod;
float gl, oldgl;
float gr, oldgr;
class fparams {
public:
float x1;
float y1;
//filter coefficients
float n0;
float n1;
float d0;
float d1;
} vc[8], vcvo[8], ecvc[8], vevo[8], bootstrap[8];
float vibefilter(float data, fparams *ftype, int stage);
void init_vibes();
void modulate(float ldrl, float ldrr);
float bjt_shape(float data);
float R1;
float Rv;
float C2;
float C1[8];
float beta; //transistor forward gain.
float gain, k;
float oldcvolt[8] ;
float en1[8], en0[8], ed1[8], ed0[8];
float cn1[8], cn0[8], cd1[8], cd0[8];
float ecn1[8], ecn0[8], ecd1[8], ecd0[8];
float on1[8], on0[8], od1[8], od0[8];
class FPreset *Fpre;
};
Vibe::Vibe (float * efxoutl_, float * efxoutr_)
{
efxoutl = efxoutl_;
efxoutr = efxoutr_;
//Swing was measured on operating device of: 10K to 250k.
//400K is reported to sound better for the "low end" (high resistance)
//Because of time response, Rb needs to be driven further.
//End resistance will max out to around 10k for most LFO freqs.
//pushing low end a little lower for kicks and giggles
Ra = 500000.0f; //Cds cell dark resistance.
Ra = logf(Ra); //this is done for clarity
Rb = 600.0f; //Cds cell full illumination
b = exp(Ra/logf(Rb))  CNST_E;
dTC = 0.085f;
dRCl = dTC;
dRCr = dTC; //Right & left channel dynamic time contsants
minTC = logf(0.005f/dTC);
//cSAMPLE_RATE is 1/SAMPLE_RATE
alphal = 1.0f  cSAMPLE_RATE/(dRCl + cSAMPLE_RATE);
alphar = alphal;
dalphal = dalphar = alphal;
lampTC = cSAMPLE_RATE/(0.02 + cSAMPLE_RATE); //guessing 10ms
ilampTC = 1.0f  lampTC;
lstep = 0.0f;
rstep = 0.0f;
Pdepth = 127;
Ppanning = 64;
lpanning = 1.0f;
rpanning = 1.0f;
fdepth = 1.0f;
oldgl = 0.0f;
oldgr = 0.0f;
gl = 0.0f;
gr = 0.0f;
for(int jj = 0; jj<8; jj++) oldcvolt[jj] = 0.0f;
cperiod = 1.0f/fPERIOD;
init_vibes();
cleanup();
}
Vibe::~Vibe ()
{
}
void
Vibe::cleanup ()
{
//Yeah, clean up some stuff
};
void
Vibe::out (float *smpsl, float *smpsr)
{
int i,j;
float lfol, lfor, xl, xr, fxl, fxr;
float vbe,vin;
float cvolt, ocvolt, evolt, input;
float emitterfb = 0.0f;
float outl, outr;
input = cvolt = ocvolt = evolt = 0.0f;
lfo.effectlfoout (&lfol, &lfor);
lfol = fdepth + lfol*fwidth;
lfor = fdepth + lfor*fwidth;
if (lfol > 1.0f)
lfol = 1.0f;
else if (lfol < 0.0f)
lfol = 0.0f;
if (lfor > 1.0f)
lfor = 1.0f;
else if (lfor < 0.0f)
lfor = 0.0f;
lfor = 2.0f  2.0f/(lfor + 1.0f); //
lfol = 2.0f  2.0f/(lfol + 1.0f); //emulate lamp turn on/off characteristic by typical curves
for (i = 0; i < PERIOD; i++)
{
//Left Lamp
gl = lfol*lampTC + oldgl*ilampTC;
oldgl = gl;
//Right Lamp
gr = lfor*lampTC + oldgr*ilampTC;
oldgr = gr;
//Left Cds
stepl = gl*alphal + dalphal*oldstepl;
oldstepl = stepl;
dRCl = dTC*expf(stepl*minTC);
alphal = cSAMPLE_RATE/(dRCl + cSAMPLE_RATE);
dalphal = 1.0f  cSAMPLE_RATE/(0.5f*dRCl + cSAMPLE_RATE); //different attack & release character
xl = CNST_E + stepl*b;
fxl = expf(Ra/logf(xl));
//Right Cds
stepr = gr*alphar + dalphar*oldstepr;
oldstepr = stepr;
dRCr = dTC*expf(stepr*minTC);
alphar = cSAMPLE_RATE/(dRCr + cSAMPLE_RATE);
dalphar = 1.0f  cSAMPLE_RATE/(0.5f*dRCr + cSAMPLE_RATE); //different attack & release character
xr = CNST_E + stepr*b;
fxr = expf(Ra/logf(xr));
if(i%16 == 0) modulate(fxl, fxr);
//Left Channel
input = bjt_shape(fbl + smpsl[i]);
emitterfb = 25.0f/fxl;
for(j=0;j<4;j++) //4 stages phasing
{
cvolt = vibefilter(input,ecvc,j) + vibefilter(input + emitterfb*oldcvolt[j],vc,j);
ocvolt = vibefilter(cvolt,vcvo,j);
oldcvolt[j] = ocvolt;
evolt = vibefilter(input, vevo,j);
input = bjt_shape(ocvolt + evolt);
}
fbl = fb*ocvolt;
outl = lpanning*input;
//Right channel
input = bjt_shape(fbr + smpsr[i]);
emitterfb = 25.0f/fxr;
for(j=4;j<8;j++) //4 stages phasing
{
cvolt = vibefilter(input,ecvc,j) + vibefilter(input + emitterfb*oldcvolt[j],vc,j);
ocvolt = vibefilter(cvolt,vcvo,j);
oldcvolt[j] = ocvolt;
evolt = vibefilter(input, vevo,j);
input = bjt_shape(ocvolt + evolt);
}
fbr = fb*ocvolt;
outr = rpanning*input;
efxoutl[i] = outl*fcross + outr*flrcross;
efxoutr[i] = outr*fcross + outl*flrcross;
};
};
float
Vibe::vibefilter(float data, fparams *ftype, int stage)
{
float y0 = 0.0f;
y0 = data*ftype[stage].n0 + ftype[stage].x1*ftype[stage].n1  ftype[stage].y1*ftype[stage].d1;
ftype[stage].y1 = y0 + DENORMAL_GUARD;
ftype[stage].x1 = data;
return y0;
};
float
Vibe::bjt_shape(float data)
{
float vbe, vout;
float vin = 7.5f*(1.0f + data);
if(vin<0.0f) vin = 0.0f;
if(vin>15.0f) vin = 15.0f;
vbe = 0.8f  0.8f/(vin + 1.0f); //really rough, simplistic bjt turnon emulator
vout = vin  vbe;
vout = vout*0.1333333333f 0.90588f; //some magic numbers to return gain to unity & zero the DC
return vout;
}
void
Vibe::init_vibes()
{
k = 2.0f*fSAMPLE_RATE;
float tmpgain = 1.0f;
R1 = 4700.0f;
Rv = 4700.0f;
C2 = 1e6f;
beta = 150.0f; //transistor forward gain.
gain = beta/(beta + 1.0f);
//Univibe cap values 0.015uF, 0.22uF, 470pF, and 0.0047uF
C1[0] = 0.015e6f;
C1[1] = 0.22e6f;
C1[2] = 470e12f;
C1[3] = 0.0047e6f;
C1[4] = 0.015e6f;
C1[5] = 0.22e6f;
C1[6] = 470e12f;
C1[7] = 0.0047e6f;
for(int i =0; i<8; i++)
{
//Vo/Ve driven from emitter
en1[i] = k*R1*C1[i];
en0[i] = 1.0f;
ed1[i] = k*(R1 + Rv)*C1[i];
ed0[i] = 1.0f + C1[i]/C2;
// Vc~=Ve/(Ic*Re*alpha^2) collector voltage from current input.
//Output here represents voltage at the collector
cn1[i] = k*gain*Rv*C1[i];
cn0[i] = gain*(1.0f + C1[i]/C2);
cd1[i] = k*(R1 + Rv)*C1[i];
cd0[i] = 1.0f + C1[i]/C2;
//Contribution from emitter load through passive filter network
ecn1[i] = k*gain*R1*(R1 + Rv)*C1[i]*C2/(Rv*(C2 + C1[i]));
ecn0[i] = 0.0f;
ecd1[i] = k*(R1 + Rv)*C1[i]*C2/(C2 + C1[i]);
ecd0[i] = 1.0f;
// %Represents Vo/Vc. Output over collector voltage
on1[i] = k*Rv*C2;
on0[i] = 1.0f;
od1[i] = k*Rv*C2;
od0[i] = 1.0f + C2/C1[i];
//%Bilinear xform stuff
tmpgain = 1.0f/(cd1[i] + cd0[i]);
vc[i].n1 = tmpgain*(cn0[i]  cn1[i]);
vc[i].n0 = tmpgain*(cn1[i] + cn0[i]);
vc[i].d1 = tmpgain*(cd0[i]  cd1[i]);
vc[i].d0 = 1.0f;
tmpgain = 1.0f/(ecd1[i] + ecd0[i]);
ecvc[i].n1 = tmpgain*(ecn0[i]  ecn1[i]);
ecvc[i].n0 = tmpgain*(ecn1[i] + ecn0[i]);
ecvc[i].d1 = tmpgain*(ecd0[i]  ecd1[i]);
ecvc[i].d0 = 1.0f;
tmpgain = 1.0f/(od1[i] + od0[i]);
vcvo[i].n1 = tmpgain*(on0[i]  on1[i]);
vcvo[i].n0 = tmpgain*(on1[i] + on0[i]);
vcvo[i].d1 = tmpgain*(od0[i]  od1[i]);
vcvo[i].d0 = 1.0f;
tmpgain = 1.0f/(ed1[i] + ed0[i]);
vevo[i].n1 = tmpgain*(en0[i]  en1[i]);
vevo[i].n0 = tmpgain*(en1[i] + en0[i]);
vevo[i].d1 = tmpgain*(ed0[i]  ed1[i]);
vevo[i].d0 = 1.0f;
// bootstrap[i].n1
// bootstrap[i].n0
// bootstrap[i].d1
}
};
void
Vibe::modulate(float ldrl, float ldrr)
{
float tmpgain;
float R1pRv;
float C2pC1;
Rv = 4700.0f + ldrl;
R1pRv = R1 + Rv;
for(int i =0; i<8; i++)
{
if(i==4) {
Rv = 4700.0f + ldrr;
R1pRv = R1 + Rv;
}
C2pC1 = C2 + C1[i];
//Vo/Ve driven from emitter
ed1[i] = k*(R1pRv)*C1[i];
//ed1[i] = R1pRv*kC1[i];
// Vc~=Ve/(Ic*Re*alpha^2) collector voltage from current input.
//Output here represents voltage at the collector
cn1[i] = k*gain*Rv*C1[i];
//cn1[i] = kgainCl[i]*Rv;
//cd1[i] = (R1pRv)*C1[i];
cd1[i]=ed1[i];
//Contribution from emitter load through passive filter network
ecn1[i] = k*gain*R1*cd1[i]*C2/(Rv*(C2pC1));
//ecn1[i] = iC2pC1[i]*kgainR1C2*cd1[i]/Rv;
ecd1[i] = k*cd1[i]*C2/(C2pC1);
//ecd1[i] = iC2pC1[i]*k*cd1[i]*C2/(C2pC1);
// %Represents Vo/Vc. Output over collector voltage
on1[i] = k*Rv*C2;
od1[i] = on1[i];
//%Bilinear xform stuff
tmpgain = 1.0f/(cd1[i] + cd0[i]);
vc[i].n1 = tmpgain*(cn0[i]  cn1[i]);
vc[i].n0 = tmpgain*(cn1[i] + cn0[i]);
vc[i].d1 = tmpgain*(cd0[i]  cd1[i]);
tmpgain = 1.0f/(ecd1[i] + ecd0[i]);
ecvc[i].n1 = tmpgain*(ecn0[i]  ecn1[i]);
ecvc[i].n0 = tmpgain*(ecn1[i] + ecn0[i]);
ecvc[i].d1 = tmpgain*(ecd0[i]  ecd1[i]);
ecvc[i].d0 = 1.0f;
tmpgain = 1.0f/(od1[i] + od0[i]);
vcvo[i].n1 = tmpgain*(on0[i]  on1[i]);
vcvo[i].n0 = tmpgain*(on1[i] + on0[i]);
vcvo[i].d1 = tmpgain*(od0[i]  od1[i]);
tmpgain = 1.0f/(ed1[i] + ed0[i]);
vevo[i].n1 = tmpgain*(en0[i]  en1[i]);
vevo[i].n0 = tmpgain*(en1[i] + en0[i]);
vevo[i].d1 = tmpgain*(ed0[i]  ed1[i]);
}
};
5 comment(s)  add a comment  nofrills version 






Variablehardness clipping function
References : Posted by Laurent de Soras Linked file : laurent.gif
Notes : k >= 1 is the "clipping hardness". 1 gives a smooth clipping, and a high value gives hardclipping.
Don't set k too high, because the formula use the pow() function, which use exp() and would overflow easily. 100 seems to be a reasonable value for "hardclipping"
Code : f (x) = sign (x) * pow (atan (pow (abs (x), k)), (1 / k));
9 comment(s)  add a comment  nofrills version 






WaveShaper
Type : waveshaper References : Posted by Bram de Jong
Notes : where x (in [1..1] will be distorted and a is a distortion parameter that goes from 1 to infinity
The equation is valid for positive and negativ values.
If a is 1, it results in a slight distortion and with bigger a's the signal get's more funky.
A good thing about the shaper is that feeding it with biggerthanone
values, doesn't create strange fx. The maximum this function will reach is
1.2 for a=1.
Code : f(x,a) = x*(abs(x) + a)/(x^2 + (a1)*abs(x) + 1)
1 comment(s)  add a comment  nofrills version 






Waveshaper
Type : waveshaper References : Posted by Jon Watte
Notes : A favourite of mine is using a sin() function instead.
This will have the "unfortunate" side effect of removing
odd harmonics if you take it to the extreme: a triangle
wave gets mapped to a pure sine wave.
This will work with a going from .1 or so to a= 5 and bigger!
The mathematical limits for a = 0 actually turns it into a linear
function at that point, but unfortunately FPUs aren't that good
with calculus :) Once a goes above 1, you start getting clipping
in addition to the "soft" wave shaping. It starts getting into
more of an effect and less of a mastering tool, though :)
Seeing as this is just various forms of wave shaping, you
could do it all with a lookup table, too. In my version, that would
get rid of the somewhatexpensive sin() function.
Code : (input: a == "overdrive amount")
z = M_PI * a;
s = 1/sin(z)
b = 1/a
if (x > b)
f(x) = 1
else
f(x) = sin(z*x)*s
3 comment(s)  add a comment  nofrills version 






Waveshaper
References : Posted by Partice Tarrabia and Bram de Jong
Notes : amount should be in [1..1[ Plot it and stand back in astonishment! ;)
Code : x = input in [1..1]
y = output
k = 2*amount/(1amount);
f(x) = (1+k)*x/(1+k*abs(x))
3 comment(s)  add a comment  nofrills version 






Waveshaper (simple description)
Type : Polynomial; Distortion References : Posted by Jon Watte
Notes : > The other question; what's a 'waveshaper' algorithm. Is it simply another
> word for distortion?
A typical "waveshaper" is some function which takes an input sample value
X and transforms it to an output sample X'. A typical implementation would
be a lookup table of some number of points, and some level of interpolation
between those points (say, cubic). When people talk about a wave shaper,
this is most often what they mean. Note that a wave shaper, as opposed to a
filter, does not have any state. The mapping from X > X' is stateless.
Some wave shapers are implemented as polynomials, or using other math
functions. Hard clipping is a wave shaper implemented using the min() and
max() functions (or the threeargument clamp() function, which is the same
thing). A very mellow and musicalsounding distortion is implemented using
a thirddegree polynomial; something like X' = (3/2)X  (1/2)X^3. The nice
thing with polynomial wave shapers is that you know that the maximum they
will expand bandwidth is their order. Thus, you need to oversample 3x to
make sure that a thirddegree polynomial is aliasing free. With a lookup
table based wave shaper, you don't know this (unless you treat an Npoint
table as an Npoint polynomial :)
Code : float waveshape_distort( float in ) {
return 1.5f * in  0.5f * in *in * in;
}
4 comment(s)  add a comment  nofrills version 




