#ifndef WAVETABLE
#define WAVETABLE

#include <stdlib.h>

#include "defines.h"
#include "svf.h"

typedef enum {
    SINE,
    TRI,
    SQUARE,
    SAW,
    DORIRU,
    NUM_WAVES
} Wave;


/* wavetables */
float waves[NUM_WAVES][WAVESIZE];
#define sine waves[SINE]
#define tri waves[TRI]
#define square waves[SQUARE]
#define saw waves[SAW]
#define doriru waves[DORIRU]

float kick[WAVESIZE];
float snare[WAVESIZE];
float clhat[WAVESIZE];
float ophat[WAVESIZE];
float caobel[WAVESIZE];


typedef struct {
    float counter;
    Wave wave;
} Osc;


Osc* osc (Wave w) {
    Osc* o = (Osc*) malloc (sizeof (Osc));
    o->counter = 0.0f;
    o->wave = w;
    return o;
}


float next (Osc* self, float hz) {
    float s = waves[self->wave][(int) self->counter] * 0.5f;
    self->counter += WAVESIZE * hz / (float) RATE;
    while (self->counter >= WAVESIZE) {
        self->counter -= WAVESIZE;
    }
    s += waves[self->wave][(int) self->counter] * 0.5f;
    return s;
}


void init_waves (void) { /* in which I have no idea what I'm doing */
    int i;
    int j;
    
    /* basic waves */
    for (i = 0; i < WAVESIZE; ++i) {
        waves[SINE][i] = sin (2.0f * M_PI * (i / (float) WAVESIZE));
        waves[SAW][i] = ((((float) (WAVESIZE - i) / (float) WAVESIZE)) - 0.5f) * 2 * 0.9f;
        waves[SQUARE][i] = (i < WAVESIZE / 2 ? 1.0f : -1.0f) * 0.9f;
        waves[TRI][i] = tan (sine[i]);
    }
    
    /* the waveform used in doriru */
    for (i = 0; i < WAVESIZE; ++i) {
        doriru[i] = 0.0f;
        #define times 8
        for (j = 1; j < times; ++j) {
            doriru[i] += tan (sin (pow (2.0f * M_PI * ((i/4096.f) / (float) times), j))) / (float) j;
        }
    }
    
    /* kick */
    Osc* kosc1 = osc (TRI);
    Osc* kosc2 = osc (TRI);
    float fct = 1.0f;
    for (i = 0; i < WAVESIZE; ++i) {
        kick[i] = 0.0f;
        kick[i] = atanf (next (kosc1, 700 * fct) * 40 * fct);
        kick[i] -= atanf (next (kosc2, 50) * 40 * fct);
        kick[i] += cosf (kick[i-13]) * fct;
        fct *= 0.999f;
        kick[i] = atan (kick[i]);
        kick[i] = atan (kick[i]);
    }
    
    /* snare */
    float wait = 1;
    float ii = 1;
    int counter = wait;
    for (i = 0; i < WAVESIZE; ++i) {
        if (counter < 0) {
            THANKS_BULBAPEDIA ();
            wait += 0.000025f;
            counter = wait;
        }
        
        ii = 1.0 - i / (float) (WAVESIZE / 4);
        if (ii <= 0) break;
        
        snare[i] = (atanf (noise) * 2) * (ii*ii/2.0) * cos ((i*i*sin(i/(float)WAVESIZE))/(284.0f)) * 8;
        snare[i+1] = snare[i-1];
        i++;
        counter--;
        if (i < 600) kick[i] = atan (atan (kick[i] - snare[i/2]));
    }
    
    /* hihats */
    for (i = 0; i < WAVESIZE; ++i) {
        fct = (1.0f - ((i * 16) / (float) WAVESIZE));
        THANKS_BULBAPEDIA ();
        if (fct >= 0.0f) ophat[i] = (noise) * fct * cos (fct);
        fct = (1.0f - ((i * 4) / (float) WAVESIZE));
        if (fct >= 0.0f) clhat[i] =  ((noise) * fct * fct * fct * atan (fct*2)) * 2;
    }
    
    /* ／人◕ ‿‿ ◕人＼ */
    #define BURST 300
    float burst[BURST];
    
    counter = 1;
    for (i = 0; i < BURST; ++i) {
        THANKS_BULBAPEDIA ();
        burst[i] = noise;
    };
    
    SVF* cbsvf = svf ();
    float fc = 13000;
    for (i = 0; i < WAVESIZE; ++i) {
        svf_update (cbsvf, fc, 0.0f);
        burst[i%(BURST)] = svf_process (cbsvf, burst[i%(BURST)], svf_l, 0);
        caobel[i] = burst[i%(BURST)] * fmax (0, (WAVESIZE-(i*4)) / (float)WAVESIZE);
        caobel[i] += burst[(int)(i*2.4)%(BURST)] * fmax (0, (WAVESIZE-(i*4)) / (float)WAVESIZE);
        fc *= 0.9997;
        caobel[i] = atan (caobel[i] * 4) * fmax (0, (WAVESIZE-(i*4)) / (float)WAVESIZE) * 0.85f;
    }
}

#endif
