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

#define RATE 32000.0

float sinetab[2048];

typedef struct oscillator {
	uint32_t phasor;
	uint32_t step;
	float value;
} osc_t;

void update_osc(osc_t* o) {
	o->phasor += o->step;
	o->value = sinetab[o->phasor >> (32-11)];
}

void set_osc_freq(osc_t* o, float f) {
	o->step = (uint32_t) ((f / RATE) * UINT32_MAX);
}

typedef struct noise {
	float r1, r2, out1, out2, filt;
	uint8_t left;
} noise_t;

float get_noise(noise_t* n) {
	float in;
	if(n->left == 0) {
		n->r1 = (float) random() / UINT32_MAX;
		n->r2 = (float) random() / UINT32_MAX;
		n->left = 2;
	}
	if(n->left == 2) {
		in = (sqrt(-2*log(n->r1))*cos(2*M_PI*n->r2))/6;
	} else if(n->left == 1) {
		in = (sqrt(-2*log(n->r1))*sin(2*M_PI*n->r2))/6;
	}
	n->left = n->left - 1;
	n->out1 = n->out1 + n->filt*(in - n->out1);
	n->out2 = n->out2 + n->filt*(n->out1 - n->out2);
	return n->out2;
}

int main() {
	osc_t amp_lfobank[6];
	osc_t freq_lfobank[6];
	noise_t noisebank[6];
	float final_l, final_r, out;
	int16_t out16;
	float pan[6] = {0.9, 0.33, 0.66, 0.1, 0.5, 0.5};

	srandom(42);
	for(int i=0; i<2048; i++) {
		sinetab[i] = (float) sin(i*2*M_PI/2048);
	}
	for(int i=0; i<6; i++) {
		noisebank[i].left = 0;
	}
	noisebank[0].filt = 0.25/2;
	noisebank[1].filt = 0.10/2;
	noisebank[2].filt = 0.05/2;
	noisebank[3].filt = 0.50/2;
	noisebank[4].filt = 0.33/2;
	noisebank[5].filt = 0.20/2;

	amp_lfobank[0].phasor = 0;
	amp_lfobank[1].phasor = UINT32_MAX/2;
	amp_lfobank[2].phasor = 2*UINT32_MAX/3;
	amp_lfobank[3].phasor = UINT32_MAX/3;
	amp_lfobank[4].phasor = 3*UINT32_MAX/4;
	amp_lfobank[5].phasor = UINT32_MAX/6;

	set_osc_freq(&freq_lfobank[0], 1/(5*60));
	set_osc_freq(&freq_lfobank[1], 1/(3*60));
	set_osc_freq(&freq_lfobank[2], 1/(6*60));
	set_osc_freq(&freq_lfobank[3], 1/(10*60));
	set_osc_freq(&freq_lfobank[4], 1/(11*60));
	set_osc_freq(&freq_lfobank[5], 1/(13*60));
	
	while(1) {
		for(int i=0; i<6; i++) {
			update_osc(&freq_lfobank[i]);
			set_osc_freq(&amp_lfobank[0], 0.075*1 + 0.10*freq_lfobank[0].value);
			set_osc_freq(&amp_lfobank[1], 0.075*1.5 + 0.20*freq_lfobank[1].value);
			set_osc_freq(&amp_lfobank[2], 0.075*0.666 + 0.15*freq_lfobank[2].value);
			set_osc_freq(&amp_lfobank[3], 0.075*2 + 0.20*freq_lfobank[3].value);
			set_osc_freq(&amp_lfobank[4], 0.075*3 + 0.15*freq_lfobank[4].value);
			set_osc_freq(&amp_lfobank[5], 0.075*5 + 0.10*freq_lfobank[5].value);
			update_osc(&amp_lfobank[i]);
		}

		final_l = 0;
		final_r = 0;
		for(int i=0; i<6; i++) {
			out = get_noise(&noisebank[i]);
			final_l += pan[i]*(0.5 + 0.5*amp_lfobank[i].value)*out;
			final_r += (1-pan[i])*(0.5 + 0.5*amp_lfobank[i].value)*out;
		}
	
		out16 = (int16_t) (INT16_MAX)*(final_l);
		fwrite(&out16, 2, 1, stdout);
		out16 = (int16_t) (INT16_MAX)*(final_r);
		fwrite(&out16, 2, 1, stdout);
	}

	return 1;
}
