#include <v_lib.h>

static char *d2c(char *buf)
{
	char *ptr;
	for(ptr = buf;*ptr;ptr++)
		if(*ptr == '.')
			*ptr = ',';
	return buf;
}

struct rec
{
	vec_t delta;
	vec_t time;
	vec_t abs_amp;
	vec_t en;
};

void postprocess(vhandle_t out,struct rec *records,unsigned len)
{
	unsigned i;
	char buf[256];
	struct rec *r;
	vec_t min_amp, min_en;
	if(!len)
		return;
	min_amp = records->abs_amp;
	min_en = records->en;
	for(i = 1;i < len - 1;i++) /* exclude last sample */
	{
		r = records + i;
		if(min_amp > r->abs_amp)
			min_amp = r->abs_amp;
		if(min_en > r->en)
			min_en = r->en;
	}
	for(i = 0;i < len;i++)
	{
		r = records + i;
		sprintf(buf,"%g;%g;%g;%g",r->delta,r->time,r->abs_amp - min_amp,r->en - min_en);
		filePuts(out,d2c(buf));
	}
}

vboolean wav2txt(char *name_in,char *name_out,vec_t summation_time)
{
	vhandle_t in, out;
	u32_t nc,bps,freq;
	vec_t t, time, dt, a, amp, en;
	vec_t scale;
	s16_t sample;
	bstack_t outs;
	struct rec r;
	stackInit(&outs, sizeof(struct rec));
	in = wavOpenRead(name_in);
	if(!in)
	{
		return false;
	}
	fileControl(in,pctl_wave_get_sampling_frequency,&freq);
	fileControl(in,pctl_wave_get_bits_per_sample,&bps);
	fileControl(in,pctl_wave_get_num_channels,&nc);
	if(nc != 1)
	{
		conlPrintf(LOG_ERROR,
			"wav2txt: %s - more than one channel, please convert to mono first.\n",
			name_in);
		fileClose(in);
		return -1;
	}
	if(bps != 16)
	{
		conlPrintf(LOG_ERROR,
			"wav2txt: %s - 16 bits per sample expected.\n",
			name_in);
		fileClose(in);
		return -1;
	}
	out = fileOpenWrite(name_out);
	if(!out)
	{
		conlPrintf(LOG_ERROR,
			"wav2txt: %s - unable to write to.\n",
			name_out);
		fileClose(in);
		return -1;
	}
	dt = 1.0 / (vec_t)freq;
	scale = dt / (vec_t)(0xFFFF >> 1);
	amp = en = 0;
	t = time = 0;
	filePrintf(out,"dt;time;abs_amp;eng\n");
	while(fileRead(in, &sample, 2)) /* sample = fileGetLittleShort(in) */
	{
		a = sample;
		amp += v_abs(a);
		en += a * a;
		t += dt;
		if(t >= summation_time)
		{
			/*
			sprintf(buf,"%g;%g;%g;%g",t,time,amp * scale,en * scale * scale);
			*/
			r.time = time;
			r.delta = t;
			r.abs_amp = amp * scale;
			r.en = en * scale * scale;
			stackPush(&outs, &r);
			time += t;
			t = 0;
			amp = en = 0;
		}
	}
	r.time = time;
	r.delta = t;
	r.abs_amp = amp * scale;
	r.en = en * scale * scale;
	stackPush(&outs, &r);
	postprocess(out,(struct rec*)stackGetStorage(&outs),stackCount(&outs));
	stackClear(&outs);
	fileClose(in);
	fileClose(out);
	return true;
}

int main(int argc, char *argv[])
{
	vec_t st;
	if(argc != 4 || (st = atof(argv[3])) == 0)
	{
		puts("usage: wav2txt infile outfile summation_time_in_seconds");
		return -1;
	}
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	return wav2txt(argv[1], argv[2], st) ? 0 : -1;
}
