Blame |
Last modification |
View Log
| RSS feed
#include "DSoundManager.h"
#include <io.h>
#include <fcntl.h>
#include "debug.h"
#include "DSoundInstance.h"
#include "FModLoader.h"
#include <math.h>
#include "..\PakLib\PakInterface.h"
using namespace Sexy;
#define USE_OGG_LIB
#ifdef USE_OGG_LIB
#include "ogg/ivorbiscodec.h"
#include "ogg/ivorbisfile.h"
#endif
#define SOUND_FLAGS (DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY)
DSoundManager::DSoundManager(HWND theHWnd, bool haveFMod)
{
mHaveFMod = haveFMod;
mLastReleaseTick = 0;
mPrimaryBuffer = NULL;
int i;
for (i = 0; i < MAX_SOURCE_SOUNDS; i++)
{
mSourceSounds[i] = NULL;
mBaseVolumes[i] = 1;
mBasePans[i] = 0;
}
for (i = 0; i < MAX_CHANNELS; i++)
mPlayingSounds[i] = NULL;
mDirectSound = NULL;
mMasterVolume = 1.0;
if (theHWnd != NULL)
{
extern HMODULE gDSoundDLL;
typedef HRESULT (WINAPI *DirectSoundCreateFunc)(LPCGUID lpcGuid, LPDIRECTSOUND * ppDS, LPUNKNOWN pUnkOuter);
DirectSoundCreateFunc aDirectSoundCreateFunc = (DirectSoundCreateFunc)GetProcAddress(gDSoundDLL,"DirectSoundCreate");
if (aDirectSoundCreateFunc != NULL && aDirectSoundCreateFunc(NULL, &mDirectSound, NULL) == DS_OK)
{
//FSOUND_SetOutput(FSOUND_OUTPUT_WINMM);
if (mHaveFMod)
{
LoadFModDLL();
gFMod->FSOUND_SetHWND(theHWnd);
gFMod->FSOUND_SetBufferSize(200); // #LUC
gFMod->FSOUND_Init(44100, 64, FSOUND_INIT_GLOBALFOCUS);
}
HRESULT aResult = mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_PRIORITY);
if (SUCCEEDED(aResult))
{
// Set primary buffer to 16-bit 44.1Khz
WAVEFORMATEX aWaveFormat;
DSBUFFERDESC aBufferDesc;
// Set up wave format structure.
int aBitCount = 16;
int aChannelCount = 2;
int aSampleRate = 44100;
// Set up wave format structure.
memset(&aWaveFormat, 0, sizeof(WAVEFORMATEX));
aWaveFormat.cbSize = sizeof(WAVEFORMATEX);
aWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
aWaveFormat.nChannels = aChannelCount;
aWaveFormat.nSamplesPerSec = aSampleRate;
aWaveFormat.nBlockAlign = aChannelCount*aBitCount/8;
aWaveFormat.nAvgBytesPerSec =
aWaveFormat.nSamplesPerSec * aWaveFormat.nBlockAlign;
aWaveFormat.wBitsPerSample = aBitCount;
// Set up DSBUFFERDESC structure.
memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
aBufferDesc.dwSize = sizeof(DSBUFFERDESC1);
aBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;//| DSBCAPS_CTRL3D; // Need default controls (pan, volume, frequency).
aBufferDesc.dwBufferBytes = 0;
aBufferDesc.lpwfxFormat =NULL;//(LPWAVEFORMATEX)&aWaveFormat;
HRESULT aResult = mDirectSound->CreateSoundBuffer(&aBufferDesc, &mPrimaryBuffer, NULL);
if (aResult == DS_OK)
{
aResult = mPrimaryBuffer->SetFormat(&aWaveFormat);
}
}
else
{
aResult = mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
}
}
}
}
DSoundManager::~DSoundManager()
{
ReleaseChannels();
ReleaseSounds();
if (mPrimaryBuffer)
mPrimaryBuffer->Release();
if (mDirectSound != NULL)
{
if (mHaveFMod)
gFMod->FSOUND_Close();
mDirectSound->Release();
if (mHaveFMod)
FreeFModDLL();
}
}
int DSoundManager::FindFreeChannel()
{
DWORD aTick = GetTickCount();
if (aTick-mLastReleaseTick > 1000)
{
ReleaseFreeChannels();
mLastReleaseTick = aTick;
}
for (int i = 0; i < MAX_CHANNELS; i++)
{
if (mPlayingSounds[i] == NULL)
return i;
if (mPlayingSounds[i]->IsReleased())
{
delete mPlayingSounds[i];
mPlayingSounds[i] = NULL;
return i;
}
}
return -1;
}
bool DSoundManager::Initialized()
{
/*
if (mDirectSound!=NULL)
{
mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
}
*/
return (mDirectSound != NULL);
}
int DSoundManager::VolumeToDB(double theVolume)
{
int aVol = (int) ((log10(1 + theVolume*9) - 1.0) * 2333);
if (aVol < -2000)
aVol = -10000;
return aVol;
}
void DSoundManager::SetVolume(double theVolume)
{
mMasterVolume = theVolume;
for (int i = 0; i < MAX_CHANNELS; i++)
if (mPlayingSounds[i] != NULL)
mPlayingSounds[i]->RehupVolume();
}
bool DSoundManager::LoadWAVSound(unsigned int theSfxID, const std::string& theFilename)
{
int aDataSize;
PFILE* fp;
fp = p_fopen(theFilename.c_str(), "rb");
if (fp <= 0)
return false;
char aChunkType[5];
aChunkType[4] = '\0';
ulong aChunkSize;
p_fread(aChunkType, 1, 4, fp);
if (!strcmp(aChunkType, "RIFF") == 0)
return false;
p_fread(&aChunkSize, 4, 1, fp);
p_fread(aChunkType, 1, 4, fp);
if (!strcmp(aChunkType, "WAVE") == 0)
return false;
ushort aBitCount = 16;
ushort aChannelCount = 1;
ulong aSampleRate = 22050;
uchar anXor = 0;
while (!p_feof(fp))
{
p_fread(aChunkType, 1, 4, fp);
if (p_fread(&aChunkSize, 4, 1, fp) == 0)
return false;
int aCurPos = p_ftell(fp);
if (strcmp(aChunkType, "fmt ") == 0)
{
ushort aFormatTag;
ulong aBytesPerSec;
ushort aBlockAlign;
p_fread(&aFormatTag, 2, 1, fp);
p_fread(&aChannelCount, 2, 1, fp);
p_fread(&aSampleRate, 4, 1, fp);
p_fread(&aBytesPerSec, 4, 1, fp);
p_fread(&aBlockAlign, 2, 1, fp);
p_fread(&aBitCount, 2, 1, fp);
if (aFormatTag != 1)
return false;
}
else if (strcmp(aChunkType, "dep ") == 0)
{
char aStr[256];
ushort aStrLen;
p_fread(&aStrLen, 2, 1, fp);
if (aStrLen > 255)
aStrLen = 255;
p_fread(aStr, 1, aStrLen, fp);
aStr[aStrLen] = '\0';
FILETIME aSavedFileTime;
p_fread(&aSavedFileTime, sizeof(FILETIME), 1, fp);
FILETIME anActualFileTime;
memset(&anActualFileTime, 0, sizeof(FILETIME));
GetTheFileTime(aStr, &anActualFileTime);
if ((aSavedFileTime.dwHighDateTime != anActualFileTime.dwHighDateTime) ||
(aSavedFileTime.dwLowDateTime != anActualFileTime.dwLowDateTime ))
return false;
}
else if (strcmp(aChunkType, "xor ") == 0)
{
p_fread(&anXor, 1, 1, fp);
}
else if (strcmp(aChunkType, "data") == 0)
{
aDataSize = aChunkSize;
mSourceDataSizes[theSfxID] = aChunkSize;
PCMWAVEFORMAT aWaveFormat;
DSBUFFERDESC aBufferDesc;
// Set up wave format structure.
memset(&aWaveFormat, 0, sizeof(PCMWAVEFORMAT));
aWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
aWaveFormat.wf.nChannels = aChannelCount;
aWaveFormat.wf.nSamplesPerSec = aSampleRate;
aWaveFormat.wf.nBlockAlign = aChannelCount*aBitCount/8;
aWaveFormat.wf.nAvgBytesPerSec =
aWaveFormat.wf.nSamplesPerSec * aWaveFormat.wf.nBlockAlign;
aWaveFormat.wBitsPerSample = aBitCount;
// Set up DSBUFFERDESC structure.
memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
aBufferDesc.dwSize = sizeof(DSBUFFERDESC);
//aBufferDesc.dwFlags = DSBCAPS_CTRL3D;
aBufferDesc.dwFlags = SOUND_FLAGS; //DSBCAPS_CTRLDEFAULT;
//aBufferDesc.dwFlags = 0;
aBufferDesc.dwBufferBytes = aDataSize;
aBufferDesc.lpwfxFormat = (LPWAVEFORMATEX)&aWaveFormat;
if (mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL) != DS_OK)
{
p_fclose(fp);
return false;
}
void* lpvPtr;
DWORD dwBytes;
if (mSourceSounds[theSfxID]->Lock(0, aDataSize, &lpvPtr, &dwBytes, NULL, NULL, 0) != DS_OK)
{
p_fclose(fp);
return false;
}
int aReadSize = p_fread(lpvPtr, 1, aDataSize, fp);
p_fclose(fp);
for (int i = 0; i < aDataSize; i++)
((uchar*) lpvPtr)[i] ^= anXor;
if (mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL) != DS_OK)
return false;
if (aReadSize != aDataSize)
return false;
return true;
}
p_fseek(fp, aCurPos+aChunkSize, SEEK_SET);
}
return false;
}
// Load FMod sound can handle oggs and mp3s and whatever else fmod can decode
bool DSoundManager::LoadFModSound(unsigned int theSfxID, const std::string& theFilename)
{
if (!mHaveFMod)
return false;
FSOUND_SAMPLE* aSample = gFMod->FSOUND_Sample_Load(FSOUND_FREE, theFilename.c_str(), 0, 0);
if (aSample == NULL)
{
return false;
}
int aMode = gFMod->FSOUND_Sample_GetMode(aSample);
int aFreq;
gFMod->FSOUND_Sample_GetDefaults(aSample, &aFreq, NULL, NULL, NULL);
PCMWAVEFORMAT aWaveFormat;
DSBUFFERDESC aBufferDesc;
// Set up wave format structure.
memset(&aWaveFormat, 0, sizeof(PCMWAVEFORMAT));
aWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
aWaveFormat.wf.nChannels = ((aMode & FSOUND_MONO) != 0) ? 1 : 2;
aWaveFormat.wf.nSamplesPerSec = aFreq;
aWaveFormat.wBitsPerSample = ((aMode & FSOUND_8BITS) != 0) ? 8 : 16;
aWaveFormat.wf.nBlockAlign = aWaveFormat.wf.nChannels*aWaveFormat.wBitsPerSample/8;
aWaveFormat.wf.nAvgBytesPerSec = aWaveFormat.wf.nSamplesPerSec * aWaveFormat.wf.nBlockAlign;
/*
WAVEFORMATEX rigWave;
rigWave.cbSize=sizeof(rigWave);
rigWave.nAvgBytesPerSec=aWaveFormat.wf.nAvgBytesPerSec;
rigWave.nBlockAlign=aWaveFormat.wf.nBlockAlign;
rigWave.nChannels=aWaveFormat.wf.nChannels;
rigWave.nSamplesPerSec=aWaveFormat.wf.nSamplesPerSec;
rigWave.wBitsPerSample=aWaveFormat.wBitsPerSample;
rigWave.wFormatTag=aWaveFormat.wf.wFormatTag;
*/
// Set up DSBUFFERDESC structure.
int aLenBytes = gFMod->FSOUND_Sample_GetLength(aSample) * aWaveFormat.wf.nBlockAlign;
memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
mSourceDataSizes[theSfxID] = aLenBytes;
//FUNK
aBufferDesc.dwSize = sizeof(DSBUFFERDESC);
aBufferDesc.dwFlags = SOUND_FLAGS;
aBufferDesc.dwBufferBytes = aLenBytes;
aBufferDesc.lpwfxFormat =(LPWAVEFORMATEX)&aWaveFormat;
if (mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL) != DS_OK)
{
/*
char xmsg[100];
sprintf(xmsg, "WAV STUFF: (%s)\n"
"nAvgBytesPerSec: %d\n"
"nBlockAlign: %d\n"
"nChannels: %d\n"
"nSamplesPerSec: %d\n"
"wBitsPerSample: %d\n"
"wFormatTag: %d\n",
theFilename.c_str(),
aWaveFormat.wf.nAvgBytesPerSec,
aWaveFormat.wf.nBlockAlign,
aWaveFormat.wf.nChannels,
aWaveFormat.wf.nSamplesPerSec,
aWaveFormat.wBitsPerSample,
aWaveFormat.wf.wFormatTag);
MessageBox(0,xmsg,xmsg,MB_OK);
HRESULT error=mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL);
switch (error)
{
case DSERR_ALLOCATED:MessageBox(0,"DSERR_ALLOCATED","Ugh",MB_OK);break;
case DSERR_BADFORMAT:MessageBox(0,"DSERR_BADFORMAT","Ugh",MB_OK);break;
case DSERR_INVALIDPARAM:MessageBox(0,"DSERR_INVALIDPARAM(XXX)","Ugh",MB_OK);break;
case DSERR_NOAGGREGATION:MessageBox(0,"DSERR_NOAGGREGATION","Ugh",MB_OK);break;
case DSERR_OUTOFMEMORY:MessageBox(0,"DSERR_OUTOFMEMORY","Ugh",MB_OK);break;
case DSERR_UNINITIALIZED:MessageBox(0,"DSERR_UNINITIALIZED","Ugh",MB_OK);break;
case DSERR_UNSUPPORTED:MessageBox(0,"DSERR_UNSUPPORTED","Ugh",MB_OK);break;
}
exit(0);
*/
// Delete
gFMod->FSOUND_Sample_Free(aSample);
return false;
}
void* lpvPtr;
DWORD dwBytes;
if (mSourceSounds[theSfxID]->Lock(0, aLenBytes, &lpvPtr, &dwBytes, NULL, NULL, 0) == DS_OK)
{
void* aPtr1;
void* aPtr2;
uint aLen1;
uint aLen2;
if (gFMod->FSOUND_Sample_Lock(aSample, 0, aLenBytes, &aPtr1, &aPtr2, &aLen1, &aLen2))
{
memcpy(lpvPtr, aPtr1, aLen1);
mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL);
gFMod->FSOUND_Sample_Unlock(aSample, aPtr1, aPtr2, aLen1, aLen2);
}
}
else
{
}
mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, 0);
gFMod->FSOUND_Sample_Free(aSample);
return true;
}
#ifdef USE_OGG_LIB
static int p_fseek64_wrap(PFILE *f,ogg_int64_t off,int whence){
if(f==NULL)return(-1);
return p_fseek(f,(long)off,whence);
}
int ov_pak_open(PFILE *f,OggVorbis_File *vf,char *initial,long ibytes){
ov_callbacks callbacks = {
(size_t (*)(void *, size_t, size_t, void *)) p_fread,
(int (*)(void *, ogg_int64_t, int)) p_fseek64_wrap,
(int (*)(void *)) p_fclose,
(long (*)(void *)) p_ftell
};
return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
}
bool DSoundManager::LoadOGGSound(unsigned int theSfxID, const std::string& theFilename)
{
OggVorbis_File vf;
int current_section;
PFILE *aFile = p_fopen(theFilename.c_str(),"rb");
if (aFile==NULL)
return false;
if(ov_pak_open(aFile, &vf, NULL, 0) < 0)
{
p_fclose(aFile);
return false;
}
vorbis_info *anInfo = ov_info(&vf,-1);
PCMWAVEFORMAT aWaveFormat;
DSBUFFERDESC aBufferDesc;
// Set up wave format structure.
memset(&aWaveFormat, 0, sizeof(PCMWAVEFORMAT));
aWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
aWaveFormat.wf.nChannels = anInfo->channels;
aWaveFormat.wf.nSamplesPerSec = anInfo->rate;
aWaveFormat.wBitsPerSample = 16;
aWaveFormat.wf.nBlockAlign = aWaveFormat.wf.nChannels*aWaveFormat.wBitsPerSample/8;
aWaveFormat.wf.nAvgBytesPerSec = aWaveFormat.wf.nSamplesPerSec * aWaveFormat.wf.nBlockAlign;
int aLenBytes = (int) (ov_pcm_total(&vf,-1) * aWaveFormat.wf.nBlockAlign);
memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
mSourceDataSizes[theSfxID] = aLenBytes;
//FUNK
aBufferDesc.dwSize = sizeof(DSBUFFERDESC);
aBufferDesc.dwFlags = SOUND_FLAGS;
aBufferDesc.dwBufferBytes = aLenBytes;
aBufferDesc.lpwfxFormat =(LPWAVEFORMATEX)&aWaveFormat;
if (mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL) != DS_OK)
{
ov_clear(&vf);
return false;
}
char* aBuf;
DWORD dwBytes;
if (mSourceSounds[theSfxID]->Lock(0, aLenBytes, (LPVOID*)&aBuf, &dwBytes, NULL, NULL, 0) != DS_OK)
{
ov_clear(&vf);
return false;
}
char *aPtr = aBuf;
int aNumBytes = dwBytes;
while(aNumBytes > 0)
{
long ret=ov_read(&vf,aPtr,aNumBytes,¤t_section);
if (ret == 0)
break;
else if (ret < 0)
break;
else
{
aPtr += ret;
aNumBytes -= ret;
}
}
mSourceSounds[theSfxID]->Unlock(aBuf, dwBytes, NULL, 0);
ov_clear(&vf);
return aNumBytes==0;
}
#else
bool DSoundManager::LoadOGGSound(unsigned int theSfxID, const std::string& theFilename)
{
return false;
}
#endif
bool DSoundManager::LoadAUSound(unsigned int theSfxID, const std::string& theFilename)
{
PFILE* fp;
fp = p_fopen(theFilename.c_str(), "rb");
if (fp <= 0)
return false;
char aHeaderId[5];
aHeaderId[4] = '\0';
p_fread(aHeaderId, 1, 4, fp);
if (!strcmp(aHeaderId, ".snd") == 0)
return false;
ulong aHeaderSize;
p_fread(&aHeaderSize, 4, 1, fp);
aHeaderSize = LONG_BIGE_TO_NATIVE(aHeaderSize);
ulong aDataSize;
p_fread(&aDataSize, 4, 1, fp);
aDataSize = LONG_BIGE_TO_NATIVE(aDataSize);
ulong anEncoding;
p_fread(&anEncoding, 4, 1, fp);
anEncoding = LONG_BIGE_TO_NATIVE(anEncoding);
ulong aSampleRate;
p_fread(&aSampleRate, 4, 1, fp);
aSampleRate = LONG_BIGE_TO_NATIVE(aSampleRate);
ulong aChannelCount;
p_fread(&aChannelCount, 4, 1, fp);
aChannelCount = LONG_BIGE_TO_NATIVE(aChannelCount);
p_fseek(fp, aHeaderSize, SEEK_SET);
bool ulaw = false;
ulong aSrcBitCount = 8;
ulong aBitCount = 16;
switch (anEncoding)
{
case 1:
aSrcBitCount = 8;
aBitCount = 16;
ulaw = true;
break;
case 2:
aSrcBitCount = 8;
aBitCount = 8;
break;
/*
Support these formats?
case 3:
aBitCount = 16;
break;
case 4:
aBitCount = 24;
break;
case 5:
aBitCount = 32;
break;*/
default:
return false;
}
ulong aDestSize = aDataSize * aBitCount/aSrcBitCount;
mSourceDataSizes[theSfxID] = aDestSize;
PCMWAVEFORMAT aWaveFormat;
DSBUFFERDESC aBufferDesc;
// Set up wave format structure.
memset(&aWaveFormat, 0, sizeof(PCMWAVEFORMAT));
aWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
aWaveFormat.wf.nChannels = (WORD) aChannelCount;
aWaveFormat.wf.nSamplesPerSec = aSampleRate;
aWaveFormat.wf.nBlockAlign = (WORD) (aChannelCount*aBitCount/8);
aWaveFormat.wf.nAvgBytesPerSec =
aWaveFormat.wf.nSamplesPerSec * aWaveFormat.wf.nBlockAlign;
aWaveFormat.wBitsPerSample = (WORD) aBitCount;
// Set up DSBUFFERDESC structure.
memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
aBufferDesc.dwSize = sizeof(DSBUFFERDESC);
//aBufferDesc.dwFlags = DSBCAPS_CTRL3D;
aBufferDesc.dwFlags = SOUND_FLAGS;
aBufferDesc.dwBufferBytes = aDestSize;
aBufferDesc.lpwfxFormat = (LPWAVEFORMATEX)&aWaveFormat;
if (mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL) != DS_OK)
{
p_fclose(fp);
return false;
}
void* lpvPtr;
DWORD dwBytes;
if (mSourceSounds[theSfxID]->Lock(0, aDestSize, &lpvPtr, &dwBytes, NULL, NULL, 0) != DS_OK)
{
p_fclose(fp);
return false;
}
uchar* aSrcBuffer = new uchar[aDataSize];
int aReadSize = p_fread(aSrcBuffer, 1, aDataSize, fp);
p_fclose(fp);
if (ulaw)
{
short* aDestBuffer = (short*) lpvPtr;
for (ulong i = 0; i < aDataSize; i++)
{
int ch = aSrcBuffer[i];
int sign = (ch < 128) ? -1 : 1;
ch = ch | 0x80;
if (ch > 239)
ch = ((0xF0 | 15) - ch) * 2;
else if (ch > 223)
ch = (((0xE0 | 15) - ch) * 4) + 32;
else if (ch > 207)
ch = (((0xD0 | 15) - ch) * 8) + 96;
else if (ch > 191)
ch = (((0xC0 | 15) - ch) * 16) + 224;
else if (ch > 175)
ch = (((0xB0 | 15) - ch) * 32) + 480;
else if (ch > 159)
ch = (((0xA0 | 15) - ch) * 64) + 992;
else if (ch > 143)
ch = (((0x90 | 15) - ch) * 128) + 2016;
else if (ch > 128)
ch = (((0x80 | 15) - ch) * 256) + 4064;
else
ch = 0xff;
aDestBuffer[i] = sign * ch * 4;
}
}
else
memcpy(lpvPtr, aSrcBuffer, aDataSize);
delete [] aSrcBuffer;
if (mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL) != DS_OK)
return false;
if (aReadSize != aDataSize)
return false;
return true;
}
bool DSoundManager::LoadSound(unsigned int theSfxID, const std::string& theFilename)
{
if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
return false;
ReleaseSound(theSfxID);
if (!mDirectSound)
return true; // sounds just won't play, but this is not treated as a failure condition
mSourceFileNames[theSfxID] = theFilename;
std::string aFilename = theFilename;
std::string aCachedName;
if ((aFilename.length() > 2) && (aFilename[0] != '\\') && (aFilename[0] != '/') &&
(aFilename[1] != ':'))
{
// Not an absolute path
aCachedName = GetAppDataFolder() + "cached\\" + aFilename + ".wav";
if (LoadWAVSound(theSfxID, aCachedName))
return true;
MkDir(GetFileDir(aCachedName));
}
if (LoadWAVSound(theSfxID, aFilename + ".wav"))
return true;
if (mHaveFMod)
{
if (LoadFModSound(theSfxID, aFilename + ".mp3"))
{
WriteWAV(theSfxID, aCachedName, aFilename + ".mp3");
return true;
}
#ifndef USE_OGG_LIB
if (LoadFModSound(theSfxID, aFilename + ".ogg"))
{
WriteWAV(theSfxID, aCachedName, aFilename + ".ogg");
return true;
}
#endif
}
#ifdef USE_OGG_LIB
if (LoadOGGSound(theSfxID, aFilename + ".ogg"))
{
WriteWAV(theSfxID, aCachedName, aFilename + ".ogg");
return true;
}
#endif
if (LoadAUSound(theSfxID, aFilename + ".au"))
{
WriteWAV(theSfxID, aCachedName, aFilename + ".au");
return true;
}
return false;
}
int DSoundManager::LoadSound(const std::string& theFilename)
{
int i;
for (i = 0; i < MAX_SOURCE_SOUNDS; i++)
if (mSourceFileNames[i] == theFilename)
return i;
for (i = MAX_SOURCE_SOUNDS-1; i >= 0; i--)
{
if (mSourceSounds[i] == NULL)
{
if (!LoadSound(i, theFilename))
return -1;
else
return i;
}
}
return -1;
}
void DSoundManager::ReleaseSound(unsigned int theSfxID)
{
if (mSourceSounds[theSfxID] != NULL)
{
mSourceSounds[theSfxID]->Release();
mSourceSounds[theSfxID] = NULL;
mSourceFileNames[theSfxID] = "";
}
}
int DSoundManager::GetFreeSoundId()
{
for (int i=0; i<MAX_SOURCE_SOUNDS; i++)
{
if (mSourceSounds[i]==NULL)
return i;
}
return -1;
}
int DSoundManager::GetNumSounds()
{
int aCount = 0;
for (int i=0; i<MAX_SOURCE_SOUNDS; i++)
{
if (mSourceSounds[i]!=NULL)
aCount++;
}
return aCount;
}
bool DSoundManager::SetBaseVolume(unsigned int theSfxID, double theBaseVolume)
{
if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
return false;
mBaseVolumes[theSfxID] = theBaseVolume;
return true;
}
bool DSoundManager::SetBasePan(unsigned int theSfxID, int theBasePan)
{
if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
return false;
mBasePans[theSfxID] = theBasePan;
return true;
}
bool DSoundManager::GetTheFileTime(const std::string& theDepFile, FILETIME* theFileTime)
{
memset(theFileTime, 0, sizeof(FILETIME));
HANDLE aDepFileHandle = CreateFile(theDepFile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (aDepFileHandle == INVALID_HANDLE_VALUE)
return false;
GetFileTime(aDepFileHandle, NULL, NULL, theFileTime);
CloseHandle(aDepFileHandle);
return true;
}
bool DSoundManager::WriteWAV(unsigned int theSfxID, const std::string& theFilename, const std::string& theDepFile)
{
if ((theFilename.length() == 0) || (theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
return false;
ulong aDataSize = mSourceDataSizes[theSfxID];
void* lpvPtr;
DWORD dwBytes;
if (mSourceSounds[theSfxID]->Lock(0, aDataSize, &lpvPtr, &dwBytes, NULL, NULL, 0) != DS_OK)
return false;
FILE* fp;
fp = fopen(theFilename.c_str(), "wb");
if (fp <= 0)
{
mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL);
return false;
}
char aChunkType[5];
aChunkType[4] = '\0';
ulong aChunkSize = 4 + 8 + 16 + 8 + aDataSize;
fwrite("RIFF", 1, 4, fp);
fwrite(&aChunkSize, 4, 1, fp);
fwrite("WAVE", 1, 4, fp);
ulong aBufferSize;
mSourceSounds[theSfxID]->GetFormat(NULL, 0, &aBufferSize);
WAVEFORMATEX* aWaveFormat = (WAVEFORMATEX*) new char[aBufferSize];
memset(aWaveFormat, 0, sizeof(WAVEFORMATEX));
mSourceSounds[theSfxID]->GetFormat(aWaveFormat, aBufferSize, NULL);
ushort aFormatTag = 1;
ushort aChannelCount = aWaveFormat->nChannels;
ulong aSampleRate = aWaveFormat->nSamplesPerSec;
ushort aBitCount = aWaveFormat->wBitsPerSample;
ushort aBlockAlign = (aBitCount * aChannelCount) / 8;
ulong aBytesPerSec = aSampleRate * aBlockAlign;
delete aWaveFormat;
aChunkSize = 16;
fwrite("fmt ", 1, 4, fp);
fwrite(&aChunkSize, 1, 4, fp);
fwrite(&aFormatTag, 2, 1, fp);
fwrite(&aChannelCount, 2, 1, fp);
fwrite(&aSampleRate, 4, 1, fp);
fwrite(&aBytesPerSec, 4, 1, fp);
fwrite(&aBlockAlign, 2, 1, fp);
fwrite(&aBitCount, 2, 1, fp);
FILETIME aFileTime;
memset(&aFileTime, 0, sizeof(FILETIME));
GetTheFileTime(theDepFile, &aFileTime);
ushort aStrLen = theDepFile.length();
aChunkSize = 2 + aStrLen + sizeof(FILETIME);
fwrite("dep ", 1, 4, fp);
fwrite(&aChunkSize,4, 1, fp);
fwrite(&aStrLen, 2, 1, fp);
fwrite(theDepFile.c_str(), 1, aStrLen, fp);
fwrite(&aFileTime, sizeof(FILETIME), 1, fp);
aChunkSize = 1;
uchar anXor = 0xF7;
fwrite("xor ", 1, 4, fp);
fwrite(&aChunkSize, 4, 1, fp);
fwrite(&anXor, 1, 1, fp);
for (DWORD i = 0; i < dwBytes; i++)
((uchar*) lpvPtr)[i] ^= anXor;
fwrite("data", 1, 4, fp);
fwrite(&aDataSize, 4, 1, fp);
fwrite(lpvPtr, 1, aDataSize, fp);
fclose(fp);
for (DWORD i = 0; i < dwBytes; i++)
((uchar*) lpvPtr)[i] ^= anXor;
if (mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL) != DS_OK)
return false;
return true;
}
SoundInstance* DSoundManager::GetSoundInstance(unsigned int theSfxID)
{
if (theSfxID > MAX_SOURCE_SOUNDS)
return NULL;
int aFreeChannel = FindFreeChannel();
if (aFreeChannel < 0)
return NULL;
if (mDirectSound==NULL)
{
mPlayingSounds[aFreeChannel] = new DSoundInstance(this, NULL);
}
else
{
if (mSourceSounds[theSfxID] == NULL)
return NULL;
mPlayingSounds[aFreeChannel] = new DSoundInstance(this, mSourceSounds[theSfxID]);
}
mPlayingSounds[aFreeChannel]->SetBasePan(mBasePans[theSfxID]);
mPlayingSounds[aFreeChannel]->SetBaseVolume(mBaseVolumes[theSfxID]);
return mPlayingSounds[aFreeChannel];
}
void DSoundManager::ReleaseSounds()
{
for (int i = 0; i < MAX_SOURCE_SOUNDS; i++)
if (mSourceSounds[i] != NULL)
{
mSourceSounds[i]->Release();
mSourceSounds[i] = NULL;
}
}
void DSoundManager::ReleaseChannels()
{
for (int i = 0; i < MAX_CHANNELS; i++)
if (mPlayingSounds[i] != NULL)
{
delete mPlayingSounds[i];
mPlayingSounds[i] = NULL;
}
}
void DSoundManager::ReleaseFreeChannels()
{
for (int i = 0; i < MAX_CHANNELS; i++)
if (mPlayingSounds[i] != NULL && mPlayingSounds[i]->IsReleased())
{
delete mPlayingSounds[i];
mPlayingSounds[i] = NULL;
}
}
void DSoundManager::StopAllSounds()
{
for (int i = 0; i < MAX_CHANNELS; i++)
if (mPlayingSounds[i] != NULL)
{
bool isAutoRelease = mPlayingSounds[i]->mAutoRelease;
mPlayingSounds[i]->Stop();
mPlayingSounds[i]->mAutoRelease = isAutoRelease;
}
}
double DSoundManager::GetMasterVolume()
{
MIXERCONTROLDETAILS mcd;
MIXERCONTROLDETAILS_UNSIGNED mxcd_u;
MIXERLINECONTROLS mxlc;
MIXERCONTROL mlct;
MIXERLINE mixerLine;
HMIXER hmx;
MIXERCAPS pmxcaps;
mixerOpen((HMIXER*) &hmx, 0, 0, 0, MIXER_OBJECTF_MIXER);
mixerGetDevCaps(0, &pmxcaps, sizeof(pmxcaps));
mxlc.cbStruct = sizeof(mxlc);
mxlc.cbmxctrl = sizeof(mlct);
mxlc.pamxctrl = &mlct;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerLine.cbStruct = sizeof(mixerLine);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
mixerGetLineInfo((HMIXEROBJ) hmx, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE);
mxlc.dwLineID = mixerLine.dwLineID;
mixerGetLineControls((HMIXEROBJ) hmx, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
mcd.cbStruct = sizeof(mcd);
mcd.dwControlID = mlct.dwControlID;
mcd.cChannels = 1;
mcd.cMultipleItems = 0;
mcd.cbDetails = sizeof(mxcd_u);
mcd.paDetails = &mxcd_u;
mixerGetControlDetails((HMIXEROBJ) hmx, &mcd, 0L);
mixerClose(hmx);
return mxcd_u.dwValue / (double) 0xFFFF;
}
void DSoundManager::SetMasterVolume(double theVolume)
{
MIXERCONTROLDETAILS mcd;
MIXERCONTROLDETAILS_UNSIGNED mxcd_u;
MIXERLINECONTROLS mxlc;
MIXERCONTROL mlct;
MIXERLINE mixerLine;
HMIXER hmx;
MIXERCAPS pmxcaps;
mixerOpen((HMIXER*) &hmx, 0, 0, 0, MIXER_OBJECTF_MIXER);
mixerGetDevCaps(0, &pmxcaps, sizeof(pmxcaps));
mxlc.cbStruct = sizeof(mxlc);
mxlc.cbmxctrl = sizeof(mlct);
mxlc.pamxctrl = &mlct;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerLine.cbStruct = sizeof(mixerLine);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
mixerGetLineInfo((HMIXEROBJ) hmx, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE);
mxlc.dwLineID = mixerLine.dwLineID;
mixerGetLineControls((HMIXEROBJ) hmx, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
mcd.cbStruct = sizeof(mcd);
mcd.dwControlID = mlct.dwControlID;
mcd.cChannels = 1;
mcd.cMultipleItems = 0;
mcd.cbDetails = sizeof(mxcd_u);
mcd.paDetails = &mxcd_u;
mxcd_u.dwValue = (int) (0xFFFF * theVolume);
mixerSetControlDetails((HMIXEROBJ) hmx, &mcd, 0L);
mixerClose(hmx);
}
void DSoundManager::Flush()
{
}
void DSoundManager::SetCooperativeWindow(HWND theHWnd, bool isWindowed)
{
if (mDirectSound != NULL)
mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
/*
if (isWindowed==true) mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
else mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_EXCLUSIVE);
*/
}
#undef SOUND_FLAGS