#include"CSoundDecoderWave.h"
#include"../../auxiliary/CString.h"
#include"../../auxiliary/CAssert.h"
#include"../../auxiliary/CWarning.h"
#include"../../Auxiliary/CString.h"


namespace Maid
{
	/*!
	 *	\class	CSoundDecoderWave CSoundDecoderWave.h
	 *	\brief	WAVE ファイルエンコーダー
	 */
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! コンストラクタ
/*!
 *
 */
CSoundDecoderWave::CSoundDecoderWave()
{
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デストラクタ
/*!
 *
 */
CSoundDecoderWave::~CSoundDecoderWave()
{
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ファイルのロード
/*!
 *	引数などは ISoundDecoder::Open を参照すること
 */
MRESULT CSoundDecoderWave::Open( const MySTL::wstring& FileName )
{
	Close();

	MRESULT ret;
	ret = m_hFile.Open( FileName );
	if( ret!=MRESULT_OK ) { DEN_WARNING( 0, "%s の読み込みに失敗", CString::ConvertUTF16toSJIS(FileName).c_str() ); return 1; }

	MySTL::vector<uint08> tmp(2048);	//	これで十分でしょう
	m_hFile.Read( &(tmp[0]), tmp.size() );

	if( (*(uint32*)(&tmp[0]))!=Str2Binary32('R','I','F','F') ||
		(*(uint32*)(&tmp[8]))!=Str2Binary32('W','A','V','E')  ) { DEN_WARNING( 0, "%s はwaveファイルでありません", CString::ConvertUTF16toSJIS(FileName).c_str() ); return 2; }

	uint32 sample;
	{
		uint08*	pNow = &(tmp[12]);
		uint32	dwOffset = 12;

		bool bfmt = false;
		bool bdata= false;
		while( true )
		{
			if( bfmt && bdata ) { break; }

			uint32 type   = *((uint32*)pNow);
			uint32 length = *((uint32*)(pNow+4));

			if( type==Str2Binary32('f','m','t',' ') )
			{
				uint08* pData  = pNow+8;
				memcpy( &m_WaveFormat, pData, sizeof(m_WaveFormat) );
				bfmt = true;
			}else if( type==Str2Binary32('d','a','t','a') )
			{
				sample   = length;
				m_BeginOffset = dwOffset+8;
				bdata = true;
			}

			pNow += length+8;
			dwOffset += length+8;
		}

	}

	m_SampleLength = sample / GetBytePerSample();
	m_hFile.Seek( m_BeginOffset, IFileRead::BEGIN );

	return MRESULT_OK;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デコードする
/*!
 *	引数などは ISoundDecoder::Read を参照すること
 */
uint32 CSoundDecoderWave::Read( void* pDst, uint32 dwSize )
{
	const uint32 dat = GetBytePerSample();
	const uint32 pos = GetPosition();
	const uint32 len = GetLength();

	uint32 Red;

	if( pos+dwSize < len )	{ Red = dwSize; }
	else	
	{
		Red = len - pos; 
	}

	return m_hFile.Read( pDst, Red*dat ) /dat ;

}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デコード開始位置を移動する
/*!
 *	引数などは ISoundDecoder::SetPosition を参照すること
 */
void CSoundDecoderWave::SetPosition( sint32 Offset, POSITION ePos )
{
	const uint32 dat = GetBytePerSample();
	IFileRead::POSITION FilePos;

	switch( ePos )
	{
	case ISoundDecoder::BEGIN:	{ FilePos = IFileRead::BEGIN; }break;
	case ISoundDecoder::END:	{ FilePos = IFileRead::END; }break;
	case ISoundDecoder::CURRENT:{ FilePos = IFileRead::CURRENT; }break;
	}
	m_hFile.Seek( m_BeginOffset+Offset*dat, FilePos );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 読み込んだファイルの解放
/*!
 *	引数などは ISoundDecoder::Close を参照すること
 */
void	CSoundDecoderWave::Close()
{
	m_hFile.Close();
	ZeroMemory( &m_WaveFormat, sizeof(m_WaveFormat) );
	m_SampleLength   = 0;
	m_BeginOffset = 0;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 現在の位置の取得
/*!
 *	引数などは ISoundDecoder::GetPosition を参照すること
 */
uint32	CSoundDecoderWave::GetPosition()		const
{
	const uint32 Size = GetBytePerSample();
	const uint32 FilePos = m_hFile.GetPosition();

	return (FilePos-m_BeginOffset)/Size;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! コンバート後のファイルの長さを取得する（サンプル単位）
/*!
 *	引数などは ISoundDecoder::GetLength を参照すること
 */
uint32	CSoundDecoderWave::GetLength()			const
{
	return m_SampleLength;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! １秒あたり何サンプルあるかの取得
/*!
 *	引数などは ISoundDecoder::GetSamplesPerSec を参照すること
 */
uint32	CSoundDecoderWave::GetSamplesPerSec()	const
{
	return m_WaveFormat.nSamplesPerSec;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! チャンネル数(mono,stereo 等)の取得
/*!
 *	引数などは ISoundDecoder::GetChannels を参照すること
 */
uint32	CSoundDecoderWave::GetChannels()		const
{
	return m_WaveFormat.nChannels;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! １サンプルあたりに使用しているビット量の取得
/*!
 *	引数などは ISoundDecoder::GetBitsPerBlock を参照すること
 */
uint32	CSoundDecoderWave::GetBitsPerBlock()	const
{
	return m_WaveFormat.wBitsPerSample;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! このクラスで読み込みが出来るか調べる
/*!
 *	引数などは ResourceFile::Test を参照すること
 */
MRESULT  CSoundDecoderWave::Test( const MySTL::wstring& FileName )const
{

	if( CString::tolower(CString::GetExtension(FileName))==L"wav" ) { return MRESULT_OK; }

/*
	//	本当はこんなことはしないほうがいい？

	CSoundDecoderWave* pThis = (CSoundDecoderWave*)this;
	DENRESULT ret = pThis->Open( FileName );
	pThis->Close();
*/
	return 1;
}


}
