#include "oggplayer.h"
OggPlayer::OggPlayer()
{
bFileOpened = false;
bInitialized = false;
bReleaseDS = false;
pDS = NULL;
pDSB = NULL;
bLoop = false;
bDone = false;
bAlmostDone = false;
}
OggPlayer::~OggPlayer()
{
if (bFileOpened)
Close();
if (bReleaseDS && pDS)
pDS->Release();
}
bool OggPlayer::InitDirectSound( HWND hWnd )
{
HRESULT hr;
if (FAILED(hr = DirectSoundCreate8(NULL, &pDS, NULL)))
return bInitialized = false;
pDS->Initialize(NULL);
pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
bReleaseDS = true;
return bInitialized = true;
}
bool OggPlayer::OpenOgg( char *filename )
{
if (!bInitialized)
return false;
if (bFileOpened)
Close();
FILE *f;
f = fopen(filename, "rb");
if (!f) return false;
ov_open(f, &vf, NULL, 0);
// ok now the tricky part
// the vorbis_info struct keeps the most of the interesting format info
vorbis_info *vi = ov_info(&vf,-1);
// set the wave format
WAVEFORMATEX wfm;
memset(&wfm, 0, sizeof(wfm));
wfm.cbSize = sizeof(wfm);
wfm.nChannels = vi->channels;
wfm.wBitsPerSample = 16; // ogg vorbis is always 16 bit
wfm.nSamplesPerSec = vi->rate;
wfm.nAvgBytesPerSec = wfm.nSamplesPerSec*wfm.nChannels*2;
wfm.nBlockAlign = 2*wfm.nChannels;
wfm.wFormatTag = 1;
// set up the buffer
DSBUFFERDESC desc;
desc.dwSize = sizeof(desc);
desc.dwFlags = 0;
desc.lpwfxFormat = &wfm;
desc.dwReserved = 0;
desc.dwBufferBytes = BUFSIZE*2;
pDS->CreateSoundBuffer(&desc, &pDSB, NULL );
// fill the buffer
DWORD pos = 0;
int sec = 0;
int ret = 1;
DWORD size = BUFSIZE*2;
char *buf;
pDSB->Lock(0, size, (LPVOID*)&buf, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
// now read in the bits
while(ret && pos<size)
{
ret = ov_read(&vf, buf+pos, size-pos, 0, 2, 1, &sec);
pos += ret;
}
pDSB->Unlock( buf, size, NULL, NULL );
nCurSection =
nLastSection = 0;
return bFileOpened = true;
}
void OggPlayer::Close()
{
bFileOpened = false;
if (pDSB)
pDSB->Release();
}
void OggPlayer::Play(bool loop)
{
if (!bInitialized)
return;
if (!bFileOpened)
return;
// play looping because we will fill the buffer
pDSB->Play(0,0,DSBPLAY_LOOPING);
bLoop = loop;
bDone = false;
bAlmostDone = false;
}
void OggPlayer::Stop()
{
if (!bInitialized)
return;
if (!bFileOpened)
return;
pDSB->Stop();
}
void OggPlayer::Update()
{
DWORD pos;
pDSB->GetCurrentPosition(&pos, NULL);
nCurSection = pos<BUFSIZE?0:1;
// section changed?
if (nCurSection != nLastSection)
{
if (bDone && !bLoop)
Stop();
// gotta use this trick 'cause otherwise there wont be played all bits
if (bAlmostDone && !bLoop)
bDone = true;
DWORD size = BUFSIZE;
char *buf;
// fill the section we just left
pDSB->Lock( nLastSection*BUFSIZE, size, (LPVOID*)&buf, &size, NULL, NULL, 0 );
DWORD pos = 0;
int sec = 0;
int ret = 1;
while(ret && pos<size)
{
ret = ov_read(&vf, buf+pos, size-pos, 0, 2, 1, &sec);
pos += ret;
}
// reached the and?
if (!ret && bLoop)
{
// we are looping so restart from the beginning
// NOTE: sound with sizes smaller than BUFSIZE may be cut off
ret = 1;
ov_pcm_seek(&vf, 0);
while(ret && pos<size)
{
ret = ov_read(&vf, buf+pos, size-pos, 0, 2, 1, &sec);
pos += ret;
}
}
else if (!ret && !(bLoop))
{
// not looping so fill the rest with 0
while(pos<size)
*(buf+pos)=0; pos ++;
// and say that after the current section no other sectin follows
bAlmostDone = true;
}
pDSB->Unlock( buf, size, NULL, NULL );
nLastSection = nCurSection;
}
} |