/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#+
#+     Internet Radio Automation & Encoding Toolkit
#+
#+     Copyright (C) 2018, 2019, 2020, 2021 by Kevin C. O'Kane
#+
#+     Kevin C. O'Kane
#+     kc.okane@gmail.com
#+     https://www.cs.uni.edu/~okane
#+     https://threadsafebooks.com/
#+
#+ This program is free software; you can redistribute it and/or modify
#+ it under the terms of the GNU General Public License as published by
#+ the Free Software Foundation; either version 2 of the License, or
#+ (at your option) any later version.
#+
#+ This program is distributed in the hope that it will be useful,
#+ but WITHOUT ANY WARRANTY; without even the implied warranty of
#+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#+ GNU General Public License for more details.
#+
#+ You should have received a copy of the GNU General Public License
#+ along with this program; if not, write to the Free Software
#+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

//	Oct 25, 2022

#include "includes.h"
#include "common-externs.h"

#define SLASH '/'

#include "defines.h"

//--------------------------------------------------
//	frequency spectrum service function
//--------------------------------------------------

#define WindowWidth 200

int width = WindowWidth;     // two times the display window - half left, half right
int numBars = WindowWidth /2;

int maxHeight = 100; // display window max from midpoint

void	fftTobars(fftw_complex *fft, int size, int *bars) {

	double strength, real, imagin, scale;
	int amplitude, i, j, bar, incr;

	scale = 0.0003;

	i = 0; // fft index

	if (band_width == 1 && band_start == 0) {

		for (bar = 0; bar < numBars; bar++) { // average for each bar

			real = fft[i][0] * scale;
			imagin = fft[i][1] * scale;
			strength = real * real + imagin * imagin;  // result is not negative
			i++;

			if (strength < 1.00e-10) strength = 1.00e-10; // prevent overflows.

			if (strength > 0.0) amplitude = (maxHeight + (int) (10.0 * log10(strength))) * 2.0;
			else amplitude = 0.0;

			if (amplitude > maxHeight) amplitude = maxHeight;
			if (amplitude < 0) amplitude = 0;

			bars[bar] = amplitude;

			if (style == NARROW_SPECTRUM || style == VERY_NARROW_SPECTRUM ) {
				bar++;
				bars[bar] = (bars[bar - 1] + amplitude) / 2.0; // double up
				if (style == VERY_NARROW_SPECTRUM) {
					bar++;
					bars[bar] = (bars[bar - 2] + bars[bar - 1] + amplitude) / 3.0; // triple up
					}
				}

			}


		return;
		}

//-----------------------------------

	i = band_start; // fft index

	for (bar = 0; bar < numBars; bar++) bars[bar] = 0;

	for (bar = 0; bar < numBars - band_start; bar = bar+band_width) { // average for each bar

		real = fft[i][0] * scale;
		imagin = fft[i][1] * scale;
		strength = real * real + imagin * imagin;  // result is not negative
		i++;

		if (strength < 1.00e-10) strength = 1.00e-10; // prevent overflows.

		if (strength > 0.0) amplitude = (maxHeight + (int) (10.0 * log10(strength))) * 2.0;
		else amplitude = 0.0;

		if (amplitude > maxHeight) amplitude = maxHeight;
		if (amplitude < 0) amplitude = 0;

		for (int j=bar; j<bar+band_width; j++) {
			bars[j] = amplitude;
			}

		}
	}

//------------------------------------------------------
//	Calculate frequency spectrum array
//------------------------------------------------------

void	spectrum() {

	int size = SAMPLE_SIZE / 2;

	static float Hann[SAMPLE_SIZE/2] = {0.0};
	static int first = 1;

	/**************************************
		if (! exchange) {
	                for (int i=0; i < size; i++) slchan[i] = 0.0;
	                for (int i=0; i < size; i++) srchan[i] = 0.0;
			return;
			}
	**************************************/

	if (first)  {
		for(int n = 0; n < size; n++)  {
			Hann[n] = 0.5 * (1.0 - cos(2.0 * M_PI * n / (size - 1.0))) ;
			}
		}

	first = 0;

#define CHANNELS 2

	double in[SAMPLE_SIZE / 2] = {0.0};
	fftw_complex out[SAMPLE_SIZE / 2] ;

//	fftw_plan plan = fftw_plan_dft_r2c_1d(size, in, out, FFTW_MEASURE); // alternates
//	fftw_plan plan = fftw_plan_dft_r2c_1d(size, in, out, FFTW_PATIENT);

	fftw_plan plan = fftw_plan_dft_r2c_1d(size, in, out, FFTW_ESTIMATE);

	int barsL[WindowWidth/2] = {0}, barsR[WindowWidth/2] = {0};

//----------------------
//	left channel
//----------------------

	for (int i=0; i<size; i++) in[i] = Hann[i] * exchangeBuf[i * 2]; // every other element

	fftw_execute(plan);

	fftTobars(out, size, barsL);

	double F = 0.90;

#define EnhanceTreble 0.04

	for (int i = 0; i < width / 2; i++) {

		if (barsL[i] < 0.0 ) slchan[i] = 0.0;

		else {
			barsL[i] = barsL[i] * AudioCalibrate;

			if (draw_mode == DRAWS1) {
				if (super_bars) { // botoom of graph
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsL[i] *= F;
						F += EnhanceTreble;
						} // enhance treble
					slchan[i] = barsL[i] * SCALE_VISUAL_SPECTRUM;
					}
				else {
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsL[i] *= F;
						F += EnhanceTreble;
						} // enhance treble
					slchan[i] = barsL[i] * SCALE_VISUAL1_SPECTRUM;
					}
				}
			else {
				if (super_bars) { // baseleine
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsL[i] *= F;
						F += EnhanceTreble;
						} // enhance treble
					slchan[i] = barsL[i] * SCALE_BASELINE_SPECTRUM;
					}
				else {
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsL[i] *= F;
						F += EnhanceTreble;
						}
					slchan[i] = barsL[i] * SCALE_MIDLINE_SPECTRUM;
					}
				}

			if (slchan[i] > SPECTRUM_PEAK) slchan[i] = SPECTRUM_PEAK;
			}
		}


//	-------------
//	right channel
//	-------------

	for (int i=0; i<size; i++) in[i] = Hann[i] * exchangeBuf[i * 2 + 1]; // every other element

	fftw_execute(plan);
	fftTobars(out, size, barsR);


	F = 0.90;

	for (int i=0; i<width/2; i++) {

		if (barsR[i] < 0.0) srchan[i] = 0.0;

		else {
			barsR[i] = barsR[i] * AudioCalibrate;

			if (draw_mode == DRAWS1) {
				if (super_bars) { // bottom graph
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsR[i] *= F;
						F += EnhanceTreble;
						} // enhance treble
					srchan[i] = barsR[i] * SCALE_VISUAL_SPECTRUM;
					}
				else {
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsR[i] *= F;
						F += EnhanceTreble;
						} // enhance treble
					srchan[i] = barsR[i] * SCALE_VISUAL1_SPECTRUM;
					}
				}

			else { // DRAWS mode
				if (super_bars) { // bottom graph
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsR[i] *= F;
						F += EnhanceTreble;
						} // enhance treble
					srchan[i] = barsR[i] * SCALE_BASELINE_SPECTRUM;
					}

				else {
					if (circular_graph && !(bulls_eye || bulls_eye1)) {
						barsR[i] *= F;
						F += EnhanceTreble;
						}
					srchan[i] = barsL[i] * SCALE_MIDLINE_SPECTRUM;
					}
				}

			if (srchan[i] > SPECTRUM_PEAK) slchan[i] = SPECTRUM_PEAK;
			}
		}


//        fftw_free(in);
//        fftw_free(out);

	fftw_destroy_plan(plan);

	exchange = 0;
	}


void    on_bandwidth_value_changed( GtkSpinButton *s, GtkScrollType scr) {
	band_width = gtk_spin_button_get_value(s);
	printf("band width changed  %d\n", band_width);
	}

void    on_bandstart_value_changed( GtkSpinButton *s, GtkScrollType scr) {
	band_start = gtk_spin_button_get_value(s);
	printf("band start changed  %d\n", band_start);
	}
