
// Library Files SF3
#include "speechdetectionandseparation.h"
#include "noisecancellation.h"
// Header and source code SF1
#include "analysistransform.h"
#include "synthesistransform.h"
#include "soundfielddescription.h"
#include "packager.h"

// Reading wav files 
#include "AudioFile.h"
// standard C++ libraries
#include <fstream>
#include <iostream>

#include <stdlib.h>

int main()
{

	int samplingrates[8] = { 16000,24000,32000,44100,48000,64000,96000,192000 };
	int sampletypes[3] = { 16,24,32 };
	int blocksizes[8] = { 64,128,256,512,1024,2048,4096,8192 };

		char microphonearraygeometry[] = R"(
		{
			"$schema": "http://json-schema.org/draft-07/schema#",
			"title": "Microphone Array Geometry",
			"MicrophoneArrayType": 0,
			"MicrophoneArrayScat": 0,
			"MicrophoneArrayFilterURI": "eigenmike_filter.file",
			"SamplingRate": 4,
			"SampleType": 1,
			"BlockSize": 5,
			"NumberofMicrophones": 32,
			"MicrophoneList" : [
					{"xCoord" :  0.93358,"yCoord" : 0.0,"zCoord" : 0.35836,"directivity" : 1.0,"micxLookCoord" : 0.93358,"micyLookCoord" : 0.0,"miczLookCoord" : 0.35836},
					{"xCoord" :  0.84804,"yCoord" : 0.52991,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : 0.84804,"micyLookCoord" : 0.52991,"miczLookCoord" : 0.0},
					{"xCoord" :  0.93358,"yCoord" : 0.0,"zCoord" : -0.35836,"directivity" : 1.0,"micxLookCoord" : 0.93358,"micyLookCoord" : 0.0,"miczLookCoord" : -0.35836},
					{"xCoord" :  0.84804,"yCoord" : -0.52991,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : 0.84804,"micyLookCoord" : -0.52991,"miczLookCoord" : 0.0},
					{"xCoord" :  0.52991,"yCoord" : 0.0,"zCoord" : 0.84804,"directivity" : 1.0,"micxLookCoord" : 0.52991,"micyLookCoord" : 0.0,"miczLookCoord" : 0.84804},
					{"xCoord" :  0.57922,"yCoord" : 0.57922,"zCoord" : 0.57357,"directivity" : 1.0,"micxLookCoord" : 0.57922,"micyLookCoord" : 0.57922,"miczLookCoord" : 0.57357},
					{"xCoord" :  0.35836,"yCoord" : 0.93358,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : 0.35836,"micyLookCoord" : 0.93358,"miczLookCoord" : 0.0},
					{"xCoord" :  0.57922,"yCoord" : 0.57922,"zCoord" : -0.57357,"directivity" : 1.0,"micxLookCoord" : 0.57922,"micyLookCoord" : 0.57922,"miczLookCoord" : -0.57357},
					{"xCoord" :  0.52991,"yCoord" : 0.0,"zCoord" : -0.84804,"directivity" : 1.0,"micxLookCoord" : 0.52991,"micyLookCoord" : 0.0,"miczLookCoord" : -0.84804},
					{"xCoord" :  0.57922,"yCoord" : -0.57922,"zCoord" : -0.57357,"directivity" : 1.0,"micxLookCoord" : 0.57922,"micyLookCoord" : -0.57922,"miczLookCoord" : -0.57357},
					{"xCoord" :  0.35836,"yCoord" : -0.93358,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : 0.35836,"micyLookCoord" : -0.93358,"miczLookCoord" : 0.0},
					{"xCoord" :  0.57922,"yCoord" : -0.57922,"zCoord" : 0.57357,"directivity" : 1.0,"micxLookCoord" : 0.57922,"micyLookCoord" : -0.57922,"miczLookCoord" : 0.57357},
					{"xCoord" :  -0.00625,"yCoord" : 0.35831,"zCoord" : 0.93358,"directivity" : 1.0,"micxLookCoord" : -0.00625,"micyLookCoord" : 0.35831,"miczLookCoord" : 0.93358},
					{"xCoord" :  0.0,"yCoord" : 0.84804,"zCoord" : 0.52991,"directivity" : 1.0,"micxLookCoord" : 0.0,"micyLookCoord" : 0.84804,"miczLookCoord" : 0.52991},
					{"xCoord" :  0.0,"yCoord" : 0.85716,"zCoord" : -0.51503,"directivity" : 1.0,"micxLookCoord" : 0.0,"micyLookCoord" :  0.85716,"miczLookCoord" : -0.51503},
					{"xCoord" :  0.006254,"yCoord" : 0.35831,"zCoord" : -0.93358,"directivity" : 1.0,"micxLookCoord" : 0.006254,"micyLookCoord" : 0.35831,"miczLookCoord" : -0.93358},
					{"xCoord" :  -0.93358,"yCoord" : 0.0,"zCoord" : 0.35836,"directivity" : 1.0,"micxLookCoord" : -0.93358,"micyLookCoord" : 0.0,"miczLookCoord" : 0.35836},
					{"xCoord" :  -0.84804,"yCoord" : -0.52991,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : -0.84804,"micyLookCoord" : -0.52991,"miczLookCoord" : 0.0},
					{"xCoord" :  -0.93358,"yCoord" : 0.0,"zCoord" : -0.35836,"directivity" : 1.0,"micxLookCoord" : -0.93358,"micyLookCoord" : 0.0,"miczLookCoord" : -0.35836},
					{"xCoord" :  -0.84804,"yCoord" : 0.52991,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : -0.84804,"micyLookCoord" : 0.52991,"miczLookCoord" : 0.0},
					{"xCoord" :  -0.52991,"yCoord" : 0.0,"zCoord" : 0.84804,"directivity" : 1.0,"micxLookCoord" : -0.52991,"micyLookCoord" : 0.0,"miczLookCoord" : 0.84804},
					{"xCoord" :  -0.57922,"yCoord" : -0.57922,"zCoord" : 0.57357,"directivity" : 1.0,"micxLookCoord" : -0.57922,"micyLookCoord" : -0.57922,"miczLookCoord" : 0.57357},
					{"xCoord" :  -0.35836,"yCoord" : -0.93358,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : -0.35836,"micyLookCoord" : -0.93358,"miczLookCoord" : 0.0},
					{"xCoord" :  -0.57922,"yCoord" : -0.57922,"zCoord" : -0.57357,"directivity" : 1.0,"micxLookCoord" : -0.57922,"micyLookCoord" : -0.57922,"miczLookCoord" : -0.57357},
					{"xCoord" :  -0.52991,"yCoord" : 0.0,"zCoord" : -0.84804,"directivity" : 1.0,"micxLookCoord" : -0.52991,"micyLookCoord" : 0.0,"miczLookCoord" : -0.84804},
					{"xCoord" :  -0.57922,"yCoord" : 0.57922,"zCoord" : -0.57357,"directivity" : 1.0,"micxLookCoord" : -0.57922,"micyLookCoord" : 0.57922,"miczLookCoord" : -0.57357},
					{"xCoord" :  -0.35836,"yCoord" : 0.93358,"zCoord" : 0.0,"directivity" : 1.0,"micxLookCoord" : -0.35836,"micyLookCoord" : 0.93358,"miczLookCoord" : 0.0},
					{"xCoord" :  -0.57922,"yCoord" : 0.57922,"zCoord" : 0.57357,"directivity" : 1.0,"micxLookCoord" : -0.57922,"micyLookCoord" : 0.57922,"miczLookCoord" : 0.57357},
					{"xCoord" :  -0.00625,"yCoord" : -0.35831,"zCoord" : 0.93358,"directivity" : 1.0,"micxLookCoord" : -0.00625,"micyLookCoord" : -0.35831,"miczLookCoord" : 0.93358},
					{"xCoord" :  0.0,"yCoord" : -0.84804,"zCoord" : 0.52991,"directivity" : 1.0,"micxLookCoord" : 0.0,"micyLookCoord" : -0.84804,"miczLookCoord" : 0.52991},
					{"xCoord" :  0.0,"yCoord" : -0.84804,"zCoord" : -0.52991,"directivity" : 1.0,"micxLookCoord" : 0.0,"micyLookCoord" : -0.84804,"miczLookCoord" : -0.52991},
					{"xCoord" :  0.00625,"yCoord" : -0.35831,"zCoord" : -0.93358,"directivity" : 1.0,"micxLookCoord" : 0.00625,"micyLookCoord" : -0.35831,"miczLookCoord" : -0.93358}
				],
			 "MicrophoneArrayLookCoord" : {"xLookCoord" : 0.0, "yLookCoord" : 0.0, "zLookCoord" : 0.0}
		}
     )";
		

		json j_complete = json::parse(microphonearraygeometry);

		// Parameters during the pre-construction of the parameters
		int SamplingFrequency = samplingrates[(int)j_complete["SamplingRate"]];
		int windowsize = blocksizes[(int)j_complete["BlockSize"]];
		int blocksize = 1;
		int total = blocksizes[(int)j_complete["BlockSize"]]; // windowsize* blocksize;
		int nofmics = (int)j_complete["NumberofMicrophones"];
		// Initial parameter to set the number of sources
		int FixedSperationWavSize = 6;
		int nofsource = 6;

		/* Read the microphone array audio files for test
		 Input feeding the microphone array recordings
		 ********************************************
		 ********************************************/
		std::string SpeechPath = std::string("F:/TestSet2/20230623-075459/"); 
		//std::string SpeechPath = std::string("F:/TestSet2/20230624-152142/");
		
		// Operational pointers for the algorithm workflow
		double* signal = (double*)calloc(total * nofmics, sizeof(double));
		double* signal_out = (double*)calloc(total * nofmics, sizeof(double));
		float* realpart = (float*)calloc(nofmics * (windowsize / 2) * blocksize, sizeof(float));
		float* imagpart = (float*)calloc(nofmics * (windowsize / 2) * blocksize, sizeof(float));



		int hopsize = windowsize - 0;
		int msgsize = 0;

		/*Constructors*/
		analysistransform* m_fft = new analysistransform(windowsize, total, windowsize / 2, nofmics);
		synthesistransform* m_ifft = new synthesistransform(windowsize, (windowsize / 2) * blocksize, windowsize / 2, nofmics);
		soundfielddescription* sfd = new soundfielddescription(microphonearraygeometry);
		speechdetectionandseparation* sds = new speechdetectionandseparation(microphonearraygeometry, blocksize);
		noisecancellation* nc = new noisecancellation(windowsize, blocksize);
		packager* m_packager = new packager();

		sds->initialization(windowsize);

		for (int fileindex = 0; fileindex < 495; fileindex++)

		{

			sds->clear_doas();
			/********************************************
			* ********************************************
			*/
			int Nofsamples;

			ofstream fileStream(SpeechPath + std::to_string(fileindex) + "/Alg/recordings.txt");

			vector<AudioFile<float>> vec_audio = vector<AudioFile<float>>();
			for (int ml = 0; ml < nofmics; ml++)
			{
				AudioFile<float> a;

				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Nemeth/Nemeth") + std::to_string(ml + 1) + ".wav";
			 // const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/mhacoustics_studio/ShowcaseShowdown_") + std::to_string(ml+1) + ".wav";
				//20230623 - 075459\0
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Demo/AC_0/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = SpeechPath + std::to_string(fileindex) + "/speech" + std::to_string(ml) + "-norm_out.wav";
				const std::string inputFilePath = SpeechPath + std::to_string(fileindex) + "/speech" + std::to_string(ml) + "-norm_out.wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Demo/AC_0/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Demo/AC_2/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Demo/AC_1/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Nonreverberant/20230411-005601/0/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Nonreverberant/20230415-121522/AC/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Nonreverberant/20230411-010718/AC/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/Nonreverberant/20230411-010706/AC/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/20220312-101609/AC_0/speech") + std::to_string(ml) + ".wav";
				//const std::string inputFilePath = std::string("C:/Users/ihtar/Desktop/Speech_folder/TestSet/0/speech") + std::to_string(ml) + "-norm_out.wav";
				bool loadedOK = a.load(inputFilePath);
				Nofsamples = a.getNumSamplesPerChannel();
				if (loadedOK)
					vec_audio.push_back(a);
			}
			// Output to be malloc
			AudioFile<float>::AudioBuffer buffer;
			buffer.resize(FixedSperationWavSize);

			for (int klo = 0; klo < FixedSperationWavSize; klo++)
			{
				buffer[klo].resize(Nofsamples);

			}
			int padding = 0;
			bool checkit = false;
			for (int id = 0; id < Nofsamples; id += (hopsize- padding))
			{
				/*Analysis Block by Block*/
				for (int idk = 0; idk < padding; idk++)
				{
					if ((id + idk) < Nofsamples)
					{
						for (int mic_id = 0; mic_id < nofmics; mic_id++)
						{

							*(signal + idk * nofmics + mic_id) = 0.0; // 0.5 * sin(2.0 * 3.14 * 0.0625 * (float)(id + idk)); //
						}
					}
					else
					{
						for (int mic_id = 0; mic_id < nofmics; mic_id++)
						{
							*(signal + idk * nofmics + mic_id) = 0.0;
						}
					}

				}

				for (int idk = padding; idk < total; idk++)
				{
					if ((id + idk) < Nofsamples)
					{
						for (int mic_id = 0; mic_id < nofmics; mic_id++)
						{

							*(signal + idk * nofmics + mic_id) = vec_audio[mic_id].samples[0][(int)(id + idk)]; // 0.5 * sin(2.0 * 3.14 * 0.0625 * (float)(id + idk)); //
						}
					}
					else
					{
						for (int mic_id = 0; mic_id < nofmics; mic_id++)
						{
							*(signal + idk * nofmics + mic_id) = 0.0;
						}
					}

				}



				std::cout << "Block sampling time = " << (float)(windowsize * blocksize * 1000) / (float)SamplingFrequency << " msec" << std::endl;


				std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
				m_fft->FFT(signal, realpart, imagpart);

				//m_ifft->SetSourceSize(nofsource);
				//m_ifft->IFFT(signal_out, realpart, imagpart);

						// Detect the number of sources via RENT
				nofsource = sds->RENTComputation(realpart, imagpart);

				// recording for testing the trajectory
				////////////////////////////////////////////////////////
				if (fileStream.is_open())
				{

					json asg = sds->audioscenegeometry_out();
					int sid = asg["SpeechCount"];
					fileStream << sid << ";";
					for (int si = 0; si < sid; si++)
						fileStream << static_cast<double>(asg["SpeechList"][si]["ElevationDirection"]) << ";" << static_cast<double>(asg["SpeechList"][si]["AzimuthDirection"]) << ";";
				}
				fileStream << endl;

				////////////////////////////////////////////////////////
				if (nofsource > 0)
				{

					complex_num multip_SRF = sds->Return_BlockSRF();
					// Speech separation results 
					complex_num num_res = sds->SpeechSeparation();
					// Audio Scene Description
					nc->getwienermatrices(sds->audioscenegeometry_out());
					// Speech Separation Results and spherical harmonics will be input for noise cancellation
					nc->Operate_NoiseCancellation((float*)multip_SRF.real, (float*)multip_SRF.imag, (float*)num_res.real, (float*)num_res.imag, (float*)num_res.pressurelevel);
					// Set the number of sources after speech detection and separation
					m_ifft->SetSourceSize(nofsource);
					// Inverse FFT is applied for the separated sources
					m_ifft->IFFT(signal_out, num_res.real, num_res.imag);
				}
				unsigned char* result = m_packager->createdata(sds->audioscenegeometry_out(), json::parse(microphonearraygeometry), signal_out, &msgsize);


				//float maxval = 0.0;
				float averaging = 0.0;
				float preaveraging = 0.0;
				int counter;


				for (int channel = 0; channel < nofsource; channel++)
				{

					counter = 0;
					float blender = 32;
					int cnt = 0;
					double max = 0.0;
					float alpha;
					for (int ijk = (id + (total - hopsize)); ijk < id + total - padding; ijk++)
					{
					//	alpha = cnt / blender;
					//	if (cnt >= blender)
					//		alpha = 1.0;
					//	if (ijk >= Nofsamples)
					//		break;
						//if(ijk > (id + (total - hopsize) -16 ) && ijk > 16 && ijk < (id + (total - hopsize) + 16))
						//	buffer[channel][ijk] = (double)alpha * signal_out[counter + channel]   + (1-alpha) * buffer[channel][ijk-1];
						//else

						//if (ijk > 0  && counter + channel + nofsource < total * nofsource)
						//	buffer[channel][ijk] = 0.33 * buffer[channel][ijk - 1] + 0.33 * (double)signal_out[counter + channel] +0.33 * (double)signal_out[counter + channel + nofsource];
						//else
							buffer[channel][ijk] = (double)signal_out[counter + channel];

						counter += nofsource;
					//	cnt++;
					}

				}

				//buffer[5][(id + (total - hopsize))] = (double)1.0;

				//signal_out = (double*)calloc(total * nofmics, sizeof(double));
				std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
				std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << "Samples :" << id << "Total:" << Nofsamples << std::endl;
			}


			fileStream.close();

			AudioFile<float> a;
			a.setBitDepth(32);
			a.setSampleRate(SamplingFrequency);
			a.setAudioBuffer(buffer);
			a.save(SpeechPath + std::to_string(fileindex) + "/Alg/" + std::string("seperated.wav"), AudioFileFormat::Wave);

			vec_audio.clear();

			//system(std::to_string("ffmpeg -i") + SpeechPath + std::to_string(fileindex) + "/Alg/" + std::string("seperated.wav")  + " - af "'lowpass = f = 4000'" separated_1_out.wav")
			//sds->~speechdetectionandseparation();
		}


	return 0;
}
