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
Another cheap sinusoidal LFO
another LFO class
Arbitary shaped band-limited waveform generation (using oversampling and low-pass filtering)
Audiable alias free waveform gen using width sine
Bandlimited sawtooth synthesis
Bandlimited waveform generation
Bandlimited waveform generation with hard sync
Bandlimited waveforms synopsis.
Bandlimited waveforms...
C++ gaussian noise generation
Cubic polynomial envelopes
Discrete Summation Formula (DSF)
Drift generator
DSF (super-set of BLIT)
Fast LFO in Delphi...
Fast sine and cosine calculation
Fast sine wave calculation
Fast square wave generator
Gaussian White noise
Gaussian White Noise
Inverted parabolic envelope
Phase modulation Vs. Frequency modulation
Phase modulation Vs. Frequency modulation II
Pseudo-Random generator
Pulsewidth modulation
quick and dirty sine generator
SawSin
Sine calculation
Square Waves
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];
}


no comments on this item | 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


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));
--------------


1 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.




1 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...


4 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


6 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)




1 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)



no comments on this item | 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


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


Bandlimited waveforms synopsis.

References : Joe Wright
Linked file : waveforms.txt

Notes :
(see linkfile)



no comments on this item | 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);


1 comment(s) | 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;
}


no comments on this item | 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
}


1 comment(s) | 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;
}


4 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


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.


1 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]


6 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


1 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;


1 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));
}


1 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


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;
}


2 comment(s) | 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 */
}


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


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 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;

}


2 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


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


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.




1 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 :




1 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