/***************************************************************/
//
//
//		DirectX	[sound.cpp]
//
//												Author	kazuki tanaka
//												Date	2016 06/15
/*---------------------------------------------------------------
■Update : 2016/06/15
			sound.cppの作成

■Update : 2016/06/16
			サウンドデバイス以下
			サウンドの設定
			サウンドの吸い出し処理
			追加

■Update : 2016/08/07
            ボリュームの変更
			Play,Stop関数の実装

/*---------------------------------------------------------------
	インクルードファイル
---------------------------------------------------------------*/
#include "sound.h"

#include "input.h"
#include "game_equation.h"

/*---------------------------------------------------------------
	マクロ定義
---------------------------------------------------------------*/

/*
// Audio_number の定義
typedef enum{

	AUDIO_TITLE = 0,

	MAX_AUDIO,

}AUDIO_NUMBER;

// SoundEffect_number の定義
typedef enum{

	SE_TITLE = 0,

	MAX_AUDIO,

}SE_NUMBER;
*/

/*---------------------------------------------------------------
	定数定義
---------------------------------------------------------------*/

#define AUDIO_MAX ( 3 )			// 最大bgm数
#define SE_MAX ( 6 )			// 最大SE数

#define START_VOLUME ( -1000 )	// 初期ボリューム値

// bgmファイルネーム定数
const char* AUDIO_FILE_NAME [ AUDIO_MAX ] = {

	// TITLE 
	"data\\AUDIO\\bgm\\title.wav",
	// GAME
	"data\\AUDIO\\bgm\\game.wav",
	// RESULT
	"data\\AUDIO\\bgm\\result.wav",

};

//  soundeffectファイルネーム定数
const char* SE_FILE_NAME [ SE_MAX ] = {

	// TITLE
	"data\\AUDIO\\sound_effect\\enter.wav",
	// GAME
	"data\\AUDIO\\sound_effect\\delet.wav",
	"data\\AUDIO\\sound_effect\\frameenter.wav",
	"data\\AUDIO\\sound_effect\\goal.wav",
	// RESULT
	"data\\AUDIO\\sound_effect\\seremony.wav",
	"data\\AUDIO\\sound_effect\\failed.wav",

};

/*---------------------------------------------------------------
	プロトタイプ宣言
---------------------------------------------------------------*/

HRESULT CreatePrimaryBuffer( void );			// プライマリバッファの作成
HRESULT CreateSoundBuffer(						// セカンダリバッファの作成
	LPDIRECTSOUNDBUFFER *dsb,					// >> サウンドバッファのポインタ
	const char *file );							// >> ファイル名( ファイルネーム定数 )

/*----------------------------------------------------------------
	グローバル変数
----------------------------------------------------------------*/

// グローバル変数
LPDIRECTSOUND8      lpDS      = nullptr;					// DirectSound8のポインタ
LPDIRECTSOUNDBUFFER lpPrimary = nullptr;					// プライマリサウンドバッファ
LPDIRECTSOUNDBUFFER lpSecondary[ AUDIO_MAX ] = { nullptr };	// セカンダリサウンドバッファ
LPDIRECTSOUNDBUFFER lpSoundEffectBuf[ SE_MAX ] = { nullptr };// セカンダリサウンドバッファ
LONG volume = START_VOLUME;									// ボリューム値


#if 0

IDirectSound8 *pDS8;							//サウンドデバイスのポインタ
DSBUFFERDESC DSBufferDesc;
IDirectSoundBuffer *ptmpBuf = nullptr;
IDirectSoundBuffer8 *pDSBuffer=nullptr;

LPDIRECTSOUNDBUFFER pDsb = NULL;
  HRESULT hr; 

//サウンドの初期化
HRESULT InitSound( HWND hWnd )
{

	char *pData;			//波形データ格納用バッファ

	//サウンドデバイス作成
	DirectSoundCreate8(NULL, &pDS8, NULL);

	//協調レベル設定
	pDS8->SetCooperativeLevel( hWnd, DSSCL_NORMAL );
	  // WAV フォーマットの構造体をセットアップする。

	//WAVEFORMATDISC構造体
	WAVEFORMATEX wFmt={};

	memset(&wFmt, 0, sizeof(WAVEFORMATEX)); 
	wFmt.wFormatTag = WAVE_FORMAT_PCM;
	wFmt.nChannels = 2;
	wFmt.nSamplesPerSec = 44100;
	wFmt.wBitsPerSample = 16;
	wFmt.nBlockAlign = wFmt.nChannels;
	wFmt.nAvgBytesPerSec = wFmt.nSamplesPerSec * wFmt.nBlockAlign;
	wFmt.cbSize = 0;
 
  // DSBUFFERDESC 構造体をセットアップする。
 
  memset(&DSBufferDesc, 0, sizeof(DSBUFFERDESC)); 
  DSBufferDesc.dwSize = sizeof(DSBUFFERDESC); 
  DSBufferDesc.dwFlags = 
    DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; 
  DSBufferDesc.dwBufferBytes = 3 * wFmt.nAvgBytesPerSec; 
  DSBufferDesc.lpwfxFormat = &wFmt; 
 
  // バッファを作成する。
 
  hr = pDS8->CreateSoundBuffer(&DSBufferDesc, &pDsb, NULL); 
  if (SUCCEEDED(hr)) 
  { 
     hr = pDsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*) ptmpBuf);
     pDsb->Release();
  } 
	//セカンダリバッファの作成
	//IDirectSoundBuffer8 *pDSBuffer;
	//pDS8 ->CreateSoundBuffer( &DSBufferDesc, &ptmpBuf, NULL );
	//ptmpBuf ->QueryInterface( IID_IDirectSoundBuffer8 ,(void**)&pDSBuffer);
	//ptmpBuf->Release( );

	//ファイルオープン
	HMMIO hMmio = NULL;
	MMIOINFO mmioInfo;

	//waveファイルオープン
	memset( &mmioInfo, 0, sizeof(MMIOINFO) );
	hMmio = mmioOpen( "lastbgm.wav", &mmioInfo, MMIO_READ );
	if( !hMmio ){
		MessageBox( NULL, "WaveFILEのオープンに失敗しました!!", "file open ERROR!!", MB_OK );
		return E_FAIL;
	}
	else{
	
		//RIFFチャンクサーチ
		MMRESULT mmRes;
		MMCKINFO riffChunk;

		riffChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
		mmRes = mmioDescend( hMmio, &riffChunk, NULL, MMIO_FINDRIFF );
		if( mmRes != MMSYSERR_NOERROR ){

			mmioClose( hMmio, 0 );
			#ifdef _DEBUG
			MessageBox( NULL, "RIFFチャンクのサーチに失敗しました!!", "RIFFチャンクサーチERROR", MB_OK );
			#endif
			return E_FAIL;
		}

		//フォーマットチャンクサーチ
		MMCKINFO formatChunk;
		
		formatChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
		mmRes = mmioDescend( hMmio, &formatChunk, &riffChunk, MMIO_FINDCHUNK );
		if( mmRes != MMSYSERR_NOERROR ){

			mmioClose( hMmio, 0 );
			#ifdef _DEBUG
			MessageBox( NULL, "フォーマットチャンクのサーチに失敗しました!!", "fmtチャンクサーチERROR", MB_OK );
			#endif
			return E_FAIL;
		}

		//WAVEFORMATEX構造体格納
		DWORD fmsize = formatChunk.cksize;
		DWORD size = mmioRead( hMmio, (HPSTR)&wFmt, fmsize );
		if( size != fmsize ){

			mmioClose( hMmio, 0 );
			#ifdef _DEBUG
			MessageBox( NULL, "フォーマットチャンクのサーチに失敗しました!!", "fmtチャンクサーチERROR", MB_OK );
			#endif
			return E_FAIL;


		}

		//fmt->RIFFチャンクへ移動
		mmioAscend( hMmio, &formatChunk, 0 );


		//データチャンクサーチ
		MMCKINFO dataChunk;
		dataChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
		mmRes = mmioDescend( hMmio, &dataChunk, &riffChunk, MMIO_FINDCHUNK );
		if( mmRes != MMSYSERR_NOERROR ){

			mmioClose( hMmio, 0 );
			#ifdef _DEBUG
			MessageBox( NULL, "データチャンクのサーチに失敗しました!!", "データチャンクサーチERROR", MB_OK );
			#endif
			return E_FAIL;
		}
	
		//サウンドデータ格納
		pData = new char[ dataChunk.cksize ];
		size = mmioRead( hMmio, (HPSTR)pData, dataChunk.cksize );
		if( size != dataChunk.cksize ){
			
			delete[] pData;
			#ifdef _DEBUG
			MessageBox( NULL, "サウンドデータの格納に失敗しました!!", "サウンドデータERROR", MB_OK );
			#endif
			return E_FAIL;
		}

		//ファイルクローズ
		mmioClose( hMmio, 0 );

	}

	/*
	//DSBUFFERDESC構造体
	DSBufferDesc.dwSize = sizeof(DSBUFFERDESC);
	DSBufferDesc.dwFlags = 0;
	DSBufferDesc.dwBufferBytes =
			wFmt.nSamplesPerSec *
			wFmt.wBitsPerSample *
			wFmt.nChannels *
			m_dwTime;
	DSBufferDesc.dwReserved = 0;
	DSBufferDesc.lpwfxFormat = &wFmt;
	DSBufferDesc.guid3DAlgorithm = GUID_NULL;
	*/

	/* メモリロック */
	//セカンダリバッファにWaveデータ書き込み
	LPVOID lpvWrite = 0;
	DWORD  dwLength = 0;
	if( DS_OK == ptmpBuf -> Lock( 0, 0, &lpvWrite, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER ) ){
		
		memcpy( lpvWrite, pData, dwLength );
		pDSBuffer ->Unlock( lpvWrite, dwLength, NULL, 0 );
	}


	delete[] pData;

	return S_OK;

}
//サウンドの終了処理
void UninitSound( void )
{

	//サウンドデバイスポインタの解放
	SAFE_RELEASE( pDS8 )

}

#else

// サウンドデバイスの初期化
HRESULT InitWaveSound( HWND hWnd )
{
    HRESULT ret;

    // COMの初期化
    CoInitialize( NULL );

    // DirectSound8を作成
    ret = DirectSoundCreate8( NULL,&lpDS,NULL );
    if( FAILED(ret) ) {
        return E_FAIL;
    }

    // 協調モード
    ret = lpDS->SetCooperativeLevel( hWnd, (DSSCL_EXCLUSIVE | DSSCL_PRIORITY) );
    if( FAILED(ret) ) {
        return E_FAIL;
    }


	// プライマリバッファの設定
	CreatePrimaryBuffer( );

	// セカンドバッファの作成
	for( int index = 0; index < AUDIO_MAX; index++ ){

		CreateSoundBuffer( &lpSecondary[ index ],     AUDIO_FILE_NAME[ index ] );
	}
	
	for( int index = 0; index < SE_MAX ; index++ ){

		CreateSoundBuffer( &lpSoundEffectBuf[ index ], SE_FILE_NAME[ index ] );
	}

	/*
	CreateSoundBuffer( lpSecondary,     AUDIO_FILE_NAME[ 0 ] );
	CreateSoundBuffer( &lpSecondary[ 1 ],     AUDIO_FILE_NAME[ 1 ] );
	CreateSoundBuffer( &lpSecondary[ 2 ],     AUDIO_FILE_NAME[ 2 ] );
	CreateSoundBuffer( &lpSecondary[ 3 ],     AUDIO_FILE_NAME[ 3 ] );
	CreateSoundBuffer( &lpSecondary[ 4 ],     AUDIO_FILE_NAME[ 4 ] );
	CreateSoundBuffer( &lpSecondary[ 5 ],     AUDIO_FILE_NAME[ 5 ] );
	CreateSoundBuffer( &lpSecondary[ 6 ],     AUDIO_FILE_NAME[ 6 ] );
	CreateSoundBuffer( &lpSecondary[ 7 ],     AUDIO_FILE_NAME[ 7 ] );
	*/

	return S_OK;

}

// サウンドデバイスの開放処理
void UninitSound( void )
{

	// -- セカンダリバッファの解放処理 --

	// Audio SecondaryBuffer
	for( int index = 0 ; index < AUDIO_MAX ; index++ ){
		
		SAFE_RELEASE( lpSecondary[ index ] )
	}

	// Sound effect SecondaryBuffer
	for( int index = 0 ; index < SE_MAX ; index++ ){
		
		SAFE_RELEASE( lpSoundEffectBuf[ index ] )
	}

	// プライマリバッファの解放処理
	SAFE_RELEASE( lpPrimary )

	// サウンドデバイスの解放処理
	SAFE_RELEASE( lpDS )


    // COMの終了
    CoUninitialize( );
}

// プライマリサウンドバッファの作成
HRESULT CreatePrimaryBuffer( void )
{


    HRESULT ret;
    WAVEFORMATEX wf;

    // プライマリサウンドバッファの作成
    DSBUFFERDESC dsdesc;
    ZeroMemory( &dsdesc,sizeof(DSBUFFERDESC) );
    dsdesc.dwSize           = sizeof( DSBUFFERDESC );
    dsdesc.dwFlags          = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN;
    dsdesc.dwBufferBytes    = 0;
    dsdesc.lpwfxFormat      = NULL;
    ret = lpDS->CreateSoundBuffer( &dsdesc,&lpPrimary,NULL );
    if( FAILED(ret) ) {
        return E_FAIL;
    }

    // プライマリバッファのステータスを決定
    wf.cbSize = sizeof( WAVEFORMATEX );
    wf.wFormatTag           = WAVE_FORMAT_PCM;
    wf.nChannels            = 2;
    wf.nSamplesPerSec       = 44100;
    wf.wBitsPerSample       = 16;
    wf.nBlockAlign          = wf.nChannels * wf.wBitsPerSample / 8;
    wf.nAvgBytesPerSec      = wf.nSamplesPerSec * wf.nBlockAlign;
    ret = lpPrimary->SetFormat( &wf );
    if( FAILED(ret) ) {
        return E_FAIL;
    }

    return S_OK;
}

// セカンダリバッファの作成処理
HRESULT CreateSoundBuffer( LPDIRECTSOUNDBUFFER *dsb, const char *file )
{

    HRESULT ret;
    MMCKINFO mSrcWaveFile;
    MMCKINFO mSrcWaveFmt;
    MMCKINFO mSrcWaveData;
    LPWAVEFORMATEX wf;


    // WAVファイルをロード
    HMMIO hSrc;
    hSrc = mmioOpen( (LPSTR)file,NULL,MMIO_ALLOCBUF|MMIO_READ|MMIO_COMPAT );
    if( !hSrc ) {
		
		MessageBox( NULL, " audio file error!! ", " AUDIO FILE ERROR ", MB_OK );
        return E_FAIL;
    }

    // 'WAVE'チャンクチェック
    ZeroMemory( &mSrcWaveFile,sizeof(mSrcWaveFile) );
    ret = mmioDescend( hSrc,&mSrcWaveFile,NULL,MMIO_FINDRIFF );
    if( mSrcWaveFile.fccType!=mmioFOURCC('W','A','V','E') ) {
        mmioClose( hSrc,0 );
        return E_FAIL;
    }

    // 'fmt 'チャンクチェック
    ZeroMemory( &mSrcWaveFmt,sizeof(mSrcWaveFmt) );
    ret = mmioDescend( hSrc, &mSrcWaveFmt, &mSrcWaveFile, MMIO_FINDCHUNK );
    if( mSrcWaveFmt.ckid!=mmioFOURCC('f','m','t',' ') ) {
        mmioClose( hSrc, 0 );
        return E_FAIL;
    }

    // ヘッダサイズの計算
    int iSrcHeaderSize = mSrcWaveFmt.cksize;
    if( iSrcHeaderSize<sizeof(WAVEFORMATEX) )
        iSrcHeaderSize=sizeof(WAVEFORMATEX);

    // ヘッダメモリ確保
    wf = (LPWAVEFORMATEX)malloc( iSrcHeaderSize );
    if( !wf ) {
        mmioClose( hSrc,0 );
        return E_FAIL;
    }
    ZeroMemory( wf, iSrcHeaderSize );

    // WAVEフォーマットのロード
    ret = mmioRead( hSrc,(char*)wf, mSrcWaveFmt.cksize );
    if( FAILED(ret) ) {
        free( wf );
        mmioClose( hSrc, 0 );
        return E_FAIL;
    }


    // fmtチャンクに戻る
    mmioAscend( hSrc, &mSrcWaveFmt, 0 );

    // dataチャンクを探す
    while(1) {

        // 検索
        ret = mmioDescend( hSrc, &mSrcWaveData, &mSrcWaveFile, 0 );
        if( FAILED(ret) ) {
            free( wf );
            mmioClose( hSrc, 0 );
            return E_FAIL;
        }
        if( mSrcWaveData.ckid==mmioStringToFOURCCA( "data", 0 ) )
            break;
        // 次のチャンクへ
        ret = mmioAscend( hSrc, &mSrcWaveData, 0 );

    }


    // サウンドバッファの作成
    DSBUFFERDESC dsdesc;
    ZeroMemory( &dsdesc,sizeof(DSBUFFERDESC) );
    dsdesc.dwSize = sizeof( DSBUFFERDESC );
    dsdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_LOCDEFER | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN;
    dsdesc.dwBufferBytes = mSrcWaveData.cksize;
    dsdesc.lpwfxFormat = wf;
    dsdesc.guid3DAlgorithm = DS3DALG_DEFAULT;
    ret = lpDS->CreateSoundBuffer( &dsdesc, dsb,NULL );
    if( FAILED(ret) ) {
        free( wf );
        mmioClose( hSrc, 0 );
        return E_FAIL;
    }

    // ロック開始
    LPVOID pMem1,pMem2;
    DWORD dwSize1,dwSize2;
    ret = (*dsb)->Lock( 0, mSrcWaveData.cksize, &pMem1, &dwSize1, &pMem2, &dwSize2, 0 );
    if( FAILED(ret) ) {
        free( wf );
        mmioClose( hSrc, 0 );
        return E_FAIL;
    }

    // データ書き込み
    mmioRead( hSrc, (char*)pMem1, dwSize1 );
    mmioRead( hSrc, (char*)pMem2, dwSize2 );

    // ロック解除
    (*dsb)->Unlock( pMem1, dwSize1, pMem2, dwSize2 );

    // ヘッダ用メモリを開放
    free( wf );

    // WAVEを閉じる
    mmioClose( hSrc, 0 );

    return S_OK;

}

// サウンドバッファの作成( Audio )
HRESULT SetAudio( int index )
{

	HRESULT hResult;

	// サウンドバッファの作成
	hResult = CreateSoundBuffer( &lpSecondary[ index ],     AUDIO_FILE_NAME[ index ] );

	if( FAILED( hResult ) ){

		MessageBox( NULL, "create Audio error!!" , " Sound Error!! " , MB_OK );
		SAFE_RELEASE( lpSecondary[ index ] )
		
		return E_FAIL;
	}

	return S_OK;

}

// サウンドバッファの消去( Audio )
void DeleteAudio( int index )
{

	SAFE_RELEASE( lpSecondary[ index ] )

}

// サウンドバッファの作成( Sound effect )
HRESULT SetSoundEffect( int index )
{

	HRESULT hResult;

	// サウンドバッファの作成
	hResult = CreateSoundBuffer( &lpSoundEffectBuf[ index ],     AUDIO_FILE_NAME[ index ] );

	if( FAILED( hResult ) ){

		MessageBox( NULL, "create SE error!!" , " Sound Error!! " , MB_OK );
		SAFE_RELEASE( lpSoundEffectBuf[ index ] )	
		
		return E_FAIL;
	}

	return S_OK;

}

// サウンドバッファの消去( Sound effect )
void DeleteSoundEffect( int index )
{

	SAFE_RELEASE( lpSoundEffectBuf[ index ] )

}

// サウンドの再生
void PlaySound( int bufNumber , bool loopflag )
{

	// 現在のボリュームに設定
	SetVolume( bufNumber, 0 );

	// waveの再生
	lpSecondary[ bufNumber ] ->Play( 0, 0, loopflag );

}

// サウンドの停止
void StopSound( int bufNumber )
{

	// waveファイルの停止
	lpSecondary[ bufNumber ] ->Stop( );

	// 再生位置を初期化
	lpSecondary[ bufNumber ] ->SetCurrentPosition( 0 );

}

// サウンドエフェクトの再生
void PlayOneShotSoundEffect( int bufNumber )
{

	// 現在のボリュームに設定
	SetVolume( bufNumber, 0 );

	// SEの再生
	lpSoundEffectBuf[ bufNumber ] ->Play( 0, 0, 0 );

}

// サウンドエフェクトの停止
void StopOneShotSoundEffect( int bufNumber )
{

	// waveファイルの停止
	lpSoundEffectBuf[ bufNumber ] ->Stop( );

	// 再生位置を初期化
	lpSoundEffectBuf[ bufNumber ] ->SetCurrentPosition( 0 );

}

// ボリュームの調整
void SetVolume( int bufNumber, LONG value )
{

	// ボリュームの更新
	volume += value;

	// 最大最小値の設定
	volume = LIMIT_MAX( volume,    0   );
	volume = LIMIT_MIM( volume, -10000 );

	// ボリュームのセット
	lpSecondary[ bufNumber ] ->SetVolume( volume );

}

// ボリュームの変更
void ControlVolume( int bufNumber )
{

	// ボリュームの変更
	if( GetKeyboardPress( DIK_UP ) ){
	
		SetVolume( bufNumber, 10 );
	}
	else if( GetKeyboardPress( DIK_DOWN ) ){
	
		SetVolume( bufNumber, -10 );
	}

}



#endif 

