### Synth Tutorial

von HAL

##### Grundlegende Wellenformen:

##### Additative Synthese

Der Modulator moduliert die Tonhöhe des Oszillators (Vibrato):
Modulator -> Oscillator -> Verstärker -> Output

##### Subtraktive Synthese

Der (volle) Klang des Oszillators wird durch einen Filter geleitet
(um die Klangfülle zu reduzieren):
Oszillator -> Filter -> Verstärker -> Output

##### ADSR Hüllkurve

1.) Die Lautstärke wächst von 0% auf 100% in x Sekunden
("attack time").
2.) Die Lautstärke fällt von 100% auf xx% in y Sekunden
(x = "sustain level", y = "decay time").
3.) Die Laustärke verbleibt bei auf dem Sustain-Level,
bis ein "key off" erfolgt
4.) Die Lautstärke fällt auf 0% in x Sekunden
("release time").

##### Filter

Lowpass:
- löscht alle Frequenzen überhalb der "CutOff-Frequenz"
Highpass:
- löscht alle Frequenzen unterhalb der "CutOff-Frequenz"
BandPass:
- lässt nur Frequenzen eines bestimmten Frequenzbereichs durch
Notch:
- löscht eine bestimmte Frequenz
Einige Filter besitzen noch einen Parameter namens "Resonanz", der angibt wie stark die Frequenzen um die "CutOff-Frequenz" herum verstärkt werden.

##### Hier die wichtigsten Funktionen zum Berechnen der Koeffizienten für IIR-Filter:

    // omega & bandwidth = 0 - pi (pi ~ output freq / 2)
    //

    #define LN2O2 0.34657359027997265470861606072909

    /*
    usage:

    y[n] = a0 * x[n] + a1 * x[n-1] + a2 * x[n-2] +
                       b1 * y[n-1] + b2 * y[n-2]
    */

    typedef struct {
    	double a0, a1, a2,
    		       b1, b2;
    } biquad_coeff_t;

    // lowpass
    void
    biquad_lp(biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = (1 - cs) * 0.5;
    	b1 = 1 - cs;
    	b2 = (1 - cs) * 0.5;
    	a0 = 1 + al;
    	a1 = -2 * cs;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    // bandpass
    void
    biquad_bp(biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = al;
    	b1 = 0;
    	b2 = -al;
    	a0 = 1 + al;
    	a1 = -2 * cs;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    // highpass
    void
    biquad_hp(biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = (1 + cs) * 0.5;
    	b1 = -(1 + cs);
    	b2 = (1 + cs) * 0.5;
    	a0 = 1 + al;
    	a1 = -2 * cs;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    // notch
    void
    biquad_no(biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = 1;
    	b1 = -2 * cs;
    	b2 = 1;
    	a0 = 1 + al;
    	a1 = b1;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    // peaking equalizer
    void
    biquad_peq(biquad_coeff_t *biquad, float32 omega, float32 bandwidth, float32 dbgain)
    {
    	float64 sn, cs, al, a, a0, a1, a2, b0, b1, b2, ooa, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	a  = pow(10, dbgain * 0.025);
    	ooa = 1.0 / a;
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = 1 + al * a;
    	b1 = -2 * cs;
    	b2 = 1 - al * a;
    	a0 = 1 + al * ooa;
    	a1 = b1;
    	a2 = 1 - al * ooa;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    // low shelf
    void
    biquad_ls(biquad_coeff_t *biquad, float32 omega, float32 dbgain, float32 slope)
    {
    	float64 sn, cs, be, a, a0, a1, a2, b0, b1, b2, ooa0, ap1, am1;

    	sn  = sin(omega);
    	cs  = cos(omega);
    	a   = pow(10, dbgain * 0.025);
    	ap1 = a + 1;
    	am1 = a - 1;
    	be  = sqrt((a * a + 1) / slope - am1 * am1);

    	b0 = a * (ap1 - am1 * cs + be * sn);
    	b1 = 2* a * (am1 - ap1 * cs);
    	b2 = a * (ap1 - am1 * cs - be * sn);
    	a0 = ap1 + am1 * cs + be * sn;
    	a1 = -2 * (am1 + ap1 * cs);
    	a2 = ap1 + am1 * cs - be * sn;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    // high shelf
    void
    biquad_hs(biquad_coeff_t *biquad, float32 omega, float32 dbgain, float32 slope)
    {
    	float64 sn, cs, be, a, a0, a1, a2, b0, b1, b2, ooa0, ap1, am1;

    	sn  = sin(omega);
    	cs  = cos(omega);
    	a   = pow(10, dbgain * 0.025);
    	ap1 = a + 1;
    	am1 = a - 1;
    	be  = sqrt((a * a + 1) / slope - am1 * am1);

    	b0 = a * (ap1 + am1 * cs + be * sn);
    	b1 = -2 * a * (am1 + ap1 * cs);
    	b2 = a * (ap1 + am1 * cs - be * sn);
    	a0 = ap1 - am1 * cs + be * sn;
    	a1 = 2 * (am1 - ap1 * cs);
    	a2 = ap1 - am1 * cs - be * sn;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

##### Beispielaufbau eines Oszillatorblocks

Folgendes benutze ich zur Zeit (mehr oder weniger):

            LFO-->ENV---\
                         \
      LFO-->OSC-->BIQUAD--*-->DISTORT---\
                                        |
            LFO-->ENV---\               |
                         \              |
      LFO-->OSC-->BIQUAD--*-->DISTORT---+
                                        |
            LFO-->ENV---\               |
                         \              |
      LFO-->OSC-->BIQUAD--*-->DISTORT---+
                                        |
            LFO-->ENV---\               |
                         \              |
      LFO-->OSC-->BIQUAD--*-->DISTORT---+->CHORUS/ECHO/REVERB

    LFO     = low frequency oscillator
    ENV     = adsr envelope
    DISTORT = a distortion function

##### Was jetzt?

1.] Beweg' deinen Hintern zu www.harmonic-central.com
und folge allen weiteren Links.
2.] Gehe zu www.maz-sound.com
und downloade so viele Synthesizer wie möglich.
3.] Schau dir die mitgelieferten Sourcen an. (synth-demo.zip).
4.] ...

        EXPERIMENTIERE!!!
        EXPERIMENTIERE!!!
        EXPERIMENTIERE!!!

Okay, that's all.......
Bei Fragen, Mail an bschoedlbauer@gmx.net.
(Hal)