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

#include "binaural_drone.h"
#include "audio.h"
#include "console.h"

extern void hz2step (float& hz, float& step);
extern void step2hz (float& step, float& hz);

extern char BUFFER[];

binaural_drone::binaural_drone (multi_curve* wav, float _lhz, float _rhz, float _vol, int _just, float _sep, float lx, float rx) {

	soll (wav);
	solr (wav);
	playl.set_wave (&soll);
	playr.set_wave (&solr);

	l_step = r_step = 0.0f;
	set_hz (_lhz, _rhz);
	if (lx == INVALID) // normal lx is in [0,1]
		sync ();
	else {
		playl.x = lx;
		playr.x = rx;
	}

	vol = 0.0f;
	set_vol (_vol);

	just = _just;
	sep = _sep;

	sel = 0;

}

void binaural_drone::make_name () {
	sprintf (BUFFER, BD_NAME, l_hz, sep, r_hz, vol * 100);
	name = BUFFER;
}

void binaural_drone::make_name (float stepl, float stepr) {
	float hzl, hzr; step2hz (stepl, hzl); step2hz (stepr, hzr);
	sprintf (BUFFER, BD_NAME, hzl, (hzr - hzl), hzr, vol * 100);
	name = BUFFER;
}

void binaural_drone::make_name (float v) {
	sprintf (BUFFER, BD_NAME, l_hz, sep, r_hz, v * 100);
	name = BUFFER;
}

void binaural_drone::set_hz (int i, float v) {

	float* step_prev [] = {&l_step_prev, &r_step_prev};
	float* hz [] = {&l_hz, &r_hz};
	float* step [] = {&l_step, &r_step};
	int flags [] = {fade_flags::L, fade_flags::R};
	float* step_cur [] = {&fading.l_step_cur, &fading.r_step_cur};
	
	float& step_prev_i = *step_prev[i];
	float& hz_i = *hz[i];
	float& step_i = *step[i];

	int j = !i;
	*step_cur[j] = *step[j];

	step_prev_i = step_i;
	hz_i = v;
	hz2step (hz_i, step_i);
	sep = r_hz - l_hz;

	int fi = flags[i];
	if (fading.hz) {
		if (fading.hz != fi) fading.hz = fade_flags::BOTH;
	} else fading.hz = fi;

}

void binaural_drone::set_hz (float _lhz, float _rhz) {
	l_step_prev = l_step;
	r_step_prev = r_step;
	l_hz = _lhz;
	r_hz = _rhz;
	sep = r_hz - l_hz;
	hz2step (l_hz, l_step);
	hz2step (r_hz, r_step);
	fill_hz ();
	make_name ();
}

void binaural_drone::fill_hz () {
	playl.fill_pitch (l_step);
	playr.fill_pitch (r_step);
}

void binaural_drone::set_vol (float v) {
	vol_prev = vol;
	vol = v;
	fading.vol = 1;
}

void binaural_drone::set_sep (float s) {
	switch (just) {
		case LEFT:
			set_hz (RIGHT, l_hz + s);
			break;
		case RIGHT:
			set_hz (LEFT, r_hz - s);
			break;
		case CENTER:
			float mid = (l_hz + r_hz) / 2.0, s2 = s / 2.0;
			set_hz (LEFT, mid - s2);
			set_hz (RIGHT, mid + s2);
			break;
	}
}

void binaural_drone::set_just (int j) {
	just = j;
}

void binaural_drone::render (float* L, float* R, float* vfdr, float* pfdr, int uv, int uh, int abort) {

	play* pl [] = {&playl, &playr};
	float* outf [] = {L, R};
	float* outi [] = {aout.bufL, aout.bufR};

	if (fading.vol) {
		calc_fader (aout.fdr1, vfdr, aout.samples_per_channel, vol_prev, vol, &fading.vol_cur);
		if (uv) {
			make_name (fading.vol_cur);
			if (abort) {
				vol = fading.vol_cur;
				fading.vol = fade_flags::NONE;
			}
		}
	}

	if (fading.hz) {
		if (fading.hz == fade_flags::L || fading.hz == fade_flags::BOTH) 
			calc_fader (playl.pdx, pfdr, aout.samples_per_channel, l_step_prev, l_step, &fading.l_step_cur);
		if (fading.hz == fade_flags::R || fading.hz == fade_flags::BOTH) 
			calc_fader (playr.pdx, pfdr, aout.samples_per_channel, r_step_prev, r_step, &fading.r_step_cur);
		if (uh) {
			make_name (fading.l_step_cur, fading.r_step_cur);
			if (abort) {
				l_step = fading.l_step_cur;
				r_step = fading.r_step_cur;
				step2hz (fading.l_step_cur, l_hz);
				step2hz (fading.r_step_cur, r_hz);
				sep = r_hz - l_hz;
				fill_hz ();
				fading.hz = fade_flags::NONE;
			}
		}
	}


	for (int i = 0; i < 2; ++i) {
		float* outfi = outf [i];
		float* outii = outi [i];
		memset (outii, 0, aout.samples_channel_size);
		play* pli = pl [i];
		if (fading.vol) 
			pli->gen_wav_mix (outii, aout.fdr1, aout.samples_per_channel); 
		else 
			pli->gen_wav_mix (outii, vol, aout.samples_per_channel);
		for (int j = 0, k = aout.samples_per_channel; j < k; ++j) outfi[j] += outii[j];
	}

}

void binaural_drone::calc_fader (float* out, float* alpha, int n, float v1, float v2, float* cur) {
	float dv = v2 - v1;
	for (int i = 0; i < n; ++i) {
		float ai = alpha[i];
		out[i] = v1 + ai * dv;
	}
	*cur = out[n-1];
}

void binaural_drone::sync () {
	// so first += solves to y=0 [depends on waveform shape]
	playl.x = -playl.pdx[0];
	playr.x = -playr.pdx[0];
}
