/***************************************************************/
//
//
//		DirectX	[ directsound.cpp ]
//
//											Author	kazuki tanaka
//											Date	2017 6/16
/*---------------------------------------------------------------
■Update : 2017/6/16
			directsound.cppの作成

/*---------------------------------------------------------------
	Include File
---------------------------------------------------------------*/

#include "directsound.h"

#include "mathematics.h"

#pragma comment ( lib , "dsound.lib" )

/*---------------------------------------------------------------
	Macro Difinition
---------------------------------------------------------------*/

#define START_VOLUME ( -1000 )	// Start Volume Value

/*----------------------------------------------------------------
	static member variable Initialize 
----------------------------------------------------------------*/

LPDIRECTSOUND8      DirectSound::lpDS = nullptr;		
LPDIRECTSOUNDBUFFER DirectSound::lpPrimary = nullptr;	



// DirectSound Constructor
DirectSound::DirectSound( const std::string& filename ,bool loop = false )
	: lpSecondary(nullptr)
	, loop(loop)
	, volume(START_VOLUME)
{

	HRESULT hRes;

	// Member Clear Process
	if(!lpPrimary){
		 hRes = CreatePrimaryBuffer();
	}

	hRes = CreateSoundBuffer( filename.data() );
	if( FAILED(hRes) ){
		delete this;
	}
	

}

// DirectSound Destructor
DirectSound::~DirectSound( )
{

	// Do Nothing!!

}

// DirectSound Create Instance 
DirectSound* DirectSound::Create( const std::string& filename ,bool loop = false )
{

	// Create Class Instance
	return new DirectSound( filename, loop );

}

// DirectSound Initialize
void DirectSound::Init( void )
{

	// Initialize Process


}

// DirectSound Uninitialize
void DirectSound::Uninit( void )
{

	// Uninitialize Process


}

// DirectSound Update
void DirectSound::Update( void )
{

	// Update Process


}

// サウンドの再生
void DirectSound::Play( void )
{

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

	// waveの再生
	lpSecondary ->Play( 0, 0, loop );

}

// サウンドの停止
void DirectSound::Stop( void )
{

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

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

}

// ボリュームの調整
void DirectSound::SetVolume( const LONG& value )
{

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

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

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

}

// プライマリサウンドバッファの作成
HRESULT DirectSound::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 DirectSound::CreateSoundBuffer( 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, &lpSecondary,NULL );
    if( FAILED(ret) ) {
        free( wf );
        mmioClose( hSrc, 0 );
        return E_FAIL;
    }

    // ロック開始
    LPVOID pMem1,pMem2;
    DWORD dwSize1,dwSize2;
    ret = (lpSecondary)->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 );

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

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

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

    return S_OK;

}









