Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
542 lines
13 KiB
C++
542 lines
13 KiB
C++
|
|
#include "SoundBuffer.h"
|
|
#include "SoundFile.h"
|
|
#include "DirectSound.h"
|
|
|
|
#include <dsound.h>
|
|
#include <assert.h>
|
|
|
|
extern bool g_b3DSound;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CSoundBuffer::CSoundBuffer()
|
|
: m_pDSBuffer8( NULL )
|
|
, m_apDSBuffer( NULL )
|
|
, m_ap3DBuffer( NULL )
|
|
, m_pSoundFile( NULL )
|
|
, m_dwDSBufferSize( 0 )
|
|
, m_dwNumBuffers( 0 )
|
|
{
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CSoundBuffer::CSoundBuffer( IDirectSound8 * pDSound, ISoundFile * pSoundFile, bool b3DSound, DWORD dwNumBuffers )
|
|
: m_pDSBuffer8( NULL )
|
|
, m_apDSBuffer( NULL )
|
|
, m_ap3DBuffer( NULL )
|
|
, m_pSoundFile( NULL )
|
|
, m_dwDSBufferSize( 0 )
|
|
, m_dwNumBuffers( 0 )
|
|
{
|
|
Create( pDSound, pSoundFile, b3DSound, dwNumBuffers );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CSoundBuffer::CSoundBuffer( IDirectSound8 * pDSound, const char * szFilename, bool b3DSound, DWORD dwNumBuffers )
|
|
: m_pDSBuffer8( NULL )
|
|
, m_apDSBuffer( NULL )
|
|
, m_ap3DBuffer( NULL )
|
|
, m_pSoundFile( NULL )
|
|
, m_dwDSBufferSize( 0 )
|
|
, m_dwNumBuffers( 0 )
|
|
{
|
|
Create( pDSound, szFilename, b3DSound, dwNumBuffers );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CSoundBuffer::~CSoundBuffer()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::Create( IDirectSound8 * pDSound, ISoundFile * pSoundFile, bool b3DSound, DWORD dwNumBuffers, DWORD dwAddFlag )
|
|
{
|
|
//인자로 들어온 pDSound는 무시함.(외부 인터페이스를 변경시키지 않으려고 남겨둔 것임)
|
|
pDSound = CDirectSound::GetInstance().GetDS();
|
|
|
|
Destroy();
|
|
|
|
if( g_b3DSound == false )
|
|
b3DSound = false;
|
|
|
|
m_dwDSBufferSize = pSoundFile->GetSize();
|
|
m_pSoundFile = pSoundFile;
|
|
|
|
assert( pDSound != NULL && m_pSoundFile != NULL && m_dwDSBufferSize != 0 );
|
|
|
|
WAVEFORMATEX wfx;
|
|
ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
|
|
wfx.nChannels = pSoundFile->GetChannelCount();
|
|
wfx.nSamplesPerSec = pSoundFile->GetSamplePerSec();
|
|
wfx.wBitsPerSample = pSoundFile->GetBitsPerSample();
|
|
|
|
if( b3DSound )
|
|
{
|
|
if( wfx.nChannels != 1 ) //이것이 Stereo(2)로 되어 있으면 DSBCAPS_CTRL3D를 세팅할 수 없음
|
|
{
|
|
MessageBox( NULL, "3D 사운드를 사용하기 위해서는 사운드 화일이 mono로 설정이 되어 있어야 합니다.", pSoundFile->GetFilename(), MB_OK );
|
|
wfx.nChannels = 1;
|
|
}
|
|
}
|
|
|
|
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
|
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
|
|
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
|
|
|
DSBUFFERDESC dsbd;
|
|
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
|
|
dsbd.dwSize = sizeof(DSBUFFERDESC);
|
|
dsbd.dwFlags = dwAddFlag;
|
|
|
|
if( b3DSound )
|
|
dsbd.dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
|
|
|
|
dsbd.dwBufferBytes = m_dwDSBufferSize;
|
|
dsbd.guid3DAlgorithm = GUID_NULL;
|
|
dsbd.lpwfxFormat = &wfx;
|
|
|
|
// DirectSound is only guarenteed to play PCM data. Other
|
|
// formats may or may not work depending the sound card driver.
|
|
LPDIRECTSOUNDBUFFER tempBuffer = 0;
|
|
|
|
HRESULT hr = pDSound->CreateSoundBuffer( &dsbd, &tempBuffer, NULL );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
return;
|
|
//SNDError( "Cannot Create SoundBuffer!! ErrorCode : 0x%x", hr );
|
|
}
|
|
|
|
hr = tempBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_pDSBuffer8 );
|
|
ULONG refCount = tempBuffer->Release();
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
SNDError( "QueryInterface at (CSoundBuffer::Create) Failed!! errorCode : 0x%x", hr );
|
|
}
|
|
|
|
m_dwNumBuffers = dwNumBuffers;
|
|
m_apDSBuffer = new LPDIRECTSOUNDBUFFER[m_dwNumBuffers];
|
|
for( DWORD i = 0; i < m_dwNumBuffers; i++ )
|
|
m_apDSBuffer[i] = 0;
|
|
|
|
for( i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( FAILED( hr = pDSound->DuplicateSoundBuffer( m_pDSBuffer8, &m_apDSBuffer[i] ) ) )
|
|
{
|
|
delete [] m_apDSBuffer;
|
|
SNDError( "Duplicate SoundBuffer Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
}
|
|
|
|
if( b3DSound )
|
|
{
|
|
m_ap3DBuffer = new IDirectSound3DBuffer*[ dwNumBuffers ];
|
|
for( i = 0; i < dwNumBuffers; i++ )
|
|
{
|
|
m_apDSBuffer[i]->SetCurrentPosition(0);
|
|
m_ap3DBuffer[i] = Get3DBufferInterface( i );
|
|
}
|
|
}
|
|
|
|
FillBufferWithSound( m_apDSBuffer[0] );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::Create( IDirectSound8 * pDSound, const char * szFilename, bool b3DSound, DWORD dwNumBuffers, DWORD dwAddFlag )
|
|
{
|
|
if( !IsFileExist2( szFilename ) )
|
|
{
|
|
SNDError( "%s : 화일을 열 수 없습니다.", szFilename );
|
|
}
|
|
|
|
ISoundFile * pSoundFile = ISoundFile::CreateSoundFileInstance( szFilename );
|
|
Create( pDSound, pSoundFile, b3DSound, dwNumBuffers, dwAddFlag );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::Destroy()
|
|
{
|
|
DWORD i;
|
|
if( m_ap3DBuffer )
|
|
{
|
|
for( i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( m_ap3DBuffer[i] )
|
|
{
|
|
m_ap3DBuffer[i]->Release();
|
|
m_ap3DBuffer[i] = NULL;
|
|
}
|
|
}
|
|
delete [] m_ap3DBuffer;
|
|
m_ap3DBuffer = NULL;
|
|
}
|
|
if( m_apDSBuffer )
|
|
{
|
|
for( i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( m_apDSBuffer[i] )
|
|
{
|
|
ULONG refCount = m_apDSBuffer[i]->Release();
|
|
m_apDSBuffer[i] = NULL;
|
|
}
|
|
}
|
|
|
|
delete [] m_apDSBuffer;
|
|
m_apDSBuffer = NULL;
|
|
}
|
|
|
|
if( m_pDSBuffer8 )
|
|
{
|
|
ULONG refCount = m_pDSBuffer8->Release();
|
|
m_pDSBuffer8 = NULL;
|
|
}
|
|
|
|
delete m_pSoundFile;
|
|
m_pSoundFile = NULL;
|
|
|
|
m_dwDSBufferSize = 0;
|
|
m_dwNumBuffers = 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
int CSoundBuffer::Play( bool bLoop )
|
|
{
|
|
int freeBuffer = GetFreeBuffer();
|
|
|
|
Play( freeBuffer, bLoop );
|
|
|
|
return freeBuffer;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::Play( DWORD index, bool bLoop )
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return;
|
|
|
|
if( index >= m_dwNumBuffers )
|
|
return;
|
|
|
|
LPDIRECTSOUNDBUFFER pDSB = m_apDSBuffer[ index ];
|
|
|
|
if( pDSB == NULL )
|
|
return;
|
|
|
|
if( Restore( pDSB ) )
|
|
{
|
|
//버퍼가 restore 되었을 때 데이터를 새로 채워 넣음.
|
|
FillBufferWithSound( pDSB );
|
|
ResetAll();
|
|
}
|
|
|
|
HRESULT hr = pDSB->Play( 0, 0, ( bLoop ? DSBPLAY_LOOPING : 0 ) );
|
|
if( FAILED( hr ) )
|
|
SNDError( "DirectSound Play Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::Stop( unsigned bufIndex )
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return;
|
|
|
|
if( bufIndex >= m_dwNumBuffers )
|
|
return;
|
|
|
|
HRESULT hr = m_apDSBuffer[ bufIndex ]->Stop();
|
|
if( FAILED( hr ) )
|
|
SNDError( "DirectSoundBuffer Stop Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::StopAll()
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return;
|
|
|
|
for( DWORD i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( m_apDSBuffer[i] )
|
|
{
|
|
HRESULT hr = m_apDSBuffer[i]->Stop();
|
|
if( FAILED( hr ) )
|
|
SNDError( "DirectSoundBuffer Stop(StopAll) Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::Reset( unsigned bufIndex )
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return;
|
|
|
|
if( bufIndex >= m_dwNumBuffers )
|
|
return;
|
|
|
|
HRESULT hr = m_apDSBuffer[ bufIndex ]->SetCurrentPosition( 0L );
|
|
if( FAILED( hr ) )
|
|
SNDError( "SetCurrnetPosition(CSoundBuffer::Reset) Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::ResetAll()
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return;
|
|
|
|
for( DWORD i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( m_apDSBuffer[i] )
|
|
{
|
|
HRESULT hr = m_apDSBuffer[i]->SetCurrentPosition( 0 );
|
|
if( FAILED( hr ) )
|
|
SNDError( "CSoundBuffer Reset Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
bool CSoundBuffer::IsAllPlaying()
|
|
{
|
|
return ( GetFreeBuffer() == -1 );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
bool CSoundBuffer::IsAllFree()
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return false;
|
|
|
|
for( DWORD i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( m_apDSBuffer[i] == NULL )
|
|
return false;
|
|
|
|
DWORD dwStatus = 0;
|
|
m_apDSBuffer[i]->GetStatus( &dwStatus );
|
|
|
|
if( (dwStatus & DSBSTATUS_PLAYING) != 0 )
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
bool CSoundBuffer::IsPlaying( unsigned bufIndex )
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return false;
|
|
|
|
if( bufIndex >= m_dwNumBuffers )
|
|
return false;
|
|
|
|
DWORD dwStatus = 0;
|
|
m_apDSBuffer[ bufIndex ]->GetStatus( &dwStatus );
|
|
if( ( dwStatus & DSBSTATUS_PLAYING ) != 0 )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
DWORD CSoundBuffer::GetMemoryUse()
|
|
{
|
|
return m_dwDSBufferSize;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
bool CSoundBuffer::IsSameFile( const char * szFilename )
|
|
{
|
|
if( m_pSoundFile == NULL )
|
|
return false;
|
|
|
|
return strcmp( m_pSoundFile->GetFilename(), szFilename ) == 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
const char * CSoundBuffer::GetFilename()
|
|
{
|
|
if( m_pSoundFile == NULL )
|
|
return NULL;
|
|
|
|
return m_pSoundFile->GetFilename();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
bool CSoundBuffer::Restore( IDirectSoundBuffer * pDSBuffer )
|
|
{
|
|
assert( pDSBuffer != NULL );
|
|
|
|
DWORD dwStatus;
|
|
HRESULT hr = pDSBuffer->GetStatus( &dwStatus );
|
|
if( FAILED( hr ) )
|
|
SNDError( "GetStatus(at CSoundBuffer::Restore) Failed!! ErrorCode : 0x%x", hr );
|
|
|
|
if( dwStatus & DSBSTATUS_BUFFERLOST )
|
|
{
|
|
do
|
|
{
|
|
hr = pDSBuffer->Restore();
|
|
if( hr == DSERR_BUFFERLOST )
|
|
Sleep( 10 );
|
|
}
|
|
while( hr = pDSBuffer->Restore() );
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
|
|
int CSoundBuffer::GetFreeBuffer()
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return -1;
|
|
|
|
for( DWORD i = 0; i < m_dwNumBuffers; i++ )
|
|
{
|
|
if( m_apDSBuffer[i] )
|
|
{
|
|
DWORD dwStatus = 0;
|
|
m_apDSBuffer[i]->GetStatus( &dwStatus );
|
|
if( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::FillBufferWithSound( IDirectSoundBuffer * pDSBuffer )
|
|
{
|
|
if( pDSBuffer == NULL )
|
|
return;
|
|
|
|
Restore( pDSBuffer );
|
|
|
|
void * pLockedBuffer = NULL;
|
|
DWORD dwLockedBufferSize = 0;
|
|
HRESULT hr = pDSBuffer->Lock( 0, m_dwDSBufferSize, &pLockedBuffer, &dwLockedBufferSize, NULL, NULL, 0L );
|
|
|
|
if( FAILED( hr ) )
|
|
SNDError( "DirectSoundBuffer Lock Failed!! ErrorCode : 0x%x", hr );
|
|
|
|
m_pSoundFile->Reset();
|
|
|
|
DWORD dwDataRead = m_pSoundFile->Read( (BYTE*) pLockedBuffer, dwLockedBufferSize );
|
|
|
|
//나머지는 무음으로 채움.
|
|
FillMemory( (BYTE*) pLockedBuffer + dwDataRead, dwLockedBufferSize - dwDataRead
|
|
, (BYTE)( m_pSoundFile->GetBitsPerSample() == 8 ? 128 : 0 ) );
|
|
|
|
pDSBuffer->Unlock( pLockedBuffer, dwLockedBufferSize, NULL, 0 );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
IDirectSound3DBuffer * CSoundBuffer::Get3DBufferInterface( DWORD dwIndex )
|
|
{
|
|
if( m_apDSBuffer == NULL )
|
|
return NULL;
|
|
|
|
if( dwIndex >= m_dwNumBuffers )
|
|
return NULL;
|
|
|
|
LPDIRECTSOUND3DBUFFER8 pDS3DBuffer = NULL;
|
|
HRESULT hr = m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer8, (void**)&pDS3DBuffer );
|
|
if( FAILED( hr ) )
|
|
SNDError( "QueryInterface (DirectSound3DBuffer) Failed!! ErrorCode : 0x%x", hr );
|
|
|
|
return pDS3DBuffer;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::SetPosition( DWORD dwIndex, D3DVALUE x, D3DVALUE y, D3DVALUE z )
|
|
{
|
|
if( m_ap3DBuffer == NULL )
|
|
return;
|
|
|
|
if( dwIndex >= m_dwNumBuffers )
|
|
return;
|
|
|
|
HRESULT hr = m_ap3DBuffer[dwIndex]->SetPosition( x, y, z, DS3D_IMMEDIATE );
|
|
if( FAILED( hr ) )
|
|
SNDError( "SetPosition (DS3DBuffer) Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CSoundBuffer::SetDistance( DWORD dwIndex, D3DVALUE minDistance, D3DVALUE maxDistance )
|
|
{
|
|
if( m_ap3DBuffer == NULL )
|
|
return;
|
|
|
|
if( dwIndex >= m_dwNumBuffers )
|
|
return;
|
|
|
|
HRESULT hr = m_ap3DBuffer[dwIndex]->SetMinDistance( minDistance, DS3D_IMMEDIATE );
|
|
if( FAILED( hr ) )
|
|
SNDError( "SetMinDistance (DS3DBuffer) Failed!! ErrorCode : 0x%x", hr );
|
|
|
|
if( FAILED( hr = m_ap3DBuffer[dwIndex]->SetMaxDistance( maxDistance, DS3D_IMMEDIATE ) ) )
|
|
SNDError( "SetMaxDistance (DS3DBuffer) Failed!! ErrorCode : 0x%x", hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|