Main Archive Specials IRC Wiki | FAQ Links Submit Forum
Search

Analysis

Effects

Filters

Other

Synthesis

All

Entries in this category

(Allmost) Ready-to-use oscillators
Alias-free waveform generation with analog filtering
AM Formantic Synthesis
Another cheap sinusoidal LFO
another LFO class
antialiased square generator
Arbitary shaped band-limited waveform generation (using oversampling and low-pass filtering)
Audiable alias free waveform gen using width sine
Band Limited waveforms my way
Bandlimited sawtooth synthesis
Bandlimited waveform generation
Bandlimited waveform generation with hard sync
Bandlimited waveforms synopsis.
Bandlimited waveforms...
Butterworth
C# Oscilator class
C++ gaussian noise generation
chebyshev waveshaper (using their recursive definition)
Cubic polynomial envelopes
Direct pink noise synthesis with auto-correlated generator
Discrete Summation Formula (DSF)
Drift generator
DSF (super-set of BLIT)
Easy noise generation
Fast & small sine generation tutorial
Fast Exponential Envelope Generator
Fast LFO in Delphi...
Fast SIN approximation for usage in e.g. additive synthesizers
Fast sine and cosine calculation
Fast sine wave calculation
Fast square wave generator
Fast Whitenoise Generator
Gaussian White noise
Gaussian White Noise
Generator
Inverted parabolic envelope
matlab/octave code for minblep table generation
PADsynth synthesys method
Parabolic shaper
Phase modulation Vs. Frequency modulation
Phase modulation Vs. Frequency modulation II
PRNG for non-uniformly distributed values from trigonometric identity
Pseudo-Random generator
PulseQuad
Pulsewidth modulation
Quick & Dirty Sine
quick and dirty sine generator
randja compressor
RBJ Wavetable 101
Rossler and Lorenz Oscillators
SawSin
Simple Time Stretching-Granular Synthesizer
Sine calculation
Smooth random LFO Generator
Square Waves
Trammell Pink Noise (C++ class)
Waveform generator using MinBLEPS
Wavetable Synthesis
Weird synthesis

(Allmost) Ready-to-use oscillators

Type : waveform generation
References : Ross Bencina, Olli Niemitalo, ...

Notes :
Ross Bencina: original source code poster
Olli Niemitalo: UpdateWithCubicInterpolation


Code :
//this code is meant as an EXAMPLE

//uncomment if you need an FM oscillator
//define FM_OSCILLATOR

/*
members are:

float phase;
int TableSize;
float sampleRate;

float *table, dtable0, dtable1, dtable2, dtable3;

->these should be filled as folows... (remember to wrap around!!!)
table[i] = the wave-shape
dtable0[i] = table[i+1] - table[i];
dtable1[i] = (3.f*(table[i]-table[i+1])-table[i-1]+table[i+2])/2.f
dtable2[i] = 2.f*table[i+1]+table[i-1]-(5.f*table[i]+table[i+2])/2.f
dtable3[i] = (table[i+1]-table[i-1])/2.f
*/

float Oscillator::UpdateWithoutInterpolation(float frequency)
{
        int i = (int) phase;

        phase += (sampleRate/(float TableSize)/frequency;

        if(phase >= (float)TableSize)
                phase -= (float)TableSize;

#ifdef FM_OSCILLATOR
        if(phase < 0.f)
                phase += (float)TableSize;
#endif

        return table[i] ;
}

float Oscillator::UpdateWithLinearInterpolation(float frequency)
{
        int i = (int) phase;
        float alpha = phase - (float) i;

        phase += (sampleRate/(float)TableSize)/frequency;

        if(phase >= (float)TableSize)
                phase -= (float)TableSize;

#ifdef FM_OSCILLATOR
        if(phase < 0.f)
                phase += (float)TableSize;
#endif

        /*
        dtable0[i] = table[i+1] - table[i]; //remember to wrap around!!!
        */

        return table[i] + dtable0[i]*alpha;
}

float Oscillator::UpdateWithCubicInterpolation( float frequency )
{
        int i = (int) phase;
        float alpha = phase - (float) i;

        phase += (sampleRate/(float)TableSize)/frequency;

        if(phase >= (float)TableSize)
                phase -= (float)TableSize;

#ifdef FM_OSCILLATOR
        if(phase < 0.f)
                phase += (float)TableSize;
#endif

        /* //remember to wrap around!!!
        dtable1[i] = (3.f*(table[i]-table[i+1])-table[i-1]+table[i+2])/2.f
        dtable2[i] = 2.f*table[i+1]+table[i-1]-(5.f*table[i]+table[i+2])/2.f
        dtable3[i] = (table[i+1]-table[i-1])/2.f
        */

        return ((dtable1[i]*alpha + dtable2[i])*alpha + dtable3[i])*alpha+table[i];
}


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


Alias-free waveform generation with analog filtering

Type : waveform generation
References : Posted by Magnus Jonsson
Linked file : synthesis001.txt

Notes :
(see linkfile)



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


AM Formantic Synthesis

References : Posted by Paul Sernine

Notes :
Here is another tutorial from Doc Rochebois.
It performs formantic synthesis without filters and without grains. Instead, it uses "double carrier amplitude modulation" to pitch shift formantic waveforms. Just beware the phase relationships to avoid interferences. Some patches of the DX7 used the same trick but phase interferences were a problem. Here, Thierry Rochebois avoids them by using cosine-phased waveforms.

Various formantic waveforms are precalculated and put in tables, they correspond to different formant widths.
The runtime uses many intances (here 4) of these and pitch shifts them with double carriers (to preserve the harmonicity of the signal).

This is a tutorial code, it can be optimized in many ways.
Have Fun

Paul


Code :
// FormantsAM.cpp

// Thierry Rochebois' "Formantic Synthesis by Double Amplitude Modulation"

// Based on a tutorial by Thierry Rochebois.
// Comments by Paul Sernine.

// The spectral content of the signal is obtained by adding amplitude modulated formantic
// waveforms. The amplitude modulations spectraly shift the formantic waveforms.
// Continuous spectral shift, without losing the harmonic structure, is obtained
// by using crossfaded double carriers (multiple of the base frequency).
// To avoid  unwanted interference artifacts, phase relationships must be of the
// "cosine type".

// The output is a 44100Hz 16bit stereo PCM file.

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

//Approximates cos(pi*x) for x in [-1,1].
inline float fast_cos(const float x)
{
  float x2=x*x;
  return 1+x2*(-4+2*x2);
}

//Length of the table
#define L_TABLE (256+1) //The last entry of the table equals the first (to avoid a modulo)
//Maximal formant width
#define I_MAX 64
//Table of formants
float TF[L_TABLE*I_MAX];

//Formantic function of width I (used to fill the table of formants)
float fonc_formant(float p,const float I)
{
  float a=0.5f;
  int hmax=int(10*I)>L_TABLE/2?L_TABLE/2:int(10*I);
  float phi=0.0f;
  for(int h=1;h<hmax;h++)
  {
    phi+=3.14159265359f*p;
    float hann=0.5f+0.5f*fast_cos(h*(1.0f/hmax));
    float gaussienne=0.85f*exp(-h*h/(I*I));
    float jupe=0.15f;
    float harmonique=cosf(phi);
    a+=hann*(gaussienne+jupe)*harmonique;
   }
  return a;
}

//Initialisation of the table TF with the fonction fonc_formant.
void init_formant(void)
{ float coef=2.0f/(L_TABLE-1);
  for(int I=0;I<I_MAX;I++)
    for(int P=0;P<L_TABLE;P++)
      TF[P+I*L_TABLE]=fonc_formant(-1+P*coef,float(I));
}

//This function emulates the function fonc_formant
// thanks to the table TF. A bilinear interpolation is
// performed
float formant(float p,float i)
{
  i=i<0?0:i>I_MAX-2?I_MAX-2:i;    // width limitation
    float P=(L_TABLE-1)*(p+1)*0.5f; // phase normalisation
    int P0=(int)P;     float fP=P-P0;  // Integer and fractional
    int I0=(int)i;     float fI=i-I0;  // parts of the phase (p) and width (i).
    int i00=P0+L_TABLE*I0;     int i10=i00+L_TABLE;
    //bilinear interpolation.
    return (1-fI)*(TF[i00] + fP*(TF[i00+1]-TF[i00]))
        +    fI*(TF[i10] + fP*(TF[i10+1]-TF[i10]));
}

// Double carrier.
// h : position (float harmonic number)
// p : phase
float porteuse(const float h,const float p)
{
  float h0=floor(h);  //integer and
  float hf=h-h0;      //decimal part of harmonic number.
  // modulos pour ramener p*h0 et p*(h0+1) dans [-1,1]
  float phi0=fmodf(p* h0   +1+1000,2.0f)-1.0f;
  float phi1=fmodf(p*(h0+1)+1+1000,2.0f)-1.0f;
  // two carriers.
  float Porteuse0=fast_cos(phi0);  float Porteuse1=fast_cos(phi1);
  // crossfade between the two carriers.
  return Porteuse0+hf*(Porteuse1-Porteuse0);
}
int main()
{
  //Formant table for various french vowels (you can add your own)
  float F1[]={  730,  200,  400,  250,  190,  350,  550,  550,  450};
  float A1[]={ 1.0f, 0.5f, 1.0f, 1.0f, 0.7f, 1.0f, 1.0f, 0.3f, 1.0f};
  float F2[]={ 1090, 2100,  900, 1700,  800, 1900, 1600,  850, 1100};
  float A2[]={ 2.0f, 0.5f, 0.7f, 0.7f,0.35f, 0.3f, 0.5f, 1.0f, 0.7f};
  float F3[]={ 2440, 3100, 2300, 2100, 2000, 2500, 2250, 1900, 1500};
  float A3[]={ 0.3f,0.15f, 0.2f, 0.4f, 0.1f, 0.3f, 0.7f, 0.2f, 0.2f};
  float F4[]={ 3400, 4700, 3000, 3300, 3400, 3700, 3200, 3000, 3000};
  float A4[]={ 0.2f, 0.1f, 0.2f, 0.3f, 0.1f, 0.1f, 0.3f, 0.2f, 0.3f};

  float f0,dp0,p0=0.0f;
  int F=7; //number of the current formant preset
  float f1,f2,f3,f4,a1,a2,a3,a4;
  f1=f2=f3=f4=100.0f;a1=a2=a3=a4=0.0f;

  init_formant();
  FILE *f=fopen("sortie.pcm","wb");
  for(int ns=0;ns<10*44100;ns++)
  {
    if(0==(ns%11025)){F++;F%=8;} //formant change
    f0=12*powf(2.0f,4-4*ns/(10*44100.0f)); //sweep
    f0*=(1.0f+0.01f*sinf(ns*0.0015f));        //vibrato
    dp0=f0*(1/22050.0f);
    float un_f0=1.0f/f0;
    p0+=dp0;  //phase increment
    p0-=2*(p0>1);
    { //smoothing of the commands.
      float r=0.001f;
      f1+=r*(F1[F]-f1);f2+=r*(F2[F]-f2);f3+=r*(F3[F]-f3);f4+=r*(F4[F]-f4);
      a1+=r*(A1[F]-a1);a2+=r*(A2[F]-a2);a3+=r*(A3[F]-a3);a4+=r*(A4[F]-a4);
    }

    //The f0/fn coefficients stand for a -3dB/oct spectral enveloppe
    float out=
           a1*(f0/f1)*formant(p0,100*un_f0)*porteuse(f1*un_f0,p0)
     +0.7f*a2*(f0/f2)*formant(p0,120*un_f0)*porteuse(f2*un_f0,p0)
     +     a3*(f0/f3)*formant(p0,150*un_f0)*porteuse(f3*un_f0,p0)
     +     a4*(f0/f4)*formant(p0,300*un_f0)*porteuse(f4*un_f0,p0);

    short s=short(15000.0f*out);
    fwrite(&s,2,1,f);fwrite(&s,2,1,f); //fichier raw pcm stereo
  }
  fclose(f);
  return 0;
}


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


Another cheap sinusoidal LFO

References : Posted by info[at]e-phonic[dot]com

Notes :
Some pseudo code for a easy to calculate LFO.

You can even make a rough triangle wave out of this by substracting the output of 2 of these with different phases.

PJ



Code :
r = the rate 0..1

--------------
p += r
if(p > 1) p -= 2;
out = p*(1-abs(p));
--------------


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


another LFO class

References : Posted by mdsp
Linked file : LFO.zip

Notes :
This LFO uses an unsigned 32-bit phase and increment whose 8 Most Significant Bits adress a Look-up table while the 24 Least Significant Bits are used as the fractionnal part.
Note: As the phase overflow automatically, the index is always in the range 0-255.

It performs linear interpolation, but it is easy to add other types of interpolation.

Don't know how good it could be as an oscillator, but I found it good enough for a LFO.
BTW there is also different kind of waveforms.

Modifications:
We could use phase on 64-bit or change the proportion of bits used by the index and the fractionnal part.




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


antialiased square generator

Type : 1st April edition
References : Posted by Paul Sernine

Notes :
It is based on a code by Thierry Rochebois, obfuscated by me.
It generates a 16bit MONO raw pcm file. Have Fun.


Code :
//sqrfish.cpp
                       #include <math.h>
                        #include <stdio.h>
                        //obfuscation P.Sernine
int main()      {float ccc,cccc=0,CC=0,cc=0,CCCC,
     CCC,C,c;    FILE *CCCCCCC=fopen("sqrfish.pcm",
      "wb"  );  int ccccc= 0; float CCCCC=6.89e-6f;
      for(int CCCCCC=0;CCCCCC<1764000;CCCCCC++   ){
      if(!(CCCCCC%7350)){if(++ccccc>=30){ ccccc =0;
      CCCCC*=2;}CCC=1;}ccc=CCCCC*expf(0.057762265f*
      "aiakahiafahadfaiakahiahafahadf"[ccccc]);CCCC
      =0.75f-1.5f*ccc;cccc+=ccc;CCC*=0.9999f;cccc-=
      2*(cccc>1);C=cccc+CCCC*CC;  c=cccc+CCCC*cc; C
      -=2*(C>1);c-=2*(c>1);C+=2*(C<-1);      c+=1+2
      *(c<-1);c-=2*(c>1);C=C*C*(2 *C*C-4);
      c=c*c*(2*c*c-4); short cccccc=short(15000.0f*
      CCC*(C-c  )*CCC);CC=0.5f*(1+C+CC);cc=0.5f*(1+
     c+cc);      fwrite(&cccccc,2,1,CCCCCCC);}
//algo by              Thierry  Rochebois
                        fclose(CCCCCCC);
                       return 0000000;}


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


Arbitary shaped band-limited waveform generation (using oversampling and low-pass filtering)

References : Posted by remage[AT]kac[DOT]poliod[DOT]hu
Code :
Arbitary shaped band-limited waveform generation
(using oversampling and low-pass filtering)

There are many articles about band-limited waveform synthesis techniques, that provide correct and fast methods for generating classic analogue waveforms, such as saw, pulse, and triangle wave.  However, generating arbitary shaped band-limited waveforms, such as the "sawsin" shape (found in this source-code archive), seems to be quite hard using these techniques.

My analogue waveforms are generated in a _very_ high sampling rate (actually it's 1.4112 GHz for 44.1 kHz waveforms, using 32x oversampling).  Using this sample-rate, the amplitude of the aliasing harmonics are negligible (the base analogue waveforms has exponentially decreasing harmonics amplitudes).

Using a 511-tap windowed sync FIR filter (with Blackman-Harris window, and 12 kHz cutoff frequency) the harmonics above 20 kHz are killed, the higher harmonics (that cause the sharp overshoot at step response) are dampened.

The filtered signal downsampled to 44.1 kHz contains the audible (non-aliased) harmonics only.

This waveform synthesis is performed for wavetables of 4096, 2048, 1024, ... 8, 4, 2 samples.  The real-time signal is interpolated from these waveform-tables, using Hermite-(cubic-)interpolation for the waveforms, and linear interpolation between the two wavetables near the required note.

This procedure is quite time-consuming, but the whole waveform (or, in my implementation, the whole waveform-set) can be precalculated (or saved at first launch of the synth) and reloaded at synth initialization.

I don't know if this is a theoretically correct solution, but the waveforms sound good (no audible aliasing).  Please let me know if I'm wrong...


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


Audiable alias free waveform gen using width sine

Type : Very simple
References : Posted by joakim[DOT]dahlstrom[AT]ongame[DOT]com

Notes :
Warning, my english abilities is terribly limited.

How ever, the other day when finally understanding what bandlimited wave creation is (i am a noobie, been doing DSP stuf on and off for a half/year) it hit me i can implement one little part in my synths. It's all about the freq (that i knew), very simple you can reduce alias (the alias that you can hear that is) extremely by keeping track of your frequence, the way i solved it is using a factor, afact = 1 - sin(f*2PI). This means you can do audiable alias free synthesis without very complex algorithms or very huge tables, even though the sound becomes kind of low-filtered.
Propably something like this is mentioned b4, but incase it hasn't this is worth looking up

The psuedo code describes it more.

// Druttis


Code :
f := freq factor, 0 - 0.5 (0 to half samplingrate)

afact(f) = 1 - sin(f*2PI)

t := time (0 to ...)
ph := phase shift (0 to 1)
fm := freq mod (0 to 1)

sine(t,f,ph,fm) = sin((t*f+ph)*2PI + 0.5PI*fm*afact(f))

fb := feedback (0 to 1) (1 max saw)

saw(t,f,ph,fm,fb) = sine(t,f,ph,fb*sine(t-1,f,ph,fm))

pm := pulse mod (0 to 1) (1 max pulse)
pw := pulse width (0 to 1) (1 square)

pulse(t,f,ph,fm,fb,pm,pw) = saw(t,f,ph,fm,fb) - (t,f,ph+0.5*pw,fm,fb) * pm

I am not completely sure about fm for saw & pulse since i cant test that atm. but it should work :) otherwise just make sure fm are 0 for saw & pulse.

As you can see the saw & pulse wave are very variable.

// Druttis


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


Band Limited waveforms my way

Type : classic Sawtooth example
References : Posted by Anton Savov (antto mail bg)

Notes :
This is my <ugly> C++ code for generating a single cycle of a Sawtooth in a table
normaly i create my "fundamental" table big enough to hold on around 20-40Hz in the current Sampling rate
also, i create the table twice as big, i do "mip-maps" then
so the size should be a power of two, say 1024 for 44100Hz = 44100/1024 = ~43.066Hz
then the mip-maps are with decreasing sizes (twice) 512, 256, 128, 64, 32, 16, 8, 4, and 2

if the "gibbs" effect is what i think it is - then i have a simple solution
here is my crappy code:


Code :
int sz = 1024; // the size of the table
int i = 0;
float *table; // pointer to the table
double scale = 1.0;
double pd; // phase
double omega = 1.0 / (double)(sz);

while (i < sz)
{
    double amp = scale;
    double x = 0.0; // the sample
    double h = 1; // harmonic number (starts from 1)
    double dd; // fix high frequency "ring"
    pd = (double)(i) / (double)(sz); // calc phase
    double hpd = pd; // phase of the harmonic
    while (true) // start looping for this sample
    {
        if ((omega * h) < 0.5) // harmonic frequency is in range?
        {
            dd = cos(omega * h * 2 * pi);
            x = x + (amp * dd * sin(hpd * 2 * pi));
            h = h + 1;
            hpd = pd * h;
            amp = 1.0 / h;
        }
        else { break; }
    }
    table[i] = x;
    ++i;
}

the peaks are around +/- 0.8
a square can be generated by just changing h = h+2; the peaks would be +/- 0.4

any bugs/improvements?


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


Bandlimited sawtooth synthesis

Type : DSF BLIT
References : Posted by emanuel.landeholm [AT] telia.com
Linked file : synthesis002.txt

Notes :
This is working code for synthesizing a bandlimited sawtooth waveform. The algorithm is DSF BLIT + leaky integrator. Includes driver code.

There are two parameters you may tweak:

1) Desired attenuation at nyquist. A low value yields a duller sawtooth but gets rid of those annoying CLICKS when sweeping the frequency up real high. Must be strictly less than 1.0!

2) Integrator leakiness/cut off. Affects the shape of the waveform to some extent, esp. at the low end. Ideally you would want to set this low, but too low a setting will give you problems with DC.

Have fun!
/Emanuel Landeholm

(see linked file)




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


Bandlimited waveform generation

Type : waveform generation
References : Posted by Joe Wright
Linked file : bandlimited.cpp
Linked file : bandlimited.pdf

Notes :
(see linkfile)



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


Bandlimited waveform generation with hard sync

References : Posted by Emanuel Landeholm
Linked file : http://www.algonet.se/~e-san/hardsync.tar.gz


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


Bandlimited waveforms synopsis.

References : Joe Wright
Linked file : waveforms.txt

Notes :
(see linkfile)



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


Bandlimited waveforms...

References : Posted by Paul Kellet

Notes :
(Quoted from Paul's mail)
Below is another waveform generation method based on a train of sinc functions (actually an alternating loop along a sinc between t=0 and t=period/2).

The code integrates the pulse train with a dc offset to get a sawtooth, but other shapes can be made in the usual ways... Note that 'dc' and 'leak' may need to be adjusted for very high or low frequencies.

I don't know how original it is (I ought to read more) but it is of usable quality, particularly at low frequencies. There's some scope for optimisation by using a table for sinc, or maybe a a truncated/windowed sinc?

I think it should be possible to minimise the aliasing by fine tuning 'dp' to slightly less than 1 so the sincs join together neatly, but I haven't found the best way to do it. Any comments gratefully received.


Code :
float p=0.0f;      //current position
float dp=1.0f;     //change in postion per sample
float pmax;        //maximum position
float x;           //position in sinc function
float leak=0.995f; //leaky integrator
float dc;          //dc offset
float saw;         //output


//set frequency...

  pmax = 0.5f * getSampleRate() / freqHz;
  dc = -0.498f/pmax;


//for each sample...

  p += dp;
  if(p < 0.0f)
  {
    p = -p;
    dp = -dp;
  }
  else if(p > pmax)
  {
    p = pmax + pmax - p;
    dp = -dp;
  }

  x= pi * p;
  if(x < 0.00001f)
     x=0.00001f; //don't divide by 0

  saw = leak*saw + dc + (float)sin(x)/(x);


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


Butterworth

Type : LPF 24dB/Oct
References : Posted by Christian[at]savioursofsoul[dot]de
Code :
First calculate the prewarped digital frequency:

K = tan(Pi * Frequency / Samplerate);

Now calc some intermediate variables: (see 'Factors of Polynoms' at http://en.wikipedia.org/wiki/Butterworth_filter, especially if you want a higher order like 48dB/Oct)
a = 0.76536686473 * Q * K;
b = 1.84775906502 * Q * K;

K = K*K; (to optimize it a little bit)

Calculate the first biquad:

A0 = (K+a+1);
A1 = 2*(1-K);
A2 =(a-K-1);
B0 = K;
B1 = 2*B0;
B2 = B0;

Calculate the second biquad:

A3 = (K+b+1);
A4 = 2*(1-K);
A5 = (b-K-1);
B3 = K;
B4 = 2*B3;
B5 = B3;

Then calculate the output as follows:

Stage1 = B0*Input + State0;
State0 = B1*Input + A1/A0*Stage1 + State1;
State1 = B2*Input + A2/A0*Stage1;

Output = B3*Stage1 + State2;
State2 = B4*Stage1 + A4/A3*Output + State2;
State3 = B5*Stage1 + A5/A3*Output;


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


C# Oscilator class

Type : Sine, Saw, Variable Pulse, Triangle, C64 Noise
References : Posted by neotec

Notes :
Parameters:

Pitch: The Osc's pitch in Cents [0 - 14399] startig at A -> 6.875Hz
Pulsewidth: [0 - 65535] -> 0% to 99.99%
Value: The last Output value, a set to this property 'syncs' the Oscilator


Code :
public class SynthOscilator
{
    public enum OscWaveformType
    {
        SAW, PULSE, TRI, NOISE, SINE
    }

    public int Pitch
    {
        get
        {
            return this._Pitch;
        }
        set
        {
            this._Pitch = this.MinMax(0, value, 14399);
            this.OscStep = WaveSteps[this._Pitch];
        }
    }

    public int PulseWidth
    {
        get
        {
            return this._PulseWidth;
        }
        set
        {
            this._PulseWidth = this.MinMax(0, value, 65535);
        }
    }

    public OscWaveformType Waveform
    {
        get
        {
            return this._WaveForm;
        }
        set
        {
            this._WaveForm = value;
        }
    }

    public int Value
    {
        get
        {
            return this._Value;
        }
        set
        {
            this._Value = 0;
            this.OscNow = 0;
        }
    }

    private int _Pitch;
    private int _PulseWidth;
    private int _Value;
    private OscWaveformType _WaveForm;

    private int OscNow;
    private int OscStep;
    private int ShiftRegister;

    public const double BaseFrequence = 6.875;
    public const int SampleRate = 44100;
    public static int[] WaveSteps = new int[0];
    public static int[] SineTable = new int[0];
    
    public SynthOscilator()
    {
        if (WaveSteps.Length == 0)
            this.CalcSteps();

        if (SineTable.Length == 0)
            this.CalcSine();

        this._Pitch = 7200;
        this._PulseWidth = 32768;
        this._WaveForm = OscWaveformType.SAW;

        this.ShiftRegister = 0x7ffff8;

        this.OscNow = 0;
        this.OscStep = WaveSteps[this._Pitch];
        this._Value = 0;
    }

    private void CalcSteps()
    {
        WaveSteps = new int[14400];

        for (int i = 0; i < 14400; i++)
        {
            double t0, t1, t2;

            t0 = Math.Pow(2.0, (double)i / 1200.0);
            t1 = BaseFrequence * t0;
            t2 = (t1 * 65536.0) / (double)this.SampleRate;

            WaveSteps[i] = (int)Math.Round(t2 * 4096.0);
        }
    }

    private void CalcSine()
    {
        SineTable = new int[65536];

        double s = Math.PI / 32768.0;

        for (int i = 0; i < 65536; i++)
        {
            double v = Math.Sin((double)i * s) * 32768.0;

            int t = (int)Math.Round(v) + 32768;

            if (t < 0)
                t = 0;
            else if (t > 65535)
                t = 65535;

            SineTable[i] = t;
        }
    }
    
    public override int Run()
    {
        int ret = 32768;
        int osc = this.OscNow >> 12;

        switch (this._WaveForm)
        {
            case OscWaveformType.SAW:
                ret = osc;
                break;
            case OscWaveformType.PULSE:
                if (osc < this.PulseWidth)
                    ret = 65535;
                else
                    ret = 0;
                break;
            case OscWaveformType.TRI:
                if (osc < 32768)
                    ret = osc << 1;
                else
                    ret = 131071 - (osc << 1);
                break;
            case OscWaveformType.NOISE:
                ret = ((this.ShiftRegister & 0x400000) >> 11) |
                  ((this.ShiftRegister & 0x100000) >> 10) |
                  ((this.ShiftRegister & 0x010000) >> 7) |
                  ((this.ShiftRegister & 0x002000) >> 5) |
                  ((this.ShiftRegister & 0x000800) >> 4) |
                  ((this.ShiftRegister & 0x000080) >> 1) |
                  ((this.ShiftRegister & 0x000010) << 1) |
                  ((this.ShiftRegister & 0x000004) << 2);
                ret <<= 4;
                break;
            case OscWaveformType.SINE:
                ret = SynthTools.SineTable[osc];
                break;
            default:
                break;
        }

        this.OscNow += this.OscStep;

        if (this.OscNow > 0xfffffff)
        {
            int bit0 = ((this.ShiftRegister >> 22) ^ (this.ShiftRegister >> 17)) & 0x1;
            this.ShiftRegister <<= 1;
            this.ShiftRegister &= 0x7fffff;
            this.ShiftRegister |= bit0;
        }

        this.OscNow &= 0xfffffff;

        this._Value = ret - 32768;

        return this._Value;
    }

    public int MinMax(int a, int b, int c)
    {
        if (b < a)
            return a;
        else if (b > c)
            return c;
        else
            return b;
    }
}


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


C++ gaussian noise generation

Type : gaussian noise generation
References : Posted by paul[at]expdigital[dot]co[dot]uk

Notes :
References :
Tobybears delphi noise generator was the basis. Simply converted it to C++.
Link for original is:
http://www.musicdsp.org/archive.php?classid=0#129
The output is in noise.


Code :
/* Include requisits */
#include <cstdlib>
#include <ctime>

/* Generate a new random seed from system time - do this once in your constructor */
srand(time(0));

/* Setup constants */
const static int q = 15;
const static float c1 = (1 << q) - 1;
const static float c2 = ((int)(c1 / 3)) + 1;
const static float c3 = 1.f / c1;

/* random number in range 0 - 1 not including 1 */
float random = 0.f;

/* the white noise */
float noise = 0.f;

for (int i = 0; i < numSamples; i++)
{
    random = ((float)rand() / (float)(RAND_MAX + 1));
    noise = (2.f * ((random * c2) + (random * c2) + (random * c2)) - 3.f * (c2 - 1.f)) * c3;
}


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


chebyshev waveshaper (using their recursive definition)

Type : chebyshev
References : Posted by mdsp

Notes :
someone asked for it on kvr-audio.

I use it in an unreleased additive synth.
There's no oversampling needed in my case since I feed it with a pure sinusoid and I control the order to not have frequencies above Fs/2. Otherwise you should oversample by the order you'll use in the function or bandlimit the signal before the waveshaper. unless you really want that aliasing effect... :)

I hope the code is self-explaining, otherwise there's plenty of sites explaining chebyshev polynoms and their applications.


Code :
float chebyshev(float x, float A[], int order)
{
   // To = 1
   // T1 = x
   // Tn = 2.x.Tn-1 - Tn-2
   // out = sum(Ai*Ti(x)) , i C {1,..,order}
   float Tn_2 = 1.0f;
   float Tn_1 = x;
   float Tn;
   float out = A[0]*Tn_1;

   for(int n=2;n<=order;n++)
   {
      Tn    =   2.0f*x*Tn_1 - Tn_2;
      out    +=   A[n-1]*Tn;      
      Tn_2 =   Tn_1;
      Tn_1 =  Tn;
   }
   return out;
}


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


Cubic polynomial envelopes

Type : envellope generation
References : Posted by Andy Mucho

Notes :
This function runs from:
startlevel at Time=0
midlevel at Time/2
endlevel at Time
At moments of extreme change over small time, the function can generate out
of range (of the 3 input level) numbers, but isn't really a problem in
actual use with real numbers, and sensible/real times..


Code :
time = 32
startlevel = 0
midlevel = 100
endlevel = 120
k = startlevel + endlevel - (midlevel * 2)
r = startlevel
s = (endlevel - startlevel - (2 * k)) / time
t = (2 * k) / (time * time)
bigr = r
bigs = s + t
bigt = 2 * t

for(int i=0;i<time;i++)
{
bigr = bigr + bigs
bigs = bigs + bigt
}


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


Direct pink noise synthesis with auto-correlated generator

Type : 16-bit fixed-point
References : Posted by RidgeRat

Notes :
Canonical C++ class with minimum system dependencies, BUT you must provide your own uniform random number generator. Accurate range is a little over 9 octaves, degrading gracefully beyond this. Estimated deviations +-0.25 dB from ideal 1/f curve in range. Scaled to fit signed 16-bit range.

Code :
// Pink noise class using the autocorrelated generator method.
// Method proposed and described by Larry Trammell "the RidgeRat" --
// see http://home.earthlink.net/~ltrammell/tech/newpink.htm
// There are no restrictions.
//
// ------------------------------------------------------------------
//
// This is a canonical, 16-bit fixed-point implementation of the
// generator in 32-bit arithmetic. There are only a few system
// dependencies.
//
//   -- access to an allocator 'malloc' for operator new
//   -- access to definition of 'size_t'
//   -- assumes 32-bit two's complement arithmetic
//   -- assumes long int is 32 bits, short int is 16 bits
//   -- assumes that signed right shift propagates the sign bit
//
// It needs a separate URand class to provide uniform 16-bit random
// numbers on interval [1,65535]. The assumed class must provide
// methods to query and set the current seed value, establish a
// scrambled initial seed value, and evaluate uniform random values.
//
//
// ----------- header -----------------------------------------------
// pinkgen.h

#ifndef  _pinkgen_h_
#define  _pinkgen_h_  1

#include  <stddef.h>
#include  <alloc.h>

// You must provide the uniform random generator class.
#ifndef  _URand_h_
#include  "URand.h"
#endif

class PinkNoise {
  private:
    // Coefficients (fixed)
    static long int const pA[5];
    static short int const pPSUM[5];

    // Internal pink generator state
    long int   contrib[5];   // stage contributions
    long int   accum;        // combined generators
    void       internal_clear( );          

    // Include a UNoise component
    URand     ugen;

  public:
    PinkNoise( );
    PinkNoise( PinkNoise & );
    ~PinkNoise( );
    void *  operator new( size_t );
    void  pinkclear( );
    short int  pinkrand( );
} ;
#endif

// ----------- implementation ---------------------------------------
// pinkgen.cpp

#include  "pinkgen.h"

// Static class data
long int const PinkNoise::pA[5] =
    { 14055, 12759, 10733, 12273, 15716 };
short int const PinkNoise::pPSUM[5] =
    { 22347, 27917, 29523, 29942, 30007 };

// Clear generator to a zero state.
void   PinkNoise::pinkclear( )
{
    int  i;
    for  (i=0; i<5; ++i)  { contrib[i]=0L; }
    accum = 0L;
}

// PRIVATE, clear generator and also scramble the internal
// uniform generator seed.
void   PinkNoise::internal_clear( )
{
    pinkclear();
    ugen.seed(0);    // Randomizes the seed!
}

// Constructor. Guarantee that initial state is cleared
// and uniform generator scrambled.
PinkNoise::PinkNoise( )
{
    internal_clear();
}

// Copy constructor. Preserve generator state from the source
// object, including the uniform generator seed.
PinkNoise::PinkNoise( PinkNoise & Source )
{
    int  i;
    for (i=0; i<5; ++i)  contrib[i]=Source.contrib[i];
    accum = Source.accum;
    ugen.seed( Source.ugen.seed( ) );
}

// Operator new. Just fetch required object storage.
void *   PinkNoise::operator new( size_t size )
{
    return   malloc(size);
}

// Destructor. No special action required.
PinkNoise::~PinkNoise( )  { /* NIL */ }

// Coding artifact for convenience
#define   UPDATE_CONTRIB(n)  \
     {                                   \
       accum -= contrib[n];              \
       contrib[n] = (long)randv * pA[n]; \
       accum += contrib[n];              \
       break;                            \
     }                                  

// Evaluate next randomized 'pink' number with uniform CPU loading.
short int   PinkNoise::pinkrand( )
{
    short int  randu = ugen.urand() & 0x7fff;     // U[0,32767]
    short int  randv = (short int) ugen.urand();  // U[-32768,32767]

    // Structured block, at most one update is performed
    while (1)
    {
      if (randu < pPSUM[0]) UPDATE_CONTRIB(0);
      if (randu < pPSUM[1]) UPDATE_CONTRIB(1);
      if (randu < pPSUM[2]) UPDATE_CONTRIB(2);
      if (randu < pPSUM[3]) UPDATE_CONTRIB(3);
      if (randu < pPSUM[4]) UPDATE_CONTRIB(4);
      break;
    }
    return (short int) (accum >> 16);
}

// ----------- application   -------------------------------

short int    pink_signal[1024];

void   example(void)
{
    PinkNoise    pinkgen;
    int  i;
    for  (i=0; i<1024; ++i)   pink_signal[i] = pinkgen.pinkrand();
}


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


Discrete Summation Formula (DSF)

References : Stylson, Smith and others... (posted by Alexander Kritov)

Notes :
Buzz uses this type of synth.
For cool sounds try to use variable,
for example a=exp(-x/12000)*0.8 // x- num.samples


Code :
double DSF (double x,  // input
            double a,  // a<1.0
            double N,  // N<SmplFQ/2,
            double fi) // phase
{
  double s1 = pow(a,N-1.0)*sin((N-1.0)*x+fi);
  double s2 = pow(a,N)*sin(N*x+fi);
  double s3 = a*sin(x+fi);
  double s4 =1.0 - (2*a*cos(x)) +(a*a);
  if (s4==0)
     return 0;
  else
     return (sin(fi) - s3 - s2 +s1)/s4;
}


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


Drift generator

Type : Random
References : Posted by quintosardo[AT]yahoo[DOT]it

Notes :
I use this drift to modulate any sound parameter of my synth.
It is very effective if it slightly modulates amplitude or frequency of an FM modulator.
It is based on an incremental random variable, sine-warped.
I like it because it is "continuous" (as opposite to "sample and hold"), and I can set variation rate and max variation.
It can go to upper or lower constraint (+/- max drift) but it gradually decreases rate of variation when approaching to the limit.
I use it exactly as an LFO (-1.f .. +1.f)
I use a table for sin instead of sin() function because this way I can change random distribution, by selecting a different curve (different table) from sine...

I hope that it is clear ... (sigh... :-)
Bye!!!
P.S. Thank you for help in previous submission ;-)


Code :
const int kSamples //Number of samples in fSinTable below
float fSinTable[kSamples] // Tabulated sin() [0 - 2pi[ amplitude [-1.f .. 1.f]
float fWhere// Index
float fRate // Max rate of variation
float fLimit //max or min value
float fDrift // Output

//I assume that random() is a number from 0.f to 1.f, otherwise scale it

fWhere += fRate * random()
//I update this drift in a long-term cycle, so I don't care of branches
if (fWhere >= 1.f) fWhere -= 1.f
else if (fWhere < 0.f) sWhere += 1.f

fDrift = fLimit * fSinTable[(long) (fWhere * kSamples)]


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


DSF (super-set of BLIT)

Type : matlab code
References : Posted by David Lowenfels

Notes :
Discrete Summation Formula ala Moorer

computes equivalent to sum{k=0:N-1}(a^k * sin(beta + k*theta))
modified from Emanuel Landeholm's C code
output should never clip past [-1,1]

If using for BLIT synthesis for virtual analog:
N = maxN;
a = attn_at_Nyquist ^ (1/maxN); %hide top harmonic popping in and out when sweeping frequency
beta = pi/2;
num = 1 - a^N * cos(N*theta) - a*( cos(theta) - a^N * cos(N*theta - theta) ); %don't waste time on beta

You can also get growing harmonics if a > 1, but the min statement in the code must be removed, and the scaling will be weird.


Code :
function output = dsf( freq, a, H, samples, beta)
%a = rolloff coeffecient
%H = number of harmonic overtones (fundamental not included)
%beta = harmonic phase shift

samplerate = 44.1e3;
freq = freq/samplerate; %normalize frequency

bandlimit = samplerate / 2; %Nyquist
maxN = 1 + floor( bandlimit / freq ); %prevent aliasing
N = min(H+2,maxN);

theta = 2*pi * phasor(freq, samples);

epsilon = 1e-6;
a = min(a, 1-epsilon); %prevent divide by zero

num = sin(beta) - a*sin(beta-theta) - a^N*sin(beta + N*theta) + a^(N+1)*sin(beta+(N-1)*theta);
den = (1 + a * ( a - 2*cos(theta) ));

output = 2*(num ./ den - 1) * freq; %subtract by one to remove DC, scale by freq to normalize
output = output * maxN/N;           %OPTIONAL: rescale to give louder output as rolloff increases

function out = phasor(normfreq, samples);
out = mod( (0:samples-1)*normfreq , 1);
out = out * 2 - 1;                  %make bipolar


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


Easy noise generation

Type : White Noise
References : Posted by mail[AT]ihsan-dsp[DOT]com

Notes :
Easy noise generation,
in .hpp,
b_noise = 19.1919191919191919191919191919191919191919;

alternatively, the number 19 below can be replaced with a number of your choice, to get that particular flavour of noise.

Regards,
Ove Karlsen.


Code :
    b_noise = b_noise * b_noise;
    int i_noise = b_noise;
    b_noise = b_noise - i_noise;

    double b_noiseout;
    b_noiseout = b_noise - 0.5;

    b_noise = b_noise + 19;


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


Fast & small sine generation tutorial

Type : original document link: www.active-web.cc/html/research/sine/sin-cos.txt
References : Posted by office[AT]develotec[DOT]com
Linked file : http://www.active-web.cc/html/research/sine/sin-cos.txt

Notes :
original document link: www.active-web.cc/html/research/sine/sin-cos.txt



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


Fast Exponential Envelope Generator

References : Posted by Christian Schoenebeck

Notes :
The naive way to implement this would be to use a exp() call for each point
of the envelope. Unfortunately exp() is quite a heavy function for most
CPUs, so here is a numerical, much faster way to compute an exponential
envelope (performance gain measured in benchmark: about factor 100 with a
Intel P4, gcc -O3 --fast-math -march=i686 -mcpu=i686).

Note: you can't use a value of 0.0 for levelEnd. Instead you have to use an
appropriate, very small value (e.g. 0.001 should be sufficiently small
enough).


Code :
const float sampleRate = 44100;
float coeff;
float currentLevel;

void init(float levelBegin, float levelEnd, float releaseTime) {
    currentLevel = levelBegin;
    coeff = (log(levelEnd) - log(levelBegin)) /
            (releaseTime * sampleRate);
}

inline void calculateEnvelope(int samplePoints) {
    for (int i = 0; i < samplePoints; i++) {
        currentLevel += coeff * currentLevel;
        // do something with 'currentLevel' here
        ...
    }
}


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


Fast LFO in Delphi...

References : Posted by Dambrin Didier ( gol [AT] e-officedirect [DOT] com )
Linked file : LFOGenerator.zip

Notes :
[from Didier's mail...]
[see attached zip file too!]

I was working on a flanger, & needed an LFO for it. I first used a Sin(), but it was too slow, then tried a big wavetable, but it wasn't accurate enough.

I then checked the alternate sine generators from your web site, & while they're good, they all can drift, so you're also wasting too much CPU in branching for the drift checks.

So I made a quick & easy linear LFO, then a sine-like version of it. Can be useful for LFO's, not to output as sound.
If has no branching & is rather simple. 2 Abs() but apparently they're fast. In all cases faster than a Sin()


It's in delphi, but if you understand it you can translate it if you want.
It uses a 32bit integer counter that overflows, & a power for the sine output.
If you don't know delphi, $ is for hex (h at the end in c++?), Single is 32bit float, integer is 32bit integer (signed, normally).


Code :
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    Bevel1: TBevel;
    procedure PaintBox1Paint(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.PaintBox1Paint(Sender: TObject);
var n,Pos,Speed:Integer;
    Output,Scale,HalfScale,PosMul:Single;
    OurSpeed,OurScale:Single;
begin
OurSpeed:=100;  // 100 samples per cycle
OurScale:=100;  // output in -100..100

Pos:=0;  // position in our linear LFO
Speed:=Round($100000000/OurSpeed);


// --- triangle LFO ---
Scale:=OurScale*2;
PosMul:=Scale/$80000000;

// loop
for n:=0 to 299 do
  Begin
  // inc our 32bit integer LFO pos & let it overflow. It will be seen as signed when read by the math unit
  Pos:=Pos+Speed;

  Output:=Abs(Pos*PosMul)-OurScale;

  // visual
  Paintbox1.Canvas.Pixels[n,Round(100+Output)]:=clRed;
  End;


// --- sine-like LFO ---
Scale:=Sqrt(OurScale*4);
PosMul:=Scale/$80000000;
HalfScale:=Scale/2;

// loop
for n:=0 to 299 do
  Begin
  // inc our 32bit integer LFO pos & let it overflow. It will be seen as signed when read by the math unit
  Pos:=Pos+Speed;

  Output:=Abs(Pos*PosMul)-HalfScale;
  Output:=Output*(Scale-Abs(Output));

  // visual
  Paintbox1.Canvas.Pixels[n,Round(100+Output)]:=clBlue;
  End;
end;

end.


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


Fast SIN approximation for usage in e.g. additive synthesizers

References : Posted by neotec

Notes :
This code presents 2 'fastsin' functions. fastsin2 is less accurate than fastsin. In fact it's a simple taylor series, but optimized for integer phase.

phase is in 0 -> (2^32)-1 range and maps to 0 -> ~2PI

I get about 55000000 fastsin's per second on my P4,3.2GHz which would give a nice Kawai K5 emulation using 64 harmonics and 8->16 voices.


Code :
float fastsin(UINT32 phase)
{
    const float frf3 = -1.0f / 6.0f;
    const float frf5 = 1.0f / 120.0f;
    const float frf7 = -1.0f / 5040.0f;
    const float frf9 = 1.0f / 362880.0f;
    const float f0pi5 = 1.570796327f;
    float x, x2, asin;
    UINT32 tmp = 0x3f800000 | (phase >> 7);
    if (phase & 0x40000000)
        tmp ^= 0x007fffff;
    x = (*((float*)&tmp) - 1.0f) * f0pi5;
    x2 = x * x;
    asin = ((((frf9 * x2 + frf7) * x2 + frf5) * x2 + frf3) * x2 + 1.0f) * x;
    return (phase & 0x80000000) ? -asin : asin;
}

float fastsin2(UINT32 phase)
{
    const float frf3 = -1.0f / 6.0f;
    const float frf5 = 1.0f / 120.0f;
    const float frf7 = -1.0f / 5040.0f;
    const float f0pi5 = 1.570796327f;
    float x, x2, asin;
    UINT32 tmp = 0x3f800000 | (phase >> 7);
    if (phase & 0x40000000)
        tmp ^= 0x007fffff;
    x = (*((float*)&tmp) - 1.0f) * f0pi5;
    x2 = x * x;
    asin = (((frf7 * x2 + frf5) * x2 + frf3) * x2 + 1.0f) * x;
    return (phase & 0x80000000) ? -asin : asin;
}


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


Fast sine and cosine calculation

Type : waveform generation
References : Lot's or references... Check Julius O. SMith mainly
Code :
init:
float a = 2.f*(float)sin(Pi*frequency/samplerate);

float s[2];

s[0] = 0.5f;
s[1] = 0.f;

loop:
s[0] = s[0] - a*s[1];
s[1] = s[1] + a*s[0];
output_sine = s[0];
output_cosine = s[1]


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


Fast sine wave calculation

Type : waveform generation
References : James McCartney in Computer Music Journal, also the Julius O. Smith paper

Notes :
(posted by Niels Gorisse)
If you change the frequency, the amplitude rises (pitch lower) or lowers (pitch rise) a LOT I fixed the first problem by thinking about what actually goes wrong. The answer was to recalculate the phase for that frequency and the last value, and then continue normally.


Code :
Variables:
ip = phase of the first output sample in radians
w = freq*pi / samplerate
b1 = 2.0 * cos(w)

Init:
y1=sin(ip-w)
y2=sin(ip-2*w)

Loop:
y0 = b1*y1 - y2
y2 = y1
y1 = y0

output is in y0 (y0 = sin(ip + n*freq*pi / samplerate), n= 0, 1, 2, ... I *think*)

Later note by James McCartney:
if you unroll such a loop by 3 you can even eliminate the assigns!!

y0 = b1*y1 - y2
y2 = b1*y0 - y1
y1 = b1*y2 - y0


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


Fast square wave generator

Type : NON-bandlimited osc...
References : Posted by Wolfgang (wschneider[AT]nexoft.de)

Notes :
Produces a square wave -1.0f .. +1.0f.
The resulting waveform is NOT band-limited, so it's propably of not much use for syntheis. It's rather useful for LFOs and the like, though.


Code :
Idea: use integer overflow to avoid conditional jumps.

// init:
typedef unsigned long ui32;

float sampleRate = 44100.0f; // whatever
float freq = 440.0f; // 440 Hz
float one = 1.0f;
ui32 intOver = 0L;
ui32 intIncr = (ui32)(4294967296.0 / hostSampleRate / freq));

// loop:
(*((ui32 *)&one)) &= 0x7FFFFFFF; // mask out sign bit
(*((ui32 *)&one)) |= (intOver & 0x80000000);
intOver += intIncr;


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


Fast Whitenoise Generator

Type : Whitenoise
References : Posted by gerd[DOT]feldkirch[AT]web[DOT]de

Notes :
This is Whitenoise... :o)

Code :
float g_fScale = 2.0f / 0xffffffff;
int g_x1 = 0x67452301;
int g_x2 = 0xefcdab89;

void whitenoise(
  float* _fpDstBuffer, // Pointer to buffer
  unsigned int _uiBufferSize, // Size of buffer
  float _fLevel ) // Noiselevel (0.0 ... 1.0)
{
  _fLevel *= g_fScale;

  while( _uiBufferSize-- )
  {
    g_x1 ^= g_x2;
    *_fpDstBuffer++ = g_x2 * _fLevel;
    g_x2 += g_x1;
  }
}


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


Gaussian White noise

References : Posted by Alexey Menshikov

Notes :
Code I use sometimes, but don't remember where I ripped it from.

- Alexey Menshikov


Code :
#define ranf() ((float) rand() / (float) RAND_MAX)

float ranfGauss (int m, float s)
{
   static int pass = 0;
   static float y2;
   float x1, x2, w, y1;

   if (pass)
   {
      y1 = y2;
   } else  {
      do {
         x1 = 2.0f * ranf () - 1.0f;
         x2 = 2.0f * ranf () - 1.0f;
         w = x1 * x1 + x2 * x2;
      } while (w >= 1.0f);

      w = (float)sqrt (-2.0 * log (w) / w);
      y1 = x1 * w;
      y2 = x2 * w;
   }
   pass = !pass;

   return ( (y1 * s + (float) m));
}


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


Gaussian White Noise

References : Posted by remage[AT]netposta.hu

Notes :
SOURCE:

Steven W. Smith:
The Scientist and Engineer's Guide to Digital Signal Processing
http://www.dspguide.com


Code :
#define PI 3.1415926536f

float R1 = (float) rand() / (float) RAND_MAX;
float R2 = (float) rand() / (float) RAND_MAX;

float X = (float) sqrt( -2.0f * log( R1 )) * cos( 2.0f * PI * R2 );


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


Generator

Type : antialiased sawtooth
References : Posted by Paul Sernine

Notes :
This code generates a swept antialiasing sawtooth in a raw 16bit pcm file.
It is based on the quad differentiation of a 5th order polynomial. The polynomial harmonics (and aliased harmonics) decay at 5*6 dB per oct. The differenciators correct the spectrum and waveform, while aliased harmonics are still attenuated.


Code :
/* clair.c         Examen Partiel 2b
   T.Rochebois
   02/03/98
*/
#include <stdio.h>
#include <math.h>
main()
{
  double phase=0,dphase,freq,compensation;
  double aw0=0,aw1=0,ax0=0,ax1=0,ay0=0,ay1=0,az0=0,az1=0,sortie;
  short aout;
  int sr=44100;       //sample rate (Hz)
  double f_debut=55.0;//start freq (Hz)
  double f_fin=sr/6.0;//end freq (Hz)
  double octaves=log(f_fin/f_debut)/log(2.0);
  double duree=50.0;  //duration (s)
  int i;
  FILE* f;
  f=fopen("saw.pcm","wb");
  for(i=0;i<duree*sr;i++)
  {
    //exponential frequency sweep
    //Can be replaced by anything you like.
    freq=f_debut*pow(2.0,octaves*i/(duree*sr));
    dphase=freq*(2.0/sr);     //normalised phase increment
    phase+=dphase;            //phase incrementation
    if(phase>1.0) phase-=2.0; //phase wrapping (-1,+1)

    //polynomial calculation (extensive continuity at -1 +1)
    //        7       1  3    1   5
    //P(x) = --- x - -- x  + --- x
    //       360     36      120
    aw0=phase*(7.0/360.0 + phase*phase*(-1/36.0 + phase*phase*(1/120.0)));
    // quad differentiation (first order high pass filters)
    ax0=aw1-aw0; ay0=ax1-ax0; az0=ay1-ay0; sortie=az1-az0;
    //compensation of the attenuation of the quad differentiator
    //this can be calculated at "control rate" and linearly
    //interpolated at sample rate.
    compensation=1.0/(dphase*dphase*dphase*dphase);
    // compensation and output
    aout=(short)(15000.0*compensation*sortie);
    fwrite(&aout,1,2,f);
    //old memories of differentiators
    aw1=aw0; ax1=ax0; ay1=ay0; az1=az0;
  }
  fclose(f);
}


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


Inverted parabolic envelope

Type : envellope generation
References : Posted by James McCartney
Code :
dur = duration in samples
midlevel = amplitude at midpoint
beglevel = beginning and ending level (typically zero)

amp = midlevel - beglevel;

rdur = 1.0 / dur;
rdur2 = rdur * rdur;

level = beglevel;
slope = 4.0 * amp * (rdur - rdur2);
curve = -8.0 * amp * rdur2;

...

for (i=0; i<dur; ++i) {
        level += slope;
        slope += curve;
}


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


matlab/octave code for minblep table generation

References : Posted by dfl[at]ccrma[dot]stanford[dot]edu

Notes :
When I tested this code, it was running with each function in a separate file... so it might need some tweaking (endfunction statements?) if you try and run it all as one file.

Enjoy!

PS There's a C++ version by Daniel Werner here.
http://www.experimentalscene.com/?type=2&id=1
Not sure if it the output is any different than my version.
(eg no thresholding in minphase calculation)


Code :
% Octave/Matlab code to generate a minblep table for bandlimited synthesis
%% original minblep technique described by Eli Brandt:
%% http://www.cs.cmu.edu/~eli/L/icmc01/hardsync.html

% (c) David Lowenfels 2004
% you may use this code freely to generate your tables,
% but please send me a free copy of the software that you
% make with it, or at least send me an email to say hello
% and put my name in the software credits :)
% (IIRC: mps and clipdb functions are from Julius Smith)

% usage:
%  fc = dilation factor
%  Nzc = number of zero crossings
%  omega = oversampling factor
%  thresh = dB threshold for minimum phase calc

mbtable = minblep( fc, Nzc, omega, thresh );
mblen = length( mbtable );
save -binary mbtable.mat mbtable ktable nzc mblen;

*********************************************
function [out] = minblep( fc, Nzc, omega, thresh )

out = filter( 1, [1 -1], minblip( fc, Nzc, omega, thresh ) );

len = length( out );
normal = mean( out( floor(len*0.7):len ) )
out = out / normal; %% normalize

%% now truncate so it ends at proper phase cycle for minimum discontinuity
thresh = 1e-6;
for i = len:-1:len-1000
%  pause
  a = out(i) - thresh - 1;
    b = out(i-1) - thresh - 1;
%    i
    if(  (abs(a) < thresh) & (a > b) )
      break;
    endif
endfor

%out = out';
out = out(1:i);


*********************************************


function [out] = minblip( fc, Nzc, omega, thresh )
if (nargin < 4 )
  thresh = -100;
end
if (nargin < 3 )
  omega = 64;
end
if (nargin < 2 )
  Nzc = 16;
end
if (nargin < 1 )
  fc = 0.9;
end

blip = sinctable( omega, Nzc, fc );
%% length(blip) must be nextpow2! (if fc < 1 );

mag = fft( blip );
out = real( ifft( mps( mag, thresh ) ) );

*********************************************

function [sm] = mps(s, thresh)
% [sm] = mps(s)
% create minimum-phase spectrum sm from complex spectrum s

if (nargin < 2 )
  thresh = -100;
endif

s = clipdb(s, thresh);
sm = exp( fft( fold( ifft( log( s )))));

*********************************************
function [clipped] = clipdb(s,cutoff)
% [clipped] = clipdb(s,cutoff)
% Clip magnitude of s at its maximum + cutoff in dB.
% Example: clip(s,-100) makes sure the minimum magnitude
% of s is not more than 100dB below its maximum magnitude.
% If s is zero, nothing is done.

as = abs(s);
mas = max(as(:));
if mas==0, return; end
if cutoff >= 0, return; end
thresh = mas*10^(cutoff/20); % db to linear
toosmall = find(as < thresh);
clipped = s;
clipped(toosmall) = thresh;
*********************************************

function [out, phase] = sinctable( omega, Nzc, fc )

if (nargin < 3 )
  fc = 1.0 %% cutoff frequency
end %if
if (nargin < 2 )
  Nzc = 16  %% number of zero crossings
end %if
if (nargin < 1 )
  omega = 64 %% oversampling factor
end %if

Nzc = Nzc / fc %% This ensures more flatness at the ends.

phase = linspace( -Nzc, Nzc, Nzc*omega*2 );

%sinc = sin( pi * fc * phase) ./ (pi * fc * phase);

num = sin( pi*fc*phase );
den = pi*fc*phase;

len = length( phase );
sinc = zeros( len, 1 );

%sinc = num ./ den;

for i=1:len
  if ( den(i) ~= 0 )
    sinc(i) = num(i) / den(i);
    else
    sinc(i) = 1;
  end
end %for

out = sinc;
window = blackman( len );
out = out .* window;



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


PADsynth synthesys method

Type : wavetable generation
References : Posted by zynaddsubfx[at]yahoo[dot]com

Notes :
Please see the full description of the algorithm with public domain c++ code here:
http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm


Code :
It's here:
http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm
You may copy it (everything is public domain).
Paul


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


Parabolic shaper

References : Posted by azertopia at free dot fr

Notes :
This function can be used for oscillators or shaper.
it can be driven by a phase accumulator or an audio input.


Code :
Function Parashape(inp:single):single;
var fgh,tgh:single;
begin
fgh    := inp ;
fgh    := 0.25-f_abs(fgh) ;
tgh    := fgh ;
tgh    := 1-2*f_abs(tgh);
fgh    := fgh*8;
result := fgh*tgh ;
end;
// f_abs is the function of ddsputils unit.


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


Phase modulation Vs. Frequency modulation

References : Posted by Bram
Linked file : SimpleOscillator.h

Notes :
This code shows what the difference is betwee FM and PM.
The code is NOT optimised, nor should it be used like this.
It is an <b>EXAMPLE</b>

See linked file.




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


Phase modulation Vs. Frequency modulation II

References : Posted by James McCartney

Notes :
The difference between FM & PM in a digital oscillator is that FM is added to the frequency before the phase integration, while PM is added to the phase after the phase integration. Phase integration is when the old phase for the oscillator is added to the current frequency (in radians per sample) to get the new phase for the oscillator. The equivalent PM modulator to obtain the same waveform as FM is the integral of the FM modulator. Since the integral of sine waves are inverted cosine waves this is no problem. In modulators with multiple partials, the equivalent PM modulator will have different relative partial amplitudes. For example, the integral of a square wave is a triangle wave; they have the same harmonic content, but the relative partial amplitudes are different. These differences make no difference since we are not trying to exactly recreate FM, but real (or nonreal) instruments.

The reason PM is better is because in PM and FM there can be non-zero energy produced at 0 Hz, which in FM will produce a shift in pitch if the FM wave is used again as a modulator, however in PM the DC component will only produce a phase shift. Another reason PM is better is that the modulation index (which determines the number of sidebands produced and which in normal FM is calculated as the modulator amplitude divided by frequency of modulator) is not dependant on the frequency of the modulator, it is always equal to the amplitude of the modulator in radians. The benefit of solving the DC frequency shift problem, is that cascaded carrier-modulator pairs and feedback modulation are possible. The simpler calculation of modulation index makes it easier to have voices keep the same harmonic structure throughout all pitches.

The basic mathematics of phase modulation are available in any text on electronic communication theory.

Below is some C code for a digital oscillator that implements FM,PM,and AM. It illustrates the difference in implementation of FM & PM. It is only meant as an example, and not as an efficient implementation.


Code :
/* Example implementation of digital oscillator with FM, PM, & AM */

#define PI 3.14159265358979
#define RADIANS_TO_INDEX (512.0 / (2.0 * PI))

typedef struct{    /* oscillator data */
    double freq;   /* oscillator frequency in radians per sample */
    double phase;  /* accumulated oscillator phase in radians */
    double wavetable[512]; /* waveform lookup table */
} OscilRec;


/* oscil - compute 1 sample of oscillator output whose freq. phase and
*    wavetable are in the OscilRec structure pointed to by orec.
*/
double oscil(orec, fm, pm, am)
    OscilRec *orec;  /* pointer to the oscil's data */
    double fm; /* frequency modulation input  in radians per sample */
    double pm; /* phase modulation input      in radians */
    double am; /* amplitude modulation input  in any units you want */
{
    long tableindex;            /* index into wavetable */
    double instantaneous_freq;  /* oscillator freq  + freq  modulation */
    double instantaneous_phase; /* oscillator phase + phase modulation */
    double output;              /* oscillator output */
    
    instantaneous_freq  = orec->freq  + fm; /* get instantaneous freq */
    orec->phase += instantaneous_freq;      /* accumulate phase */
    instantaneous_phase = orec->phase + pm; /* get instantaneous phase */
    
    /* convert to lookup table index */
    tableindex = RADIANS_TO_INDEX * instantaneous_phase;
    tableindex &= 511; /* make it mod 512 === eliminate multiples of 2*k*PI */
    
    output = orec->wavetable[tableindex] * am; /* lookup and mult by am input */
    
    return (output);  /* return oscillator output */
}


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


PRNG for non-uniformly distributed values from trigonometric identity

Type : pseudo-random number generator
References : Posted by neolit123 gmail com

Notes :
a method, which generates random numbers in the [-1,+1] range, while having a probability density function with less concentration of values near zero for sin().
you can use an approximation of sin() and/or experiment with such an equation for different distributions. using tan() will accordingly invert the pdf graph i.e. more concentration near zero, but the output range will be also affected.

extended read on similar methods:
http://www.stat.wisc.edu/~larget/math496/random2.html

regards
lubomir


Code :
//init
x=y=1;

//sampleloop
y=sin((x+=1)*y);


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


Pseudo-Random generator

Type : Linear Congruential, 32bit
References : Hal Chamberlain, "Musical Applications of Microprocessors" (Posted by Phil Burk)

Notes :
This can be used to generate random numeric sequences or to synthesise a white noise audio signal.
If you only use some of the bits, use the most significant bits by shifting right.
Do not just mask off the low bits.


Code :
/* Calculate pseudo-random 32 bit number based on linear congruential method. */
unsigned long GenerateRandomNumber( void )
{
   /* Change this for different random sequences. */
   static unsigned long randSeed = 22222;
   randSeed = (randSeed * 196314165) + 907633515;
   return randSeed;
}


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


PulseQuad

Type : Waveform
References : Posted by am[AT]andre-michelle[DOT]com

Notes :
This is written in Actionscript 3.0 (Flash9). You can listen to the example at http://lab.andre-michelle.com/playing-with-pulse-harmonics
It allows to morph between a sinus like quadratic function and an ordinary pulse width with adjustable pulse width. Note that the slope while morphing is always zero at the edge points of the waveform. It is not just distorsion.


Code :
http://lab.andre-michelle.com/swf/f9/pulsequad/PulseQuad.as

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


Pulsewidth modulation

Type : waveform generation
References : Steffan Diedrichsen

Notes :
Take an upramping sawtooth and its inverse, a downramping sawtooth. Adding these two waves with a well defined delay between 0 and period (1/f)
results in a square wave with a duty cycle ranging from 0 to 100%.




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


Quick & Dirty Sine

Type : Sine Wave Synthesis
References : Posted by MisterToast

Notes :
This is proof of concept only (but code works--I have it in my synth now).

Note that x must come in as 0<x<=4096. If you want to scale it to something else (like 0<x<=2*M_PI), do it in the call. Or do the math to scale the constants properly.

There's not much noise in here. A few little peaks here and there. When the signal is at -20dB, the worst noise is at around -90dB.

For speed, you can go all floats without much difference. You can get rid of that unitary negate pretty easily, as well. A couple other tricks can speed it up further--I went for clarity in the code.

The result comes out a bit shy of the range -1<x<1. That is, the peak is something like 0.999.

Where did this come from? I'm experimenting with getting rid of my waveform tables, which require huge amounts of memory. Once I had the Hamming anti-ringing code in, it looked like all my waveforms were smooth enough to approximate with curves. So I started with sine. Pulled my table data into Excel and then threw the data into a curve-fitting application.

This would be fine for a synth. The noise is low enough that you could easily get away with it. Ideal for a low-memory situation. My final code will be a bit harder to understand, as I'll break the curve up and curve-fit smaller sections.


Code :
float xSin(double x)
{
    //x is scaled 0<=x<4096
    const double A=-0.015959964859;
    const double B=217.68468676;
    const double C=0.000028716332164;
    const double D=-0.0030591066066;
    const double E=-7.3316892871734489e-005;
    double y;

    bool negate=false;
    if (x>2048)
    {
        negate=true;
        x-=2048;
    }
    if (x>1024)
        x=2048-x;
    if (negate)
        y=-((A+x)/(B+C*x*x)+D*x-E);
    else
        y=(A+x)/(B+C*x*x)+D*x-E;
    return (float)y;
}


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


quick and dirty sine generator

Type : sine generator
References : Posted by couriervst[AT]hotmail[DOT]com

Notes :
this is part of my library, although I've seen a lot of sine generators, I've never seen the simplest one, so I try to do it,
tell me something, I've try it and work so tell me something about it






Code :
PSPsample PSPsin1::doOsc(int numCh)
{

    double x=0;
    double t=0;

    if(m_time[numCh]>m_sampleRate)    //re-init cycle
        m_time[numCh]=0;
    
    if(m_time[numCh]>0)
    {
        t =(double)(((double)m_time[numCh])/(double)m_sampleRate);
        
        x=(m_2PI *(double)(t)*m_freq);
    }
    else
        x=0;

    
    PSPsample r=(PSPsample) sin(x+m_phase)*m_amp;
    
    m_time[numCh]++;

    return     r;

}


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


randja compressor

Type : compressor
References : Posted by randja

Notes :
I had found this code on the internet then made some improvements (speed) and now I post it here for others to see.

Code :
#include <cmath>
#define max(a,b) (a>b?a:b)

class compressor
{

    private:
        float   threshold;
        float   attack, release, envelope_decay;
        float   output;
        float   transfer_A, transfer_B;
        float   env, gain;

    public:
    compressor()
    {
        threshold = 1.f;
        attack = release = envelope_decay = 0.f;
        output = 1.f;
    
        transfer_A = 0.f;
        transfer_B = 1.f;
    
        env = 0.f;
        gain = 1.f;
    }

    void set_threshold(float value)
    {
        threshold = value;
        transfer_B = output * pow(threshold,-transfer_A);
    }
    
    
    void set_ratio(float value)
    {
        transfer_A = value-1.f;
        transfer_B = output * pow(threshold,-transfer_A);
    }
    
    
    void set_attack(float value)
    {
        attack = exp(-1.f/value);
    }
    
    
    void et_release(float value)
    {
        release = exp(-1.f/value);
        envelope_decay = exp(-4.f/value); /* = exp(-1/(0.25*value)) */
    }
    
    
    void set_output(float value)
    {
        output = value;
        transfer_B = output * pow(threshold,-transfer_A);
    }
    
    
    void reset()
    {
        env = 0.f; gain = 1.f;
    }
    
    
    __forceinline void process(float *input_left, float *input_right,float *output_left, float *output_right,    int frames)
    {
        float det, transfer_gain;
        for(int i=0; i<frames; i++)
        {
            det = max(fabs(input_left[i]),fabs(input_right[i]));
            det += 10e-30f; /* add tiny DC offset (-600dB) to prevent denormals */
    
            env = det >= env ? det : det+envelope_decay*(env-det);
    
            transfer_gain = env > threshold ? pow(env,transfer_A)*transfer_B:output;
    
            gain = transfer_gain < gain ?
                            transfer_gain+attack *(gain-transfer_gain):
                            transfer_gain+release*(gain-transfer_gain);
    
            output_left[i] = input_left[i] * gain;
            output_right[i] = input_right[i] * gain;
        }
    }
    
    
    __forceinline void process(double *input_left, double *input_right,    double *output_left, double *output_right,int frames)
    {
        double det, transfer_gain;
        for(int i=0; i<frames; i++)
        {
            det = max(fabs(input_left[i]),fabs(input_right[i]));
            det += 10e-30f; /* add tiny DC offset (-600dB) to prevent denormals */
    
            env = det >= env ? det : det+envelope_decay*(env-det);
    
            transfer_gain = env > threshold ? pow(env,transfer_A)*transfer_B:output;
    
            gain = transfer_gain < gain ?
                            transfer_gain+attack *(gain-transfer_gain):
                            transfer_gain+release*(gain-transfer_gain);
    
            output_left[i] = input_left[i] * gain;
            output_right[i] = input_right[i] * gain;
        }
    }

};


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


RBJ Wavetable 101

References : Posted by Robert Bristow-Johnson
Linked file : Wavetable-101.pdf

Notes :
see linked file



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


Rossler and Lorenz Oscillators

Type : Chaotic LFO
References : Posted by kaleja[AT]estarcion[DOT]com

Notes :
The Rossler and Lorenz functions are iterated chaotic systems - they trace smooth curves that never repeat the same way twice. Lorenz is "unpitched", having no distinct peaks in its spectrum -- similar to pink noise. Rossler exhibits definite spectral peaks against a noisy broadband background.

Time-domain and frequency spectrum of these two functions, as well as other info, can be found at:

http://www.physics.emory.edu/~weeks/research/tseries1.html

These functions might be useful in simulating "analog drift."





Code :
Available on the web at:
http://www.tinygod.com/code/BLorenzOsc.zip


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


SawSin

Type : Oscillator shape
References : Posted by Alexander Kritov
Code :
double sawsin(double x)
{
   double t = fmod(x/(2*M_PI),(double)1.0);
   if (t>0.5)
       return -sin(x);
   if (t<=0.5)
       return (double)2.0*t-1.0;
}


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


Simple Time Stretching-Granular Synthesizer

References : Posted by Harry-Chris

Notes :
Matlab function that implements crude time stretching - granulizing function, by overlap add in time domain.

Code :
function y = gran_func(x, w, H,H2, Fs, tr_amount)


% x -> input signal
% w -> Envelope - Window Vector
% H1 -> Original Hop Size
% H2 -> Synthesis Hop Size
% Fs -> Sample Rate
% str_amount -> time stretching factor


M = length(w);

pin = 1;
pend = length(x) - M;


y = zeros(1, floor( str_amount * length(x)) +M);


count = 1;
idx = 1;

while pin < pend
      
    input = x(pin : pin+M-1) .* w';


    y(idx : idx + M - 1) = y(idx : idx + M - 1) + input;

    pin = pin + H;
    count = count + 1;
    idx = idx + H2;
    
end



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


Sine calculation

Type : waveform generation, Taylor approximation of sin()
References : Posted by Phil Burk

Notes :
Code from JSyn for a sine wave generator based on a Taylor Expansion. It is not as efficient as the filter methods, but it has linear frequency control and is, therefore, suitable for FM or other time varying applications where accurate frequency is needed. The sine generated is accurate to at least 16 bits.

Code :
for(i=0; i < nSamples ; i++)
{
  //Generate sawtooth phasor to provide phase for sine generation
  IncrementWrapPhase(phase, freqPtr[i]);
  //Wrap phase back into region where results are more accurate

  if(phase > 0.5)
    yp = 1.0 - phase;
  else
  {
    if(phase < -0.5)
       yp = -1.0 - phase;
    else
        yp = phase;
  }

  x = yp * PI;
  x2 = x*x;

  //Taylor expansion out to x**9/9! factored  into multiply-adds
  fastsin = x*(x2*(x2*(x2*(x2*(1.0/362880.0)
            - (1.0/5040.0))
            + (1.0/120.0))
            - (1.0/6.0))
            + 1.0);

  outPtr[i] = fastsin * amplPtr[i];
}


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


Smooth random LFO Generator

References : Posted by Rob Belcham

Notes :
I've been after a random LFO that's suitable for modulating a delay line for ages ( e.g for chorus / reverb modulation) , so after i rolled my own, i thought i'd better make it my first contribution to the music-dsp community.

My aim was to achive a sinusoidal based random but smooth waveform with a frequency control that has no discontinuities and stays within a -1:1 range. If you listen to it, it sounds quite like brown noise, or wind through a microphone (at rate = 100Hz for example)

It's written as a matlab m function, so shouldn't be too hard to port to C.

The oscillator generates a random level stepped waveform with random time spent at each step (within bounds). These levels are linearly interpolated between and used to drive the frequency of a sinewave. To achive amplitude variation, at each zero crossing a new random amplitude scale factor is generated. The amplitude coefficient is ramped to this value with a simple exponential.

An example call would be,
t = 4; Fs = 44100;
y = random_lfo(100, t*Fs, Fs);
axis([0, t*Fs, -1, 1]);
plot(y)

Enjoy !


Code :
% Random LFO Generator
% creates a random sinusoidal waveform with no discontinuities
%   rate = average rate in Hz
%   N = run length in samples
%   Fs = sample frequency in Hz
function y = random_lfo(rate, N, Fs)

step_freq_scale = Fs / (1*rate);
min_Cn = 0.1 * step_freq_scale;
An = 0;
lastA = 0;
Astep = 0;
y = zeros(1,N); % output
x = 0;  % sine phase
lastSign = 0;
amp_scale = 0.6;
new_amp_scale = 0.6;
amp_scale_ramp = exp(1000/Fs)-1;
for (n=1:N)
    if (An == 0) || (An>=Cn)
        % generate a new random freq scale factor
        Cn = floor(step_freq_scale * rand());
        % limit to prevent rapid transitions
        Cn = max(Cn, min_Cn);
        % generate new value & step coefficient
        newA = 0.1 + 0.9*rand();
        Astep = (newA - lastA) / Cn;
        A = lastA;
        lastA = newA;
        % reset counter
        An = 0;
    end
    An = An + 1;
    % generate output
    y(n) = sin(x) * amp_scale;
    % ramp amplitude
    amp_scale = amp_scale + ( new_amp_scale - amp_scale ) * amp_scale_ramp;
    sin_inc = 2*pi*rate*A/Fs;
    A = A + Astep;
    % increment phase
    x = x + sin_inc;
    if (x >= 2*pi)
        x = x - 2*pi;
    end
    % scale at each zero crossing
    if (sign(y(n)) ~= 0) && (sign(y(n)) ~= lastSign)
        lastSign = sign(y(n));
        new_amp_scale = 0.25 + 0.75*rand();
    end;
end;
    


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


Square Waves

Type : waveform generation
References : Posted by Sean Costello

Notes :
One way to do a square wave:

You need two buzz generators (see Dodge & Jerse, or the Csound source code, for implementation details). One of the buzz generators runs at the desired square wave frequency, while the second buzz generator is exactly one octave above this pitch. Subtract the higher octave buzz generator's output from the lower buzz generator's output - the result should be a signal with all odd harmonics, all at equal amplitude. Filter the resultant signal (maybe integrate it). Voila, a bandlimited square wave! Well, I think it should work...

The one question I have with the above technique is whether it produces a waveform that truly resembles a square wave in the time domain. Even if the number of harmonics, and the relative ratio of the harmonics, is identical to an "ideal" bandwidth-limited square wave, it may have an entirely different waveshape. No big deal, unless the signal is processed by a nonlinearity, in which case the results of the nonlinear processing will be far different than the processing of a waveform that has a similar shape to a square wave.




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


Trammell Pink Noise (C++ class)

Type : pink noise generator
References : Posted by dfl at ccrma dot stanford dot edu
Code :
#ifndef _PinkNoise_H
#define _PinkNoise_H

// Technique by Larry "RidgeRat" Trammell 3/2006
// http://home.earthlink.net/~ltrammell/tech/pinkalg.htm
// implementation and optimization by David Lowenfels

#include <cstdlib>
#include <ctime>

#define PINK_NOISE_NUM_STAGES 3

class PinkNoise {
public:
  PinkNoise() {
  srand ( time(NULL) ); // initialize random generator
    clear();
  }

  void clear() {
    for( size_t i=0; i< PINK_NOISE_NUM_STAGES; i++ )
      state[ i ] = 0.0;
    }
    
  float tick() {
    static const float RMI2 = 2.0 / float(RAND_MAX); // + 1.0; // change for range [0,1)
    static const float offset = A[0] + A[1] + A[2];

  // unrolled loop
    float temp = float( rand() );
    state[0] = P[0] * (state[0] - temp) + temp;
    temp = float( rand() );
    state[1] = P[1] * (state[1] - temp) + temp;
    temp = float( rand() );        
    state[2] = P[2] * (state[2] - temp) + temp;
    return ( A[0]*state[0] + A[1]*state[1] + A[2]*state[2] )*RMI2 - offset;
  }

protected:
  float state[ PINK_NOISE_NUM_STAGES ];
  static const float A[ PINK_NOISE_NUM_STAGES ];
  static const float P[ PINK_NOISE_NUM_STAGES ];
};

const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P)
const float PinkNoise::P[] = { 0.3190,  0.7756,  0.9613  };

#endif


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


Waveform generator using MinBLEPS

References : Posted by locke[AT]rpgfan.demon.co.uk
Linked file : MinBLEPS.zip

Notes :
C code and project file for MSVC6 for a bandwidth-limited saw/square (with PWM) generator using MinBLEPS.

This code is based on Eli's MATLAB MinBLEP code and uses his original minblep.mat file.
Instead of keeping a list of all active MinBLEPS, the output of each MinBLEP is stored in a buffer, in which all consequent MinBLEPS and the waveform output are added together. This optimization makes it fast enough to be used realtime.

Produces slight aliasing when sweeping high frequencies. I don't know wether Eli's original code does the same, because I don't have MATLAB. Any help would be appreciated.

The project name is 'hardsync', because it's easy to generate hardsync using MinBLEPS.


Code :




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


Wavetable Synthesis

References : Robert Bristow-Johnson
Linked file : http://www.harmony-central.com/Synth/Articles/Wavetable_101/Wavetable-101.pdf

Notes :
Wavetable sythesis AES paper by RBJ.



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


Weird synthesis

References : Posted by Andy M00cho

Notes :
(quoted from Andy's mail...)
What I've done in a soft-synth I've been working on is used what I've termed Fooglers, no reason, just liked the name :) Anyway all I've done is use a *VERY* short delay line of 256 samples and then use 2 controllable taps into the delay with High Frequency Damping, and a feedback parameter.

Using a tiny fixed delay size of approx. 4.8ms (really 256 samples/1k memory with floats) means this costs, in terms of cpu consumption practically nothing, and the filter is a real simple 1 pole low-pass filter. Maybe not DSP'litically correct but all I wanted was to avoid the high frequencies trashing the delay line when high feedbacks (99%->99.9%) are used (when the fun starts ;).

I've been getting some really sexy sounds out of this idea, and of course you can have the delay line tuneable if you choose to use fractional taps, but I'm happy with it as it is.. 1 nice simple, yet powerful addition to the base oscillators.

In reality you don't need 2 taps, but I found that using 2 added that extra element of funkiness...




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