#ifndef INSTRUMENTS
#define INSTRUMENTS

#include "wavetable.h"
#include "svf.h"


/* --------------------------------------------------------------------- */

typedef struct {
    Osc* osc;
    //~ Osc* modosc;
    float factor;
    float env;
    float hz;
    float s;
    SVF* svf;
    
    float fcfct;
    float detune;
} Pluck;


Pluck* pluck (Wave wave) {
    Pluck* p = (Pluck*) malloc (sizeof (Pluck));
    
    p->osc = osc (wave);
    //~ p->modosc = osc (TRI);
    p->factor = 0.9994f;
    p->env = 1.0f;
    p->hz = 0.0f;
    p->s = 0.0f;
    p->svf = svf ();
    
    p->detune = 1.0f;
    p->fcfct = 32;
    
    return p;
}


void pluck_on (Pluck* self, float hz) {
    //~ fprintf (stderr, "%f\n", hz);
    self->env = 1.0f;
    self->hz = hz;
    self->osc->counter = 0.0f;
    THANKS_BULBAPEDIA ();
    //~ self->modosc->counter = noise * noise * WAVESIZE;
}


float pluck_next (Pluck* self) {
    if (self->env > 0.0f && self->hz != 0.0f) {
        float s;
        s = next (self->osc, self->hz * self->detune) * self->env;
        //~ fprintf (stderr, "%f\n", self->env);
        self->env *= self->factor;
        self->s = s;
        svf_update (self->svf, self->hz * self->fcfct * self->env, 0.5f);
        return svf_process (self->svf, atanf (s*2 + self->s), svf_l, 0.0f);
    }
    return 0.0f;
}


/* --------------------------------------------------------------------- */

#define ROSC 3
typedef struct {
    Osc* oscs[ROSC];
    Osc* sub;
    Osc* modosc;
    float detunes[ROSC];
    float hz;
    int on;
    
    float detune;
} Rer;


Rer* rer (Wave wave) {
    Rer* r = (Rer*) malloc (sizeof (Rer));
    int oldseed = seed;
    seed = -1015741560; /* just bc */
    int i;
    for (i = 0; i < ROSC; ++i) {
        r->oscs[i] = osc (wave);
        THANKS_BULBAPEDIA ();
        r->detunes[i] = (noise * noise * 0.5f) + 1.0f;
    }
    r->detunes[0] = 1.0f;
    seed = oldseed;
    
    r->sub = osc (SINE);
    
    r->detune = 1.0f;
    
    r->on = 0;
    return r;
}


void rer_on (Rer* self, float hz) {
    self->on = 1;
    self->hz = hz;
    self->sub->counter = 0.0f;
}


void rer_off (Rer* self) {
    int i;
    
    self->on = 0;
    self->sub->counter = 0.0f;
    for (i = 0; i < ROSC; ++i) {
        self->oscs[i]->counter = 0.0f;
    }
}


float rer_next (Rer* self) {
    if (self->on) {
        float s = 0.0f;
        int i;
        for (i = 0; i < ROSC; ++i) {
            s += next (self->oscs[i], self->hz * self->detunes[i] * self->detune);
        }
        return s;
    }
    return 0.0f;
}


/* --------------------------------------------------------------------- */

typedef struct {
    Osc* osc;
    float hz;
    int on;
    
    float detune;
} Sub;


Sub* sub () {
    Sub* s = (Sub*) malloc (sizeof (Sub));
    s->osc = osc (SINE);
    s->hz = 0.0f;
    s->on = 0;
    s->detune = 1.0f;
    return s;
}


void sub_on (Sub* self, float hz) {
    self->hz = hz;
    self->on = 1;
}


void sub_off (Sub* self) {
    self->hz = 0.0f;
    self->on = 0;
}


float sub_next (Sub* self) {
    if (self->on) {
        return next (self->osc, self->hz * self->detune);
    }
    return 0.0f;
}


/* --------------------------------------------------------------------- */


/* according to <http://en.wikipedia.org/wiki/Formant> */
static const float formants[][2] = {
    { 0, 0 },
    { 240.0f, 2400.0f },
    { 235.0f, 2100.0f },
    { 390.0f, 2300.0f },
    { 370.0f, 1900.0f },
    { 610.0f, 1900.0f },
    { 585.0f, 1710.0f },
    { 850.0f, 1610.0f },
    { 820.0f, 1530.0f },
    { 750.0f,  940.0f },
    { 700.0f,  760.0f },
    { 600.0f, 1170.0f },
    { 500.0f,  700.0f },
    { 460.0f, 1310.0f },
    { 360.0f,  640.0f },
    { 300.0f, 1390.0f },
    { 250.0f,  595.0f }
};


typedef struct {
    Osc* osc;
    SVF* form;
    SVF* ant;
    float hz;
    float hztarget;
    float detune;
    char vowel;
    int on;
    
    float formtarget;
    float anttarget;
    float formnow;
    float antnow;
    
} Voice;


Voice* voice (Wave w) {
    Voice* v = (Voice*) malloc (sizeof (Voice));
    v->osc = osc (w);
    v->form = svf ();
    v->ant = svf ();
    
    v->hz = 0.0f;
    v->hztarget = 0.0f;
    v->detune = 1.0f;
    
    v->on = 0;
    
    return v;
}


void voice_on (Voice* self, float hz, char v) {
    if (!self->on) {
        self->formnow = formants[(int)v][0];
        self->antnow = formants[(int)v][1];
    }
    
    self->on = 1;
    self->hztarget = hz;
    
    self->formtarget = formants[(int)v][0];
    self->anttarget = formants[(int)v][1];
}


void voice_off (Voice* self) {
    self->on = 0;
    self->osc->counter = 0.0f;
}


float voice_next (Voice* self) {
    if (self->on) {
        float vs = 0.0f;
        float ms = 0.0f;
        
        svf_update (self->form, self->formnow, 0.5f);
        svf_update (self->ant, self->antnow, 0.5f);
        
        self->formnow += (self->formtarget - self->formnow) * 0.001;
        self->antnow += (self->anttarget - self->antnow) * 0.001;
        self->hz += (self->hztarget - self->hz) * 0.001;
                
        vs = next (self->osc, self->hz * self->detune);
        ms = svf_process (self->form, vs, svf_l, 0) + svf_process (self->ant, vs, svf_l, 0);
        
        return ms;
    }
    return 0.0f;
}

#endif
