///////////////////////////////////////////////////
// filename:PCMAudio.cpp
// author: Chafumi Touji
// version: 1.0.1
// date: 2018/09/27
//		 2020/02/04
///////////////////////////////////////////////////

#include "ChaSound.h"
#include "PCMAudio.h"

CPCMAudio::CPCMAudio(){

	lpDSound = NULL;
	lpDSoundBufferPrimary = NULL;
	WndDSound = NULL;
	ZeroMemory( &WFE_Primary, sizeof( WAVEFORMATEX ));
	FFTCount = FFT_COUNT;
	SampleLeft = new int[FFT_SAMPLE_COUNT];
	SampleRight = new int[FFT_SAMPLE_COUNT];
	FFTLeft = new double[FFTCount + 1];
	FFTRight = new double[FFTCount + 1];
	ReTempLeft = new double[FFT_SAMPLE_COUNT];
	ReTempRight = new double[FFT_SAMPLE_COUNT];
	ImTempLeft = new double[FFT_SAMPLE_COUNT];
	ImTempRight = new double[FFT_SAMPLE_COUNT];
	memset(SampleLeft, 0, sizeof(int)* FFT_SAMPLE_COUNT);
	memset(SampleRight, 0, sizeof(int)* FFT_SAMPLE_COUNT);
	memset(FFTLeft, 0, sizeof(double)* ( FFTCount + 1 ));
	memset(FFTRight, 0, sizeof(double)* ( FFTCount + 1 ));
	memset(ReTempLeft, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ReTempRight, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ImTempLeft, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ImTempRight, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	FFTLeftBack = (double **) new double*[FFT_AVE_COUNT + 1];
	FFTRightBack = (double **) new double*[FFT_AVE_COUNT + 1];
	for (int i = 0; i <= FFT_AVE_COUNT - 1; i++){
		FFTLeftBack[i] = (double *) new double[FFTCount + 1];
		FFTRightBack[i] = (double *) new double[FFTCount + 1];
		memset(FFTLeftBack[i], 0, sizeof(double)* ( FFTCount + 1));
		memset(FFTRightBack[i], 0, sizeof(double)* ( FFTCount + 1));
	}
	FFTTimerID = 0;
	CurrentID = 0;
	AudioList = NULL;
	IsMute = false;
	Volume = 0;
	ParentWnd = NULL;
}

CPCMAudio::CPCMAudio( int sample_count, int dft_average_count ){

	lpDSound = NULL;
	lpDSoundBufferPrimary = NULL;
	WndDSound = NULL;
	ZeroMemory(&WFE_Primary, sizeof(WAVEFORMATEX));
	FFTCount = sample_count;
	SampleLeft = new int[FFT_SAMPLE_COUNT];
	SampleRight = new int[FFT_SAMPLE_COUNT];
	FFTLeft = new double[FFTCount + 1];
	FFTRight = new double[FFTCount + 1];
	ReTempLeft = new double[FFT_SAMPLE_COUNT];
	ReTempRight = new double[FFT_SAMPLE_COUNT];
	ImTempLeft = new double[FFT_SAMPLE_COUNT];
	ImTempRight = new double[FFT_SAMPLE_COUNT];
	memset(SampleLeft, 0, sizeof(int)* FFT_SAMPLE_COUNT);
	memset(SampleRight, 0, sizeof(int)* FFT_SAMPLE_COUNT);
	memset(FFTLeft, 0, sizeof(double)* (FFTCount + 1));
	memset(FFTRight, 0, sizeof(double)* (FFTCount + 1));
	memset(ReTempLeft, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ReTempRight, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ImTempLeft, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ImTempRight, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	FFTLeftBack = (double **) new double*[FFT_AVE_COUNT + 1];
	FFTRightBack = (double **) new double*[FFT_AVE_COUNT + 1];
	for (int i = 0; i <= FFT_AVE_COUNT - 1; i++){
		FFTLeftBack[i] = (double *) new double[FFTCount + 1];
		FFTRightBack[i] = (double *) new double[FFTCount + 1];
		memset(FFTLeftBack[i], 0, sizeof(double)* (FFTCount + 1));
		memset(FFTRightBack[i], 0, sizeof(double)* (FFTCount + 1));
	}
	FFTTimerID = 0;
	CurrentID = 0;
	AudioList = NULL;
	IsMute = false;
	Volume = 0;
	ParentWnd = NULL;
}

CPCMAudio::~CPCMAudio(){

	::DestroyWindow(WndDSound);
	SAFE_RELEASE(lpDSoundBufferPrimary);
	SAFE_RELEASE(lpDSound);
	::timeKillEvent(FFTTimerID);
	delete[] SampleLeft;
	delete[] SampleRight;
	delete[] FFTLeft;
	delete[] FFTRight;
	delete[] ReTempLeft;
	delete[] ReTempRight;
	delete[] ImTempLeft;
	delete[] ImTempRight;
	for (int i = 0; i <= FFT_AVE_COUNT - 1; i++){
		delete[] FFTLeftBack[i];
		delete[] FFTRightBack[i];
	}
	delete[] FFTLeftBack;
	delete[] FFTRightBack;

	CoUninitialize();
}

bool CPCMAudio::Init( HWND parent_wnd, int start_id ){

	CoInitialize(NULL);

	ParentWnd = parent_wnd;
	StartID = start_id;

	CreateWnd();
	LRESULT result = DirectSoundCreate(NULL, &lpDSound, NULL);
	if (FAILED(result)){
		return false;
	}
	lpDSound->SetCooperativeLevel(WndDSound, DSSCL_PRIORITY );

	CreatePrimaryBuffer();
	AudioList = new CListA();

	if (FFTTimerID == 0)
		FFTTimerID = ::timeSetEvent(PCMAUDIO_FFT_UPDATE_MILLISEC, 1, (LPTIMECALLBACK)FFTUpdateCallback, (DWORD_PTR) this, TIME_PERIODIC);

	return true;
}

void __stdcall  CPCMAudio::FFTUpdateCallback(UINT timer_id, UINT msg, LPTIMECALLBACK user, DWORD_PTR data1, DWORD_PTR data2){

	CPCMAudio *audio = (CPCMAudio *)user;

	CListData *listdata = (CListData *)audio->AudioList->GetByID(audio->CurrentID);
	if (listdata == NULL)
		return;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		wave->GetSample(audio->SampleLeft, audio->SampleRight, FFT_SAMPLE_COUNT);
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		ogg->GetSample(audio->SampleLeft, audio->SampleRight, FFT_SAMPLE_COUNT);
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		mp3->GetSample(audio->SampleLeft, audio->SampleRight, FFT_SAMPLE_COUNT);
	}
	else
		return;

	//高速フーリエ変換
	for (int i = FFT_AVE_COUNT - 1; i >= 1; i--){
		for (int j = 0; j <= audio->FFTCount - 1; j++){
			audio->FFTLeftBack[i][j] = audio->FFTLeftBack[i-1][j];
			audio->FFTRightBack[i][j] = audio->FFTRightBack[i-1][j];
		}
	}
	for (int j = 0; j <= audio->FFTCount - 1; j++){
		audio->FFTLeftBack[0][j] = 0.0;
		audio->FFTRightBack[0][j] = 0.0;
	}
	for (int i = 0; i <= audio->FFTCount - 1; i++){
		audio->FFTLeft[i] = 0.0;
		audio->FFTRight[i] = 0.0;
	}

	int N = FFT_SAMPLE_COUNT;
	int power = 0;
	int n = N;
	double re_temp_l[FFT_SAMPLE_COUNT];
	double re_temp_r[FFT_SAMPLE_COUNT];
	double im_temp_l[FFT_SAMPLE_COUNT];
	double im_temp_r[FFT_SAMPLE_COUNT];
	for (int i = 0; i <= N - 1; i++){
		audio->ReTempLeft[i] = audio->SampleLeft[i];
		audio->ReTempRight[i] = audio->SampleRight[i];
		audio->ImTempLeft[i] = 0.0;
		audio->ImTempRight[i] = 0.0;
		re_temp_l[i] = 0.0;
		re_temp_r[i] = 0.0;
		im_temp_l[i] = 0.0;
		im_temp_r[i] = 0.0;
	}
	while (n > 1){
		n /= 2;
		power++;
	}
	
	int to = 0;
	int from = 0;
	int offset = 0;
	n = N;
	for (int i = 0; i < power - 1; i++){
		to = 0;
		offset = 0;
		while (to < N){
			from = 0;
			while (from < n){
				re_temp_l[to] = audio->ReTempLeft[from + offset];
				re_temp_r[to] = audio->ReTempRight[from + offset];
				to++;
				from += 2;
				if (from == n)
					from = 1;
			}
			offset += n;
		}
		for (int j = 0; j <= N - 1; j++){
			audio->ReTempLeft[j] = re_temp_l[j];
			audio->ReTempRight[j] = re_temp_r[j];
		}
		n /= 2;
	}

	double unit_angle = 2.0 * 3.14159265 / (double)N;
	int dft = 2;
	for (int i = 0; i < power - 1; i++){
		int num = N / dft;
		double step_angle = unit_angle * num;
		for (int j = 0; j <= num - 1; j++){
			double angle = 0.0;
			for (int k = 0; k <= dft - 1; k++){
				int to = j * dft + k;
				int from1 = 0;
				int from2 = 0;
				if (k < dft / 2){
					from1 = to;
					from2 = to + dft / 2;
				}
				else{
					from2 = to;
					from1 = to - dft / 2;
				}
				double re_l = audio->ReTempLeft[from2];
				double re_r = audio->ReTempRight[from2];
				double im_l = audio->ImTempLeft[from2];
				double im_r = audio->ImTempRight[from2];
				re_temp_l[to] = audio->ReTempLeft[from1] + re_l * cos(angle) + im_l * sin(angle);
				im_temp_l[to] = audio->ImTempLeft[from1] + im_l * cos(angle) - re_l * sin(angle);
				re_temp_r[to] = audio->ReTempRight[from1] + re_r * cos(angle) + im_r * sin(angle);
				im_temp_r[to] = audio->ImTempRight[from1] + im_r * cos(angle) - re_r * sin(angle);
				angle += step_angle;
			}
		}
		for (int j = 0; j <= N - 1; j++){
			audio->ReTempLeft[j] = re_temp_l[j];
			audio->ImTempLeft[j] = im_temp_l[j];
			audio->ReTempRight[j] = re_temp_r[j];
			audio->ImTempRight[j] = im_temp_r[j];
		}
		dft *= 2;
	}
	for (int i = 0; i <= N / 2 - 1; i++){
		int num = log(1000000.0f * (double)i / (double)N) * 2;
		audio->FFTLeftBack[0][num] += sqrt(pow(audio->ReTempLeft[i], 2) + pow(audio->ImTempLeft[i], 2)) / (7000.0 * ((double)i / 100.0 + 1));
		audio->FFTRightBack[0][num] += sqrt(pow(audio->ReTempRight[i], 2) + pow(audio->ImTempRight[i], 2)) / (7000.0 * ((double)i / 100.0 + 1));
	}

	for (int i = 0; i <= FFT_AVE_COUNT - 1; i++){
		for (int j = 0; j <= audio->FFTCount - 1; j++){
			audio->FFTLeft[j] += audio->FFTLeftBack[i][j] / ((double)(i + 1));
			audio->FFTRight[j] += audio->FFTRightBack[i][j] / ((double)(i + 1));
		}
	}
	for (int j = 0; j <= audio->FFTCount - 1; j++){
		audio->FFTLeft[j] /= (double)FFT_AVE_COUNT;
		audio->FFTRight[j] /= (double)FFT_AVE_COUNT;
	}
}

bool CPCMAudio::Open(wchar_t *filename, int id ){

	CAudioData *data = new CAudioData();

	wmemset(data->Path, 0, SIZE_CHAR_MAX);
	wmemset(data->FileName, 0, SIZE_CHAR_MAX);
	wcscpy_s(data->Path, SIZE_CHAR_MAX, filename);
	int num = wcslen(filename);
	while ((data->Path[num] != L'\\' && data->Path[num] != L'/') && num >= 1)
		num--;
	memcpy(data->FileName, &data->Path[num + 1], SIZE_CHAR_MAX);

	//拡張子確認
	wchar_t ext[8];
	wmemset(ext, 0, 8);
	wmemcpy(ext, &data->FileName[wcslen(data->FileName) - 3], 3);
	if (wcscmp(ext, L"wav") == 0 || wcscmp(ext, L"WAV") == 0){
		CWAVEAudio *wave = new CWAVEAudio();
		bool result = wave->Open(this, data->Path, ParentWnd, id, StartID );
		if (result == true){
			wave->SetVolume(wave->GetVolume(), IsMute);
			int num = AudioList->CurrentNum;
			data->AudioData = (void *)wave;
			data->AudioType = AUDIO_TYPE_WAVE;
			AudioList->InsTail((void *)data, id );
			AudioList->SetAt(num);
			CurrentID = id;
			return true;
		}
		delete wave;
		return false;
	}
	if (wcscmp(ext, L"ogg") == 0 || wcscmp(ext, L"OGG") == 0){
		COggAudio *ogg = new COggAudio();
		bool result = ogg->Open(this, data->Path, ParentWnd, id, StartID );
		if (result == true){
			ogg->SetVolume(ogg->GetVolume(), IsMute);
			int num = AudioList->CurrentNum;
			data->AudioData = (void *)ogg;
			data->AudioType = AUDIO_TYPE_OGG;
			AudioList->InsTail((void *)data, id );
			AudioList->SetAt(num);
			CurrentID = id;
			return true;
		}
		delete ogg;
		return false;
	}
	if (wcscmp(ext, L"mp3") == 0 || wcscmp(ext, L"MP3") == 0){
		CMP3Audio *mp3 = new CMP3Audio();
		bool result = mp3->Open(this, data->Path, ParentWnd, id, StartID );
		if (result == true){
			mp3->SetVolume(mp3->GetVolume(), IsMute);
			int num = AudioList->CurrentNum;
			data->AudioData = (void *)mp3;
			data->AudioType = AUDIO_TYPE_MP3;
			AudioList->InsTail((void *)data, id );
			AudioList->SetAt(num);
			CurrentID = id;
			return true;
		}
		delete mp3;
		return false;
	}

	return false;
}

bool CPCMAudio::Open(wchar_t *filename, int id, CAudioData *audio_data){

	wmemset(audio_data->Path, 0, SIZE_CHAR_MAX);
	wmemset(audio_data->FileName, 0, SIZE_CHAR_MAX);
	wcscpy_s(audio_data->Path, SIZE_CHAR_MAX, filename);
	int num = wcslen(filename);
	while ((audio_data->Path[num] != L'\\' && audio_data->Path[num] != L'/' ) && num >= 1)
		num--;
	memcpy(audio_data->FileName, &audio_data->Path[num + 1], SIZE_CHAR_MAX);

	//拡張子確認
	wchar_t ext[8];
	wmemset(ext, 0, 8);
	wmemcpy(ext, &audio_data->FileName[wcslen(audio_data->FileName) - 3], 3);
	if (wcscmp(ext, L"wav") == 0 || wcscmp(ext, L"WAV") == 0){
		CWAVEAudio *wave = new CWAVEAudio();
		bool result = wave->Open(this, audio_data->Path, ParentWnd, id, StartID );
		if (result == true){
			wave->SetVolume(wave->GetVolume(), IsMute);
			audio_data->AudioData = (void *)wave;
			audio_data->AudioType = AUDIO_TYPE_WAVE;
			CurrentID = id;
			return true;
		}
		delete wave;
		return false;
	}
	if (wcscmp(ext, L"ogg") == 0 || wcscmp(ext, L"OGG") == 0){
		COggAudio *ogg = new COggAudio();
		bool result = ogg->Open(this, audio_data->Path, ParentWnd, id, StartID );
		if (result == true){
			ogg->SetVolume(ogg->GetVolume(), IsMute);
			int num = AudioList->CurrentNum;
			audio_data->AudioData = (void *)ogg;
			audio_data->AudioType = AUDIO_TYPE_OGG;
			CurrentID = id;
			return true;
		}
		delete ogg;
		return false;
	}
	if (wcscmp(ext, L"mp3") == 0 || wcscmp(ext, L"MP3") == 0){
		CMP3Audio *mp3 = new CMP3Audio();
		bool result = mp3->Open(this, audio_data->Path, ParentWnd, id, StartID );
		if (result == true){
			mp3->SetVolume(mp3->GetVolume(), IsMute);
			audio_data->AudioData = (void *)mp3;
			audio_data->AudioType = AUDIO_TYPE_MP3;
			CurrentID = id;
			return true;
		}
		delete mp3;
		return false;
	}

	return false;
}

int CPCMAudio::GetStatus(int id){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->GetStatus();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->GetStatus();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->GetStatus();
	}

	return 0;
}

bool CPCMAudio::Play(int id){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		wave->SetVolume(wave->GetVolume(), IsMute);
		wave->Play();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		ogg->SetVolume(ogg->GetVolume(), IsMute);
		ogg->Play();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		mp3->SetVolume(mp3->GetVolume(), IsMute);
		mp3->Play();
	}
	CurrentID = id;

	return true;
}

bool CPCMAudio::Mute(bool do_mute){

	IsMute = do_mute;
	if (do_mute == true){
		for (int i = 0; i <= AudioList->ListSize - 1; i++){
			CListData *list_data = (CListData *)AudioList->GetAt(i + 1);
			if (list_data != NULL){
				CAudioData *audio_data = (CAudioData *)list_data->Data;
				if (audio_data->AudioType == AUDIO_TYPE_WAVE){
					CWAVEAudio *wave = (CWAVEAudio *)audio_data->AudioData;
					wave->Mute(true);
				}
				if (audio_data->AudioType == AUDIO_TYPE_OGG){
					COggAudio *ogg = (COggAudio *)audio_data->AudioData;
					ogg->Mute(true);
				}
				if (audio_data->AudioType == AUDIO_TYPE_MP3){
					CMP3Audio *mp3 = (CMP3Audio *)audio_data->AudioData;
					mp3->Mute(true);
				}
			}
		}
	}
	else
	for (int i = 0; i <= AudioList->ListSize - 1; i++){
		CListData *list_data = (CListData *)AudioList->GetAt(i + 1);
		if (list_data != NULL){
			CAudioData *audio_data = (CAudioData *)list_data->Data;
			if (audio_data->AudioType == AUDIO_TYPE_WAVE){
				CWAVEAudio *wave = (CWAVEAudio *)audio_data->AudioData;
				wave->Mute(false);
				wave->SetVolume(wave->GetVolume(), false);
			}
			if (audio_data->AudioType == AUDIO_TYPE_OGG){
				COggAudio *ogg = (COggAudio *)audio_data->AudioData;
				ogg->Mute(false);
				ogg->SetVolume(ogg->GetVolume(), false);
			}
			if (audio_data->AudioType == AUDIO_TYPE_MP3){
				CMP3Audio *mp3 = (CMP3Audio *)audio_data->AudioData;
				mp3->Mute(false);
				mp3->SetVolume(mp3->GetVolume(), false);
			}
		}
	}

	return true;
}

bool CPCMAudio::Stop(int id ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		wave->Stop();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		ogg->Stop();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		mp3->Stop();
	}
	CurrentID = id;

	return true;
}

bool CPCMAudio::Pause(int id ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		wave->Pause();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		ogg->Pause();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		mp3->Pause();
	}
	CurrentID = id;

	return true;
}

bool CPCMAudio::Seek(int id, double pos ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		wave->Seek( pos );
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		ogg->Seek( pos );
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		mp3->Seek( pos );
	}
	CurrentID = id;

	return true;
}

double CPCMAudio::GetPlayPos(int id ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *) listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		return wave->GetPlayPos();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		return ogg->GetPlayPos();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		return mp3->GetPlayPos();
	}
	CurrentID = id;

	return 0;
}

double CPCMAudio::GetVolume(int id){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->GetVolume();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->GetVolume();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->GetVolume();
	}

	return 0;
}

bool CPCMAudio::SetVolume(int id, double volume){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->SetVolume(volume, IsMute);
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->SetVolume(volume, IsMute );
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->SetVolume(volume, IsMute);
	}

	return false;
}

bool CPCMAudio::SetLoop(int id, bool loop ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->SetLoop(loop);
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->SetLoop(loop);
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->SetLoop(loop);
	}

	return false;
}

bool CPCMAudio::GetLoop(int id){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->GetLoop();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->GetLoop();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->GetLoop();
	}

	return false;
}

bool CPCMAudio::SetPlayOnce(int id, bool play_once ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return false;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		return wave->SetPlayOnce( play_once );
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		return ogg->SetPlayOnce( play_once );
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		return mp3->SetPlayOnce( play_once );
	}

	return false;
}

bool CPCMAudio::GetPlayOnce(int id){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return false;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		return wave->GetPlayOnce();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		return ogg->GetPlayOnce();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		return mp3->GetPlayOnce();
	}

	return false;
}

int CPCMAudio::GetID(int num){

	if (num <= 0 || num > AudioList->ListSize)
		return -1;

	CListData *list_data = (CListData *)AudioList->GetAt(num);
	CAudioData *audio_data = (CAudioData *)list_data->Data;
	if (audio_data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)audio_data->AudioData;
		return mp3->GetID();
	}
	if (audio_data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)audio_data->AudioData;
		return ogg->GetID();
	}
	if (audio_data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)audio_data->AudioData;
		return wave->GetID();
	}

	return -1;
}

bool CPCMAudio::Close(int id){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	int current_num = AudioList->CurrentNum;
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;
	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		wave->Close();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		ogg->Close();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		mp3->Close();
	}
	AudioList->DeleteByID(id);
	if (current_num > AudioList->ListSize)
		current_num--;
	CurrentID = GetID(current_num);

	Sleep(50);

	//FFTバッファをクリア
	memset(FFTLeft, 0, sizeof(double)* FFTCount);
	memset(FFTRight, 0, sizeof(double)* FFTCount);
	memset(ReTempLeft, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ReTempRight, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ImTempLeft, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	memset(ImTempRight, 0, sizeof(double)* FFT_SAMPLE_COUNT);
	for (int i = 0; i <= FFT_AVE_COUNT - 1; i++){
		memset(FFTLeftBack[i], 0, sizeof(double)* FFTCount);
		memset(FFTRightBack[i], 0, sizeof(double)* FFTCount);
	}

	return true;
}

int CPCMAudio::GetTotalTime( int id ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->GetTotalTime();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->GetTotalTime();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->GetTotalTime();
	}

	return 0;
}

double CPCMAudio::GetPlayingTime( int id ){

	CListData *listdata = (CListData *)AudioList->GetByID(id);
	if (listdata == NULL)
		return 0;
	CAudioData *data = (CAudioData *)listdata->Data;

	if (data->AudioType == AUDIO_TYPE_WAVE){
		CWAVEAudio *wave = (CWAVEAudio *)data->AudioData;
		CurrentID = id;
		return wave->GetPlayingTime();
	}
	else if (data->AudioType == AUDIO_TYPE_OGG){
		COggAudio *ogg = (COggAudio *)data->AudioData;
		CurrentID = id;
		return ogg->GetPlayingTime();
	}
	else if (data->AudioType == AUDIO_TYPE_MP3){
		CMP3Audio *mp3 = (CMP3Audio *)data->AudioData;
		CurrentID = id;
		return mp3->GetPlayingTime();
	}

	return 0;
}

bool CPCMAudio::CreateWnd(){

	WNDCLASSEX wcx;
	memset(&wcx, 0, sizeof(WNDCLASSEX));
	wcx.cbSize = sizeof(WNDCLASSEX);
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.hInstance = NULL;
	wcx.hIcon = NULL;
	wcx.lpszMenuName = NULL;
	wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcx.lpfnWndProc = ::DefWindowProc;
	wcx.lpszClassName = L"ChaSoundWindow";
	RegisterClassEx(&wcx);

	WndDSound = CreateWindowEx(WS_EX_LEFT, L"ChaSoundWindow", L"Sound", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL);

	return true;
}

bool CPCMAudio::CreatePrimaryBuffer(){

	HRESULT		result;

	DSBUFFERDESC	desc;
	ZeroMemory(&desc, sizeof(DSBUFFERDESC));
	desc.dwSize = sizeof(DSBUFFERDESC);
	desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
	desc.dwBufferBytes = 0;
	desc.lpwfxFormat = NULL;
	result = lpDSound->CreateSoundBuffer(&desc, &lpDSoundBufferPrimary, NULL);

	WFE_Primary.cbSize = sizeof(WAVEFORMATEX);
	WFE_Primary.wFormatTag = WAVE_FORMAT_PCM;
	WFE_Primary.nChannels = 2;
	WFE_Primary.nSamplesPerSec = 44100;
	WFE_Primary.wBitsPerSample = 16;
	WFE_Primary.nBlockAlign = WFE_Primary.nChannels * WFE_Primary.wBitsPerSample / 8;
	WFE_Primary.nAvgBytesPerSec = WFE_Primary.nSamplesPerSec * WFE_Primary.nBlockAlign;
	result = lpDSoundBufferPrimary->SetFormat(&WFE_Primary);

	return true;
}

