///////////////////////////////////////////////////////////////////////////////
/// @file DirectSound.cpp
///
/// @brief Destiny Sound System DirectSound interface
///
/// @author paradoxnj
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jan 2002
/// @author paradoxnj
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

//#define INITGUID
#include <windows.h>
#include <math.h>
//#include <cstdio>
#include <mmsystem.h>
#include <d3dtypes.h>

#include "eax/eax.h"

#include "DirectSound.hpp"
#include "deSound.hpp"
#include "Channels.hpp"

#include "deResource.hpp"
#include "deFileSystem.hpp"

//#pragma warning (disable : 4100) //Unreferenced format parameter
#pragma warning (disable : 4505) //Unreferenced local function has been removed...
#pragma warning (disable : 4244) //Conversion from ... to ... possible loss of data

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

IdeSoundSystem_DS::IdeSoundSystem_DS()
{
	CoInitialize(NULL);

	m_pDS = NULL;
	m_pPrimaryBuffer = NULL;
	m_pListener = NULL;

	m_RefCount = 1;

	memset(&m_Format, 0, sizeof(WAVEFORMATEX));
}

IdeSoundSystem_DS::~IdeSoundSystem_DS()
{
	Destroy();
	CoUninitialize();
}

void *IdeSoundSystem_DS::GetInterface(int interface_id)
{
	if (interface_id == iface_IdeSoundSystem)
		return (IdeSoundSystem*)this;
	if (interface_id == iface_DirectSound)
		return (IdeSoundSystem_DS*)this;

	return NULL;
}

//#pragma fixme(Need to figure out why I get a 4244 warn here...) // i don't see one - Assassin
deBoolean IdeSoundSystem_DS::Initialize(HWND hWnd)
{
	HRESULT				hres;
	DSBUFFERDESC		bdsc;

	hres = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound8, (LPVOID*)&m_pDS);
	if (FAILED(hres))
		return deFALSE;
	
	hres = m_pDS->Initialize(NULL);
	if (FAILED(hres))
	{
		Destroy();
		return deFALSE;
	}
	
	hres = m_pDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
	if (FAILED(hres))
	{
		Destroy();
		return deFALSE;
	}

	ZeroMemory(&bdsc, sizeof(DSBUFFERDESC));

	bdsc.dwSize = sizeof(DSBUFFERDESC);
	bdsc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
	bdsc.dwBufferBytes = 0;
	bdsc.dwReserved = 0;
	bdsc.lpwfxFormat = NULL;

	hres = m_pDS->CreateSoundBuffer(&bdsc, &m_pPrimaryBuffer, NULL);
	if (FAILED(hres))
	{
		Destroy();
		return deFALSE;
	}

	ZeroMemory(&m_Format, sizeof(WAVEFORMATEX));

	m_Format.wFormatTag = WAVE_FORMAT_PCM;
	m_Format.nChannels = 2;
	m_Format.nSamplesPerSec = 22050;
	m_Format.wBitsPerSample = 16;
	m_Format.nBlockAlign = m_Format.nChannels * m_Format.wBitsPerSample / 8;
	m_Format.nAvgBytesPerSec = m_Format.nSamplesPerSec * m_Format.nBlockAlign;

	hres = m_pPrimaryBuffer->SetFormat(&m_Format);
	if (FAILED(hres))
	{
		Destroy();
		return deFALSE;
	}

	hres = m_pPrimaryBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID*)&m_pListener);
	if (FAILED(hres))
	{
		Destroy();
		return deFALSE;
	}

	return deTRUE;
}

void IdeSoundSystem_DS::Destroy()
{
	if (m_pListener)
		DE3D_SAFE_RELEASE(m_pListener);

	if (m_pPrimaryBuffer)
		DE3D_SAFE_RELEASE(m_pPrimaryBuffer);

	if (m_pDS)
		DE3D_SAFE_RELEASE(m_pDS);

	Release();
}

IdeSoundBuffer *IdeSoundSystem_DS::CreateSoundBuffer(IdeSoundData *sndData)
{
	IdeSoundBuffer_DS	*dsbuff;

	dsbuff = new IdeSoundBuffer_DS();
	if (!dsbuff)
		return NULL;

	if (!dsbuff->Initialize(this, sndData))
	{
		DE3D_SAFE_RELEASE(dsbuff);
		return NULL;
	}

	return dsbuff;
}

float IdeSoundSystem_DS::GetRollOffFactor()
{
	float			f;
	HRESULT			hres;

	hres = m_pListener->GetRolloffFactor(&f);
	if (FAILED(hres))
		return 0.0f;
	else
		return f;
}

float IdeSoundSystem_DS::GetDopplerFactor()
{
	float			f;
	HRESULT			hres;

	hres = m_pListener->GetDopplerFactor(&f);
	if (!FAILED(hres))
		return 0.0f;
	else
		return f;
}

float IdeSoundSystem_DS::GetDistanceFactor()
{
	float			f;
	HRESULT			hres;

	hres = m_pListener->GetDistanceFactor(&f);
	if (FAILED(hres))
		return 0.0f;
	else
		return f;
}

void IdeSoundSystem_DS::SetRollOffFactor(float factor)
{
	m_pListener->SetRolloffFactor(factor, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetDopplerFactor(float factor)
{
	m_pListener->SetDopplerFactor(factor, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetDistanceFactor(float factor)
{
	m_pListener->SetDistanceFactor(factor, DS3D_DEFERRED);
}

deBoolean IdeSoundSystem_DS::GetListenerPosition(float *x, float *y, float *z)
{
	D3DVECTOR		vec;
	HRESULT			hres;

	hres = m_pListener->GetPosition(&vec);
	if (FAILED(hres))
		return deFALSE;

	*x = vec.x;
	*y = vec.y;
	*z = vec.z;

	return deTRUE;
}

deBoolean IdeSoundSystem_DS::GetListenerPosition(deVec3d *pos)
{
	D3DVECTOR		vec;
	HRESULT			hres;

	hres = m_pListener->GetPosition(&vec);
	if (FAILED(hres))
		return deFALSE;

	pos->X = vec.x;
	pos->Y = vec.y;
	pos->Z = vec.z;

	return deTRUE;
}

deBoolean IdeSoundSystem_DS::GetListenerVelocity(float *x, float *y, float *z)
{
	D3DVECTOR		vec;
	HRESULT			hres;

	hres = m_pListener->GetVelocity(&vec);
	if (FAILED(hres))
		return deFALSE;

	*x = vec.x;
	*y = vec.y;
	*z = vec.z;

	return deTRUE;
}

deBoolean IdeSoundSystem_DS::GetListenerVelocity(deVec3d *vel)
{
	D3DVECTOR		vec;
	HRESULT			hres;

	hres = m_pListener->GetVelocity(&vec);
	if (FAILED(hres))
		return deFALSE;

	vel->X = vec.x;
	vel->Y = vec.y;
	vel->Z = vec.z;

	return deFALSE;
}

deBoolean IdeSoundSystem_DS::GetListenerOrientation(float *Fx, float *Fy, float *Fz, float *Tx, float *Ty, float *Tz)
{
	D3DVECTOR		f, t;
	HRESULT			hres;

	hres = m_pListener->GetOrientation(&f, &t);
	if (FAILED(hres))
		return deFALSE;

	*Fx = f.x;
	*Fy = f.y;
	*Fz = f.z;

	*Tx = t.x;
	*Ty = t.y;
	*Tz = t.z;

	return deTRUE;
}

deBoolean IdeSoundSystem_DS::GetListenerOrientation(deVec3d *Front, deVec3d *Top)
{
	D3DVECTOR		f, t;
	HRESULT			hres;

	hres = m_pListener->GetOrientation(&f, &t);
	if (FAILED(hres))
		return deFALSE;

	Front->X = f.x;
	Front->Y = f.y;
	Front->Z = f.z;

	Top->X = t.x;
	Top->Y = t.y;
	Top->Z = t.z;

	return deTRUE;
}

void IdeSoundSystem_DS::SetListenerPosition(float x, float y, float z)
{
	m_pListener->SetPosition(x, y, z, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetListenerPosition(deVec3d pos)
{
	m_pListener->SetPosition((float)pos.X, (float)pos.Y, (float)pos.Z, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetListenerVelocity(float x, float y, float z)
{
	m_pListener->SetVelocity(x, y, z, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetListenerVelocity(deVec3d vel)
{
	m_pListener->SetVelocity((float)vel.X, (float)vel.Y, (float)vel.Z, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetListenerOrientation(float Fx, float Fy, float Fz, float Tx, float Ty, float Tz)
{
	m_pListener->SetOrientation(Fx, Fy, Fz, Tx, Ty, Tz, DS3D_DEFERRED);
}

void IdeSoundSystem_DS::SetListenerOrientation(deVec3d Front, deVec3d Top)
{
	m_pListener->SetOrientation((float)Front.X, (float)Front.Y, (float)Front.Z, (float)Top.X, (float)Top.Y, (float)Top.Z, DS3D_DEFERRED);
}

//A DirectSound Buffer
IdeSoundBuffer_DS::IdeSoundBuffer_DS()
{

	//for (int i = 0; i < MAX_BUFFERS; i++)
	m_pBuffer = NULL;

	m_p3DBuffer = NULL;
	m_pSS = NULL;

	m_RefCount = 1;
}

IdeSoundBuffer_DS::IdeSoundBuffer_DS(IdeSoundSystem *ss, IdeSoundData *data)
{
	//for (int i = 0; i < MAX_BUFFERS; i++)
	m_pBuffer = NULL;

	m_p3DBuffer = NULL;
	m_pSS = NULL;

	m_RefCount = 1;

	Initialize(ss, data);
}

IdeSoundBuffer_DS::~IdeSoundBuffer_DS()
{
	Destroy();
}

deBoolean IdeSoundBuffer_DS::Initialize(IdeSoundSystem *ss, IdeSoundData *data)
{
	HRESULT				hres;
	IDirectSoundBuffer	*buff;

	if (!ss)
		return deFALSE;

	m_pSS = (IdeSoundSystem_DS*)ss;
	m_pSS->Claim();

	m_pData = data;
	
	ZeroMemory(&m_Format, sizeof(WAVEFORMATEX));
	ZeroMemory(&m_Desc, sizeof(DSBUFFERDESC));

	//Get the format of the data
	data->GetFormat(&m_Format);

	//Create the buffer description
	u32 numbytes = data->GetLength();
	m_Desc.dwBufferBytes = min(numbytes, m_Format.nAvgBytesPerSec * 2);
	m_Desc.dwSize = sizeof(DSBUFFERDESC);
	m_Desc.dwReserved = 0;
	m_Desc.lpwfxFormat = &m_Format;
	m_Desc.dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;

	m_BufferSize = m_Desc.dwBufferBytes;
	m_SecureDistance = (int)(float(m_Format.nAvgBytesPerSec / 10));
	m_DataPosition = 0;
	m_LastPlayPos = 0;
	m_BufferLoops = 0;

	//Create the DirectSound buffer
	hres = m_pSS->m_pDS->CreateSoundBuffer(&m_Desc, &buff, NULL);
	if (FAILED(hres))
		return deFALSE;

	hres = buff->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)&m_pBuffer);
	if (FAILED(hres))
		return deFALSE;

	if (!Update())
		return deFALSE;

	m_Cfg.Volume = 0;
	m_Cfg.Pan = 0;
	m_Cfg.Freq = 1;
	
	m_Cfg.Dist_Min = 0;
	m_Cfg.Dist_Max = 0;
	m_Cfg.ConeAngle_Inner = 0;
	m_Cfg.ConeAngle_Outer = 0;
	m_Cfg.ConeVolume_Outside = 0;

	m_Cfg.Position.x = 0;
	m_Cfg.Position.y = 0;
	m_Cfg.Position.z = 0;

	m_Cfg.Velocity.x = 0;
	m_Cfg.Velocity.y = 0;
	m_Cfg.Velocity.z = 0;

	m_Cfg.Cone_Orientation.x = 0;
	m_Cfg.Cone_Orientation.y = 0;
	m_Cfg.Cone_Orientation.z = 0;

	m_Cfg.Repeats = 0;

	//ApplySettings();

	return deTRUE;
}

deBoolean IdeSoundBuffer_DS::Destroy()
{
	DE3D_SAFE_RELEASE(m_p3DBuffer);

	//for (int i = 0; i < MAX_BUFFERS; i++)
	DE3D_SAFE_RELEASE(m_pBuffer);

	m_pSS->Release();
	return deTRUE;
}

void IdeSoundBuffer_DS::GetConfig(deSoundCfg &Cfg)
{
	Cfg.Volume = m_Cfg.Volume;
	Cfg.Pan = m_Cfg.Pan;
	Cfg.Freq = m_Cfg.Freq;
}

void IdeSoundBuffer_DS::SetConfig(deSoundCfg Cfg)
{
	m_Cfg.Volume = Cfg.Volume;
	m_Cfg.Pan = Cfg.Pan;
	m_Cfg.Freq = Cfg.Freq;

	if (m_Cfg.Volume > DSBVOLUME_MAX)
		m_Cfg.Volume = DSBVOLUME_MAX;

	if (m_Cfg.Volume < DSBVOLUME_MIN)
		m_Cfg.Volume = DSBVOLUME_MIN;

	if (m_Cfg.Pan > DSBPAN_RIGHT)
		m_Cfg.Pan = DSBPAN_RIGHT;

	if (m_Cfg.Pan < DSBPAN_LEFT)
		m_Cfg.Pan = DSBPAN_LEFT;

	if (m_Cfg.Freq < DSBFREQUENCY_MIN)
		m_Cfg.Freq = DSBFREQUENCY_MIN;

	if (m_Cfg.Freq > DSBFREQUENCY_MAX)
		m_Cfg.Freq = DSBFREQUENCY_MAX;
}

deBoolean IdeSoundBuffer_DS::SetVolume(long vol)
{
	HRESULT				hres;

	hres = m_pBuffer->SetVolume(vol);
	if (FAILED(hres))
		return deFALSE;

	return deTRUE;
}

deBoolean IdeSoundBuffer_DS::SetPan(long pan)
{
	HRESULT				hres;

	hres = m_pBuffer->SetPan(pan);
	if (FAILED(hres))
		return deFALSE;

	return deTRUE;
}

deBoolean IdeSoundBuffer_DS::SetFrequency(long freq)
{
	HRESULT				hres;

	hres = m_pBuffer->SetFrequency((DWORD)freq);
	if (FAILED(hres))
		return deFALSE;

	return deTRUE;
}

long IdeSoundBuffer_DS::GetVolume()
{
	HRESULT				hres;
	long				vol;

	hres = m_pBuffer->GetVolume(&vol);
	if (FAILED(hres))
		return 0;

	return vol;
}

long IdeSoundBuffer_DS::GetPan()
{
	HRESULT				hres;
	long				pan;

	hres = m_pBuffer->GetPan(&pan);
	if (FAILED(hres))
		return 0;

	return pan;
}

long IdeSoundBuffer_DS::GetFrequency()
{
	HRESULT				hres;
	DWORD				freq;

	hres = m_pBuffer->GetFrequency(&freq);
	if (FAILED(hres))
		return 0;

	return (long)freq;
}

deBoolean IdeSoundBuffer_DS::ApplySettings()
{
	//HRESULT				hres;
	//DS3DBUFFER			buff;
	//D3DVECTOR			vec;

	m_pBuffer->SetVolume(m_Cfg.Volume);
	m_pBuffer->SetPan(m_Cfg.Pan);
	m_pBuffer->SetFrequency(m_Cfg.Freq);

	/*ZeroMemory(&buff, sizeof(DS3DBUFFER));

	buff.dwSize = sizeof(DS3DBUFFER);

	vec.x = m_Cfg.Velocity.x;
	vec.y = m_Cfg.Velocity.y;
	vec.z = m_Cfg.Velocity.z;

	buff.vVelocity = vec;

	vec.x = m_Cfg.Position.x;
	vec.y = m_Cfg.Position.y;
	vec.z = m_Cfg.Position.z;

	buff.vPosition = vec;

	vec.x = m_Cfg.Cone_Orientation.x;
	vec.y = m_Cfg.Cone_Orientation.y;
	vec.z = m_Cfg.Cone_Orientation.z;

	buff.vConeOrientation = vec;

	buff.lConeOutsideVolume = m_Cfg.ConeVolume_Outside;
	buff.dwInsideConeAngle = m_Cfg.ConeAngle_Inner;
	buff.dwOutsideConeAngle = m_Cfg.ConeAngle_Outer;
	buff.flMinDistance = m_Cfg.Dist_Min;
	buff.flMaxDistance = m_Cfg.Dist_Max;
	
	//hres = m_p3DBuffer->SetAllParameters(&buff, DS3D_IMMEDIATE);
	//if (FAILED(hres))
	//	return deFALSE;
	*/

	return deTRUE;
}

IdeResourceBase *IdeSoundBuffer_DS::MakeCopy()
{
	IdeSoundBuffer_DS			*ds;

	ds = new IdeSoundBuffer_DS(m_pSS, m_pData);
	if (!ds)
		return NULL;

	return (IdeResourceBase*)ds;
}

deBoolean IdeSoundBuffer_DS::Play(deBoolean loop)
{
	HRESULT				hres;
	DWORD				status;

	Update();
	m_Loop = loop;

	/*for (int i = 1; i < MAX_BUFFERS; i++)
	{
		if (m_pBuffer)
		{
			m_pBuffer->GetStatus(&status);
			if (!(status & DSBSTATUS_PLAYING))
				SAFE_RELEASE(m_pBuffer[i]);
		}
	}*/

	if (m_Loop)
	{
		hres = m_pBuffer->Play(0, 0, DSBPLAY_LOOPING);
		if (FAILED(hres))
			return deFALSE;

		return deTRUE;
	}

	m_pBuffer->GetStatus(&status);
	/*if (status & DSBSTATUS_PLAYING && m_pData->GetType() != IdeSoundData::iface_OGG)
	{
		(for (i = 1; i < MAX_BUFFERS; i++)
		{
			if (!m_pBuffer[i])
				break;
		}

		if (i >= MAX_BUFFERS)
			return deTRUE;

		hres = m_pSS->m_pDS->DuplicateSoundBuffer(m_pBuffer[0], &m_pBuffer[i]);
		if (FAILED(hres))
			return deFALSE;

		hres = m_pBuffer->Play(0, 0, 0);
		if (FAILED(hres))
			return deFALSE;
	}
	else*/
	{
		hres = m_pBuffer->Play(0, 0, 0);
		if (FAILED(hres))
			return deFALSE;
	}

	return deTRUE;
}

deBoolean IdeSoundBuffer_DS::Update()
{
	HRESULT				hres;
	uint8				*ptr1, *ptr2;
	DWORD				size1, size2;
	DWORD				written1, written2;
	DWORD				playpos, writepos;

	hres = m_pBuffer->GetCurrentPosition(&playpos, &writepos);
	if (FAILED(hres))
		return deFALSE;

	if (playpos < m_LastPlayPos)
		++m_BufferLoops;
	u32 FullPlayPos = playpos + m_BufferLoops*m_BufferSize;
	u32 DataLength = m_pData->GetLength();
	m_LastPlayPos = playpos;

	if (m_pData->GetType() == IdeSoundData::iface_OGG)
	{
		u32 FillLength;
		if (playpos > m_DataPosition)
			FillLength = playpos - m_DataPosition - m_SecureDistance;
		else
			FillLength = (m_BufferSize - m_DataPosition) + playpos - m_SecureDistance;

		if (FillLength > m_SecureDistance)
		{
			hres = m_pBuffer->Lock(m_DataPosition, FillLength, (LPVOID*)&ptr1, &size1, (LPVOID*)&ptr2, &size2, 0);
			if (FAILED(hres))
				return deFALSE;

			written1 = m_pData->GetDataChunk((void*)ptr1, size1);
			if (written1 == size1)
			{
				written2 = m_pData->GetDataChunk((void*)ptr2, size2);
				if (written2 != size2)
					written2 = size2;
			}
			else
			{
				memset(&ptr1[written1], 0, size1-written1);
				written1 = size1;
				memset(ptr2, 0, size2);
				written2 = size2;
			}

			hres = m_pBuffer->Unlock((LPVOID)ptr1, size1, (LPVOID)ptr2, size2);
			if (FAILED(hres))
				return deFALSE;

			m_DataPosition += FillLength;
			if (m_DataPosition >= m_BufferSize)
				m_DataPosition -= m_BufferSize;
		}
	}
	else
	{
		deBoolean streamdone = (m_DataPosition >= DataLength) ? deTRUE : deFALSE;
		
		if (!streamdone)
		{
			u32 UnsafeArea;
			if (writepos >= playpos)
				UnsafeArea = (writepos - playpos);
			else
				UnsafeArea = (m_BufferSize - playpos) + writepos;
			// if the play position somehow managed to get ahead of the file position, jump ahead in the file
			if (m_DataPosition < FullPlayPos + UnsafeArea)
			{
				m_DataPosition = FullPlayPos + UnsafeArea;
				if (m_DataPosition >= DataLength)
					m_DataPosition = DataLength;
			}
			u32 FillLength = m_BufferSize - (m_DataPosition - FullPlayPos);
			if (FillLength > m_BufferSize - UnsafeArea)
				FillLength = m_BufferSize - UnsafeArea;
			u32 BufferPos = m_DataPosition % m_BufferSize;
/*			if (playpos > m_FillPosition)
				m_FillLength = playpos - m_FillPosition - m_SecureDistance;
			else
				m_FillLength = (m_BufferSize - m_FillPosition) + playpos - m_SecureDistance;
*/

			hres = m_pBuffer->Lock(BufferPos, FillLength, (LPVOID*)&ptr1, &size1, (LPVOID*)&ptr2, &size2, 0);
			if (FAILED(hres))
				return deFALSE;
			
			written2 = 0;
			written1 = m_pData->GetDataChunk((void*)ptr1, size1, m_DataPosition);
			m_DataPosition += written1;
			if (written1 == size1)
			{
				if (ptr2)
				{
					written2 = m_pData->GetDataChunk((void*)ptr2, size2, m_DataPosition);
					if (written2 != size2)
						written2 = size2;
					m_DataPosition += written2;
				}
			}
			else
			{
				// blank out the remainder of the buffer
				memset(ptr1 + written1, 0, size1-written1);
				written1 = size1;
				if (ptr2)
				{
					memset(ptr2, 0, size2);
					written2 = size2;
				}
			}
			
			hres = m_pBuffer->Unlock((LPVOID)ptr1, written1, (LPVOID)ptr2, written2);
			if (FAILED(hres))
				return deFALSE;
			
			//if (m_FillPosition == 0 && m_pData->AtEndOfStream())
			//	m_BufferFilled = deTRUE;
			
/*			m_DataPosition += m_FillLength;
			if (m_FillPosition >= m_BufferSize)
				m_FillPosition -= m_BufferSize;
*/		}

/*
		if (streamdone && m_EmptyPos == -1)
			m_EmptyPos = m_DataPosition;
		
		if (m_EmptyPos != -1 && (s32)playpos >= m_EmptyPos)
		{
			if (!m_Loop)
				Stop(deTRUE);
			else
			{
				m_pBuffer->SetCurrentPosition(0);
				m_pData->SetPosition(0);
				m_FillPosition = 0;
			}
			m_EmptyPos = -1;
		}
*/	}

	if (FullPlayPos >= m_DataPosition)
	{
		if (!m_Loop)
			Stop(deTRUE);
		else
		{
			m_pBuffer->SetCurrentPosition(0);
			m_pData->SetPosition(0);
			m_DataPosition = 0;
			m_BufferLoops = 0;
			m_LastPlayPos = 0;
		}
	}
	return deTRUE;
}

deBoolean IdeSoundBuffer_DS::Stop(deBoolean rewind)
{
	HRESULT				hres;

	//for (int i = 1; i < MAX_BUFFERS; i++)
	//	SAFE_RELEASE(m_pBuffer[i]);

	hres = m_pBuffer->Stop();
	if (FAILED(hres))
		return deFALSE;

	if (rewind)
	{
		if (!Rewind())
			return deFALSE;
	}
	else
	{
		m_pBuffer->GetCurrentPosition(&m_LastPlayPos, NULL);
	}

	return deTRUE;
}

deBoolean IdeSoundBuffer_DS::Rewind()
{
	HRESULT				hres;

	m_DataPosition = 0;
	m_BufferLoops = 0;
	m_LastPlayPos = 0;
	m_pData->SetPosition(0);
	hres = m_pBuffer->SetCurrentPosition(0);
	if (FAILED(hres))
		return deFALSE;
	return deTRUE;
}


deBoolean IdeSoundBuffer_DS::IsPlaying()
{
	DWORD				status;
	HRESULT				hres;
	DWORD				playpos, writepos;
	
	hres = m_pBuffer->GetCurrentPosition(&playpos, &writepos);
	if (FAILED(hres))
		return deFALSE;
	hres = m_pBuffer->GetStatus(&status);
	if (FAILED(hres))
		return deFALSE;

	deBoolean playing = (status & DSBSTATUS_PLAYING) ? deTRUE : deFALSE;
	if (!playing && playpos == 0 && m_LastPlayPos > 0)
	{
		if (!m_Loop)
			Stop(deTRUE);
		else
			Rewind();
	}

	return playing;
}

void *IdeSoundBuffer_DS::GetInterface(int interface_id)
{
	if (interface_id == iface_IdeSoundBuffer)
		return (IdeSoundBuffer*)this;

	if (interface_id == iface_DirectSound)
		return (IdeSoundBuffer_DS*)this;

	return NULL;
}

#pragma warning (default : 4100)
#pragma warning (default : 4505)
#pragma warning (default : 4244)

