#include "stdafx.h"
#include "speaker_include.h"

namespace speaker{
namespace openJtalk{



COpenJtalkCore::COpenJtalkCore():
manageFlag(false){

	_beginthread(COpenJtalkCore::SynthesisThreadFunction,0,this);
	this->synthesisEventObject = ::CreateEvent(NULL,false,false,NULL);
	this->endEventObject = ::CreateEvent(NULL,true,false,NULL);

}


COpenJtalkCore::~COpenJtalkCore(){
	if(this->manageFlag == true)this->Clear();

	
	int errcount = 0;
	::SetEvent(this->endEventObject);


	::CloseHandle(this->synthesisEventObject);
	::CloseHandle(this->endEventObject);

}

void COpenJtalkCore::Initialize( HTS_Boolean use_lpf, int sampling_rate,
                          int fperiod, double alpha, int stage, double beta, int audio_buff_size,
                          double uv_threshold, HTS_Boolean use_log_gain, double gv_weight_mgc,
                          double gv_weight_lf0, double gv_weight_lpf){
							  if(this->manageFlag == true)this->Clear();
							  ::OpenJTalk_initialize(&this->openJtalk_internal,use_lpf,sampling_rate,fperiod,alpha,stage,
								  beta,audio_buff_size,uv_threshold,use_log_gain,gv_weight_mgc,gv_weight_lf0,gv_weight_lpf);

							  this->manageFlag = true;
}

void COpenJtalkCore::Load( const TChar_P in_voiceDataDir,const TChar_P in_dictinalyDataDir, Char_P fn_ms_dur, Char_P fn_ts_dur,
            Char_P fn_ms_mgc, Char_P fn_ts_mgc, Char_P *fn_ws_mgc, int num_ws_mgc,
            Char_P fn_ms_lf0, Char_P fn_ts_lf0, Char_P *fn_ws_lf0, int num_ws_lf0,
            Char_P fn_ms_lpf, Char_P fn_ts_lpf, Char_P *fn_ws_lpf, int num_ws_lpf,
            Char_P fn_ms_gvm, Char_P fn_ts_gvm, Char_P fn_ms_gvl, Char_P fn_ts_gvl,
            Char_P fn_ms_gvf, Char_P fn_ts_gvf,Char_P fn_gv_switch){

				if(this->manageFlag == true){

					CStringA dictionaryDataDir(in_dictinalyDataDir);			//辞書データディレクトリ
					CStringA voiceDataDir(in_voiceDataDir);				//音声ーデータディレクトリ

					std::vector<Char_P> ws_mgcList;
					std::vector<std::string> ws_mgcBuffList;
					

					for(int ws_mgc_index = 0;ws_mgc_index < num_ws_mgc;++ws_mgc_index){

						ws_mgcBuffList.push_back((const char*)(voiceDataDir + fn_ws_mgc[ws_mgc_index]));
						ws_mgcList.push_back(&ws_mgcBuffList.back()[0]);
					}

					std::vector<Char_P> ws_lf0List;
					std::vector<std::string> ws_lf0BuffList;
					for(int ws_lf0Index = 0;ws_lf0Index < num_ws_lf0;++ws_lf0Index){

						ws_lf0BuffList.push_back((const char*)(voiceDataDir + fn_ws_mgc[ws_lf0Index]));
						ws_lf0List.push_back(&ws_lf0BuffList.back()[0]);
					}

					std::vector<Char_P> ws_lpfList;
					std::vector<std::string> ws_lpfBuffList;
					for(int ws_lpfIndex = 0;ws_lpfIndex < num_ws_lpf;++ws_lpfIndex){

						ws_lpfBuffList.push_back((const char*)(voiceDataDir + fn_ws_mgc[ws_lpfIndex]));
						ws_lpfList.push_back(&ws_lpfBuffList.back()[0]);
					}

					::OpenJTalk_load(&this->openJtalk_internal,
						(char *)(const char*)(dictionaryDataDir),
						fn_ms_dur != NULL ?(char *)(const char*)(voiceDataDir +fn_ms_dur) : NULL,
						fn_ts_dur != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_dur) : NULL,
						fn_ms_mgc != NULL ? (char *)(const char*)(voiceDataDir +fn_ms_mgc) : NULL,
						fn_ts_mgc != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_mgc) : NULL,
						&ws_mgcList[0],
						num_ws_mgc,
						fn_ms_lf0 != NULL ?(char *)(const char*)(voiceDataDir +fn_ms_lf0) : NULL,
						fn_ts_lf0 != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_lf0) : NULL,
						&ws_mgcList[0],
						num_ws_lf0,
						fn_ms_lpf != NULL ? (char *)(const char*)(voiceDataDir +fn_ms_lpf) : NULL,
						fn_ts_lpf != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_lpf) : NULL,
						&ws_lpfList[0],
						num_ws_lpf,
						fn_ms_gvm != NULL ? (char *)(const char*)(voiceDataDir +fn_ms_gvm) : NULL,
						fn_ts_gvm != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_gvm) : NULL,
						fn_ms_gvl != NULL ? (char *)(const char*)(voiceDataDir +fn_ms_gvl) : NULL,
						fn_ts_gvl != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_gvl) : NULL,
						fn_ms_gvf != NULL ? (char *)(const char*)(voiceDataDir +fn_ms_gvf) : NULL,
						fn_ts_gvf != NULL ? (char *)(const char*)(voiceDataDir +fn_ts_gvf) : NULL,
						fn_gv_switch != NULL ? (char *)(const char*)(voiceDataDir +fn_gv_switch) : NULL
						
						);
				}
}
		
void COpenJtalkCore::Synthesis( const TChar_P txt, FILE * wavfp, FILE * logfp){
	CStringA txtA(txt);
	idumpln_mb(CP_THREAD_ACP,"synthesis:%s",(LPCSTR)txtA);
	::OpenJTalk_synthesis(&this->openJtalk_internal,(Char_P)(const char*)txtA,wavfp,logfp);
}

void COpenJtalkCore::Synthesis(const TChar_P txt){

	Synthesis(txt,NULL,NULL);

}


void COpenJtalkCore::SynthesisAsync(const TChar_P txt){

	this->synthesisQueueCS.Lock();

	if(this->synthesisQueue.size() > 3)this->synthesisQueue.pop_back();

	this->synthesisQueue.push_front(txt);

	this->synthesisQueueCS.Unlock();

	::SetEvent(this->synthesisEventObject);
}

void COpenJtalkCore::Clear(){
	::OpenJTalk_clear(&this->openJtalk_internal);
	this->manageFlag = false;
}

void  COpenJtalkCore::SynthesisThreadFunction(void *userData){

	auto &self = *(COpenJtalkCore*)userData;

	HANDLE eventList[2] = {self.synthesisEventObject,self.endEventObject};

	DWORD dwRslt;

	do{
		dwRslt = ::WaitForMultipleObjects(sizeof(eventList) / sizeof(eventList[0]),eventList,false,INFINITE);

		if(dwRslt-  WAIT_OBJECT_0 == 1)break;
		else if(dwRslt-  WAIT_OBJECT_0 == 0){
			CString synthesisString(TEXT(""));
			
			self.synthesisQueueCS.Lock();

			 
			
			auto rbegin = self.synthesisQueue.rbegin();
			auto rend = self.synthesisQueue.rend();

			for(;rbegin != rend;(++rbegin)){
				synthesisString += *rbegin;

				if(rbegin != rend){
					synthesisString += TEXT(" ");
				}
			}
			self.synthesisQueue.clear();
			self.synthesisQueueCS.Unlock();

			

			self.Synthesis((const TChar_P)(const wchar_t*)synthesisString);
		}


	} while(true);
	
	_endthread();

	return ;
}

}
}