/*
* noiser.cc
* DIN Is Noise is copyright (c) 2006-2022 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/

#include "noiser.h"
#include "keyboard_keyboard.h"
#include "audio.h"
#include "console.h"

noiser::noiser () {
	warp (&interp);
	last_vol = 0.0f;
	set_spread (0.0f);
	set_value (0);
}

void noiser::set_value (float v) {
	value.cur = v;
	value.next = random_value ();
	value.delta = value.next - value.cur;
	alpha.val = 0.0f;
}

void noiser::calc_delta_alpha () {
	if (samples.due < 3) alpha.delta = 1; else alpha.delta = 1.0f / (samples.due - 1);
}

void noiser::set_samples (float sn) {
	samples.next = sn;
	samples.duei = samples.due = int (sn);
	samples.derr = samples.next - samples.duei;
	calc_delta_alpha ();
}

void noiser::set_spread (float s) {
	spread = s;
	random_value.set (-spread, spread);
}

void noiser::operator() (float* L, float* R, int n, float* vola) {
	for (int i = 0; i < n; ++i) { 
		alpha.val += alpha.delta; 
		alpha.warp = warp (alpha.val); 
		float no = value.cur + alpha.warp * value.delta; 
		float vno = vola[i] * no;
		L[i] += vno;
		R[i] += vno;
		if (++samples.cur < samples.due); else {
			set_value (no);
			samples.cur = 0;
			samples.err += samples.derr;
			if (samples.err < 1.0f) {
				samples.due = samples.duei;
			} else {
				samples.due = samples.duei + 1;
				samples.err = 1.0f - samples.err;
			}
			calc_delta_alpha ();
		}
	}
}

void noiser::operator() (float* L, float* R, int n, float vol) {
	float v = last_vol;
	float dv = (vol - last_vol) * 1.0f / n; 
	for (int i = 0; i < n; ++i) { 
		alpha.val += alpha.delta; 
		alpha.warp = warp (alpha.val); 
		float no = value.cur + alpha.warp * value.delta; 
		v += dv;
		float vno = v * no;
		L[i] += vno;
		R[i] += vno;
		if (++samples.cur < samples.due); else {
			set_value (no);
			samples.cur = 0;
			samples.err += samples.derr;
			if (samples.err < 1.0f) {
				samples.due = samples.duei;
			} else {
				samples.due = samples.duei + 1;
				samples.err = 1.0f - samples.err;
			}
			calc_delta_alpha ();
		}
	}
	last_vol = vol;
}

ofstream& operator<< (ofstream& o, noiser& n) {
	extern const char spc;
	o << n.spread << spc << n.samples.next;
	return o;
}
