Main Archive Specials IRC Wiki | FAQ Links Submit Forum
Search

Analysis

Effects

Filters

Other

Synthesis

All

Entries in this category

2 Wave shaping things
Alien Wah
Band Limited PWM Generator
Bit quantization/reduction effect
Class for waveguide/delay effects
Compressor
Decimator
Delay time calculation for reverberation
DIRAC - Free C/C++ Library for Time and Pitch Manipulation of Audio Based on Time-Frequency Transforms
dynamic convolution
Early echo's with image-mirror technique
ECE320 project: Reverberation w/ parameter control from PC
fold back distortion
Guitar feedback
Lo-Fi Crusher
Lookahead Limiter
Most simple and smooth feedback delay
Most simple static delay
Parallel combs delay calculation
Phaser code
Polynominal Waveshaper
Reverberation Algorithms in Matlab
Reverberation techniques
Simple Compressor class (C++)
smsPitchScale Source Code
Soft saturation
Stereo Enhancer
Stereo Field Rotation Via Transformation Matrix
Stereo Width Control (Obtained Via Transfromation Matrix)
Time compression-expansion using standard phase vocoder
transistor differential amplifier simulation
UniVox Univibe Emulator
Variable-hardness clipping function
WaveShaper
Waveshaper
Waveshaper
Waveshaper (simple description)
Waveshaper :: Gloubi-boulga

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


Alien Wah

References : Nasca Octavian Paul ( paulnasca[AT]email.ro )
Linked file : alienwah.c

Notes :
"I found this algoritm by "playing around" with complex numbers. Please email me your opinions about it.

Paul."




3 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 44100Hz-raw-PCM-mono-wavefile.
// It is based on Tomisawa's self-phase-modulated sinewave generators.
// Rochebois uses a common phase accumulator to feed two half-Tomisawa-
// oscillators. Each half-Tomisawa-oscillator 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*(dphi-dphif);
    //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*(env-envf);     // de-clicked enveloppe
    B=1.0f;                    // feedback coefficient
    //try this for a nice bass sound:
    //B*=envf*envf;              // feedback controlled by enveloppe
    B*=2.3f*(1-0.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); // half-output 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); // half-output 1
    Y1=0.5f*(out1+Y1);            // anti "hunting" filter

    // combination, enveloppe and output
    short s=short(15000.0f*(out0-out1)*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 : Bit-level noise-generating effect
References : Posted by Jon Watte

Notes :
This function, run on each sample, will emulate half the effect of running your signal through a Speak-N-Spell or similar low-bit-depth circuitry.

The other half would come from downsampling with no aliasing control, i e replicating every N-th sample N times in the output signal.


Code :
short keep_bits_from_16( short input, int keepBits ) {
  return (input & (-1 << (16-keepBits)));
}



3 comment(s) | add a comment | nofrills version


Class for waveguide/delay effects

Type : IIR filter
References : Posted by arguru[AT]smartelectronix.com

Notes :
Flexible-time, non-sample quantized delay , can be used for stuff like waveguide synthesis or time-based (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)counter-delay;
        
        // clip lookback buffer-bound
        if(back<0.0)
            back=MAX_WG_DELAY+back;
        
        // compute interpolation left-floor
        int const index0=floor_int(back);
        
        // compute interpolation right-floor
        int index_1=index0-1;
        int index1=index0+1;
        int index2=index0+2;
        
        // clip interp. buffer-bound
        if(index_1<0)index_1=MAX_WG_DELAY-1;
        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*(y1-y_1);
        float const c2 = y_1 - 2.5f*y0 + 2.0f*y1 - 0.5f*y2;
        float const c3 = 0.5f*(y2-y_1) + 1.5f*(y0-y1);
        
        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 look-ahead 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 *= 1e-3;                // lookahead time to seconds
    twnd *= 1e-3;               // window time to seconds
    tatt *= 1e-3;               // attack time to seconds
    trel *= 1e-3;               // 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);   // root-mean-square

        // 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 : Bit-reducer 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 (bits-1);
cnt:=1;
rate:=shrate;
end;

function decimate(i:single):single;
begin
cnt:=cnt+rate;
if (cnt>1) then
begin
  cnt:=cnt-1;
  y:=round(i*m)/m;
end;
result:=y;
end;

********** C source **********
int bits=16;
float rate=0.5;

long int m=1<<(bits-1);
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 phase-shifter 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 Time-Frequency 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 overlap-add ([P]SOLA) algorithms for independent time and pitch manipulation of audio ("time stretching" and "pitch shifting") to be the method of choice for single-pitched 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 multi-pitched sounds and entire musical pieces.

"Dirac" is a free cross-platform C/C++ object library that exploits the good localization of time-frequency transforms in both domains to build an algorithm for time and pitch manipulation that uses an arbitrary time-frequency tiling depending on the underlying signal. Additionally, the time and frequency localization parameter of the basis can be user-defined, 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=steps-2, 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=L-1; j>0; j--)
        {
        x[j] = x[j-1];
        S[j] = S[j-1];
        }
    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 + (1-w)*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


Early echo's with image-mirror technique

References : Donald Schulz
Linked file : early_echo.c
Linked file : early_echo_eng.c

Notes :
(see linked files)
Donald Schulz's code for computing early echoes using the image-mirror method. There's an english and a german version.




no comments on this item | add a comment | nofrills version


ECE320 project: Reverberation w/ parameter control from PC

References : Posted by Brahim Hamadicharef (project by Hua Zheng and Shobhit Jain)
Linked file : rev.txt

Notes :
rev.asm
ECE320 project: Reverberation w/ parameter control from PC
Hua Zheng and Shobhit Jain
12/02/98 ~ 12/11/98
(se linked file)




no comments on this item | add a comment | nofrills version


fold back distortion

Type : distortion
References : Posted by hellfire[AT]upb[DOT]de

Notes :
a simple fold-back distortion filter.
if the signal exceeds the given threshold-level, it mirrors at the positive/negative threshold-border 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 - (in-threshold);
// mirror at negative threshold
if (in<-threshold) in= -threshold + (-threshold-in);
}


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 Karplus-Strong algorithm (this was described in a CMJ article in the early 90's):



Code :
Run the output of the Karplus-Strong 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 Karplus-Strong 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


Lo-Fi 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 1-13) 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 (0-1)

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_(k-1)/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


Phaser code

References : Posted by Ross Bencina
Linked file : phaser.cpp

Notes :
(see linked file)



10 comment(s) | 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 M-files implement a few reverberation algorithms (based on Schroeder's and Moorer's algorithms). Each of the M-files include a short description.

There are 5 M-files that implement reverberation. They are:

- schroeder1.m
- schroeder2.m
- schroeder3.m
- moorer.m
- stereoverb.m

The remaining 8 M-files implement filters, delay lines etc. Most of these are used in the above M-files. 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.

* 2nd-order 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 "figure-8" 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.

* Waveguide-based 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.

* Convolution-based reverbs, where the sound to be reverbed is convolved with the impulse response of a room, or with exponentially-decaying white noise. Supposedly the best sound, but very computationally expensive, and not very flexible.

* FIR-based 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, feed-forward, 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 ready-to-use C++ source code.

This is a C++ implementation of a simple, stereo, peak compressor. It uses a feed-forward topology, detecting the sidechain level pre-gain 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


smsPitchScale Source Code

Type : Pitch Scaling (often incorrectly referred to as "Pitch Shifting") using the Fourier transform
References : Posted by sms[AT]dspdimension.com
Linked file : http://www.dspdimension.com
Code :
See above web site

1 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 + (x-a)/(1+((x-a)/(1-a))^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


Time compression-expansion using standard phase vocoder

Type : vocoder phase time stretching
References : Posted by Cournape
Linked file : vocoder.m

Notes :
Standard phase vocoder. For imporved techniques ( faster ), see paper of Laroche : "Improved phase vocoder time-scale modification of audio"
Laroche, J.; Dolson, M.
Speech and Audio Processing, IEEE Transactions on , Volume: 7 Issue: 3 , May 1999
Page(s): 323 -332




17 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 SSE-Code yet) and performs in VST-Plugins 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;


8 comment(s) | add a comment | nofrills version


UniVox Univibe Emulator

Type : 4 Cascaded all-pass 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 all-pass 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 1rst-order 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 re-create 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 stand-alone 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) 2008-2010 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  02111-1307 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 turn-on 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 = 1e-6f;
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.015e-6f;
C1[1] = 0.22e-6f;
C1[2] = 470e-12f;
C1[3] = 0.0047e-6f;
C1[4] = 0.015e-6f;
C1[5] = 0.22e-6f;
C1[6] = 470e-12f;
C1[7] = 0.0047e-6f;

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


Variable-hardness 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 bigger-than-one
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 + (a-1)*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 look-up table, too. In my version, that would
get rid of the somewhat-expensive 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/(1-amount);

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 look-up 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 three-argument clamp() function, which is the same
thing). A very mellow and musical-sounding distortion is implemented using
a third-degree 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 third-degree polynomial is aliasing free. With a lookup
table based wave shaper, you don't know this (unless you treat an N-point
table as an N-point polynomial :-)


Code :
float waveshape_distort( float in ) {
  return 1.5f * in - 0.5f * in *in * in;
}


4 comment(s) | add a comment | nofrills version


Waveshaper :: Gloubi-boulga

References : Laurent de Soras on IRC

Notes :
Multiply input by gain before processing

Code :
const double x = input * 0.686306;
const double a = 1 + exp (sqrt (fabs (x)) * -0.75);
output = (exp (x) - exp (-x * a)) / (exp (x) + exp (-x));


18 comment(s) | add a comment | nofrills version