mirror of
https://github.com/galaxyhaxz/devilution
synced 2024-11-14 16:29:02 +00:00
510 lines
10 KiB
C++
510 lines
10 KiB
C++
|
#include "diablo.h"
|
||
|
#include "../3rdParty/Storm/Source/storm.h"
|
||
|
|
||
|
IDirectSoundBuffer *DSBs[8];
|
||
|
IDirectSound *sglpDS;
|
||
|
char gbSndInited;
|
||
|
long sglMusicVolume;
|
||
|
long sglSoundVolume;
|
||
|
HMODULE hDsound_dll; // idb
|
||
|
HANDLE sghMusic;
|
||
|
IDirectSoundBuffer *sglpDSB;
|
||
|
|
||
|
/* data */
|
||
|
|
||
|
char gbMusicOn = 1; // weak
|
||
|
char gbSoundOn = 1; // weak
|
||
|
char gbDupSounds = 1; // weak
|
||
|
int sgnMusicTrack = 6;
|
||
|
char *sgszMusicTracks[6] =
|
||
|
{
|
||
|
"Music\\DTowne.wav",
|
||
|
"Music\\DLvlA.wav",
|
||
|
"Music\\DLvlB.wav",
|
||
|
"Music\\DLvlC.wav",
|
||
|
"Music\\DLvlD.wav",
|
||
|
"Music\\Dintro.wav"
|
||
|
};
|
||
|
char unk_volume[4][2] =
|
||
|
{
|
||
|
{ 15, -16 },
|
||
|
{ 15, -16 },
|
||
|
{ 30, -31 },
|
||
|
{ 30, -31 }
|
||
|
};
|
||
|
|
||
|
void snd_update(BOOL bStopAll)
|
||
|
{
|
||
|
int i;
|
||
|
HRESULT hDSVal;
|
||
|
DWORD dwStatus;
|
||
|
|
||
|
for(i = 0; (DWORD)i < 8; i++) {
|
||
|
if(DSBs[i] == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
if(!bStopAll) {
|
||
|
hDSVal = DSBs[i]->GetStatus(&dwStatus);
|
||
|
if(hDSVal == DS_OK && dwStatus == DSBSTATUS_PLAYING) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
DSBs[i]->Stop();
|
||
|
DSBs[i]->Release();
|
||
|
DSBs[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static IDirectSoundBuffer *sound_dup_channel(IDirectSoundBuffer *pDSB)
|
||
|
{
|
||
|
int i;
|
||
|
HRESULT hDSVal;
|
||
|
|
||
|
if(!gbDupSounds) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
for(i = 0; (DWORD)i < 8; i++) {
|
||
|
if(DSBs[i] == NULL) {
|
||
|
hDSVal = sglpDS->DuplicateSoundBuffer(pDSB, &DSBs[i]);
|
||
|
if(hDSVal == DS_OK) {
|
||
|
return DSBs[i];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void snd_get_volume(const char *pszKey, long *plVolume)
|
||
|
{
|
||
|
DWORD dwTemp;
|
||
|
|
||
|
dwTemp = *plVolume;
|
||
|
if(!SRegLoadValue("Diablo", pszKey, 0, &dwTemp)) {
|
||
|
dwTemp = VOLUME_MAX;
|
||
|
}
|
||
|
*plVolume = dwTemp;
|
||
|
|
||
|
if(*plVolume < VOLUME_MIN) {
|
||
|
*plVolume = VOLUME_MIN;
|
||
|
} else if(*plVolume > VOLUME_MAX) {
|
||
|
*plVolume = VOLUME_MAX;
|
||
|
}
|
||
|
|
||
|
*plVolume -= *plVolume % 100;
|
||
|
}
|
||
|
|
||
|
static void snd_set_volume(const char *pszKey, long lVolume)
|
||
|
{
|
||
|
SRegSaveValue("Diablo", pszKey, 0, lVolume);
|
||
|
}
|
||
|
|
||
|
static BOOL sound_file_reload(TSnd *pSnd, IDirectSoundBuffer *pDSB)
|
||
|
{
|
||
|
BOOL rv;
|
||
|
HRESULT hDSVal;
|
||
|
HANDLE hsFile;
|
||
|
DWORD dwAudioBytes1, dwAudioBytes2;
|
||
|
void *vAudioPtr1, *vAudioPtr2;
|
||
|
|
||
|
/// ASSERT: assert(pSnd);
|
||
|
/// ASSERT: assert(pDSB);
|
||
|
|
||
|
if(pDSB->Restore()) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
rv = FALSE;
|
||
|
WOpenFile(pSnd->sound_path, &hsFile, 0);
|
||
|
WSetFilePointer(hsFile, pSnd->chunk.dwOffset, NULL, 0);
|
||
|
|
||
|
hDSVal = pDSB->Lock(0, pSnd->chunk.dwSize, &vAudioPtr1, &dwAudioBytes1, &vAudioPtr2, &dwAudioBytes2, 0);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
#ifdef _DEBUG
|
||
|
DSErrMsg(hDSVal, 163, "C:\\Diablo\\Direct\\SOUND.CPP");
|
||
|
#endif
|
||
|
} else {
|
||
|
WReadFile(hsFile, (char *)vAudioPtr1, dwAudioBytes1);
|
||
|
hDSVal = pDSB->Unlock(vAudioPtr1, dwAudioBytes1, vAudioPtr2, dwAudioBytes2);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
#ifdef _DEBUG
|
||
|
DSErrMsg(hDSVal, 169, "C:\\Diablo\\Direct\\SOUND.CPP");
|
||
|
#endif
|
||
|
} else {
|
||
|
rv = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WCloseFile(hsFile);
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
void snd_stop_snd(TSnd *pSnd)
|
||
|
{
|
||
|
if(pSnd == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
if(pSnd->DSB == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pSnd->DSB->Stop();
|
||
|
}
|
||
|
|
||
|
BOOL snd_playing(TSnd *pSnd)
|
||
|
{
|
||
|
HRESULT hDSVal;
|
||
|
DWORD dwStatus;
|
||
|
|
||
|
if(pSnd == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
if(pSnd->DSB == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
hDSVal = pSnd->DSB->GetStatus(&dwStatus);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
#ifdef _DEBUG
|
||
|
DSErrMsg(hDSVal, 195, "C:\\Diablo\\Direct\\SOUND.CPP");
|
||
|
#endif
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return dwStatus == DSBSTATUS_PLAYING;
|
||
|
}
|
||
|
|
||
|
void snd_play_snd(TSnd *pSnd, long lVolume, long lPan)
|
||
|
{
|
||
|
DWORD dwTicks;
|
||
|
HRESULT hDSVal;
|
||
|
IDirectSoundBuffer *pDSB;
|
||
|
|
||
|
if(pSnd == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
if(!gbSoundOn) {
|
||
|
return;
|
||
|
}
|
||
|
pDSB = pSnd->DSB;
|
||
|
if(pDSB == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
dwTicks = GetTickCount();
|
||
|
if(dwTicks - pSnd->start_tc < 80) {
|
||
|
GetTickCount(); /// BUGFIX: call has no purpose
|
||
|
return;
|
||
|
}
|
||
|
if(snd_playing(pSnd)) {
|
||
|
pDSB = sound_dup_channel(pSnd->DSB);
|
||
|
if(pDSB == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lVolume += sglSoundVolume;
|
||
|
if(lVolume < VOLUME_MIN) {
|
||
|
lVolume = VOLUME_MIN;
|
||
|
} else if(lVolume > VOLUME_MAX) {
|
||
|
lVolume = VOLUME_MAX;
|
||
|
}
|
||
|
|
||
|
hDSVal = pDSB->SetVolume(lVolume);
|
||
|
#ifdef _DEBUG
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 235, "C:\\Diablo\\Direct\\SOUND.CPP");
|
||
|
}
|
||
|
#endif
|
||
|
hDSVal = pDSB->SetPan(lPan);
|
||
|
#ifdef _DEBUG
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 238, "C:\\Diablo\\Direct\\SOUND.CPP");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
hDSVal = pDSB->Play(0, 0, 0);
|
||
|
if(hDSVal != DSERR_BUFFERLOST) {
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 261, "C:\\Src\\Diablo\\Source\\SOUND.CPP");
|
||
|
}
|
||
|
} else if(sound_file_reload(pSnd, pDSB)) {
|
||
|
hDSVal = pDSB->Play(0, 0, 0);
|
||
|
}
|
||
|
|
||
|
pSnd->start_tc = dwTicks;
|
||
|
}
|
||
|
|
||
|
static void sound_CreateSoundBuffer(TSnd *pSnd)
|
||
|
{
|
||
|
HRESULT hDSVal;
|
||
|
DSBUFFERDESC dsbd;
|
||
|
|
||
|
/// ASSERT: assert(sglpDS);
|
||
|
|
||
|
memset(&dsbd, 0, sizeof(dsbd));
|
||
|
dsbd.dwSize = sizeof(dsbd);
|
||
|
dsbd.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_STATIC;
|
||
|
dsbd.dwBufferBytes = pSnd->chunk.dwSize;
|
||
|
dsbd.lpwfxFormat = &pSnd->fmt;
|
||
|
|
||
|
hDSVal = sglpDS->CreateSoundBuffer(&dsbd, &pSnd->DSB, NULL);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 282, "C:\\Src\\Diablo\\Source\\SOUND.CPP");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TSnd *sound_file_load(const char *pszFile)
|
||
|
{
|
||
|
HRESULT hDSVal;
|
||
|
HANDLE hsFile;
|
||
|
DWORD dwAudioBytes1, dwAudioBytes2;
|
||
|
void *vAudioPtr1, *vAudioPtr2;
|
||
|
TSnd *pSnd;
|
||
|
BYTE *p;
|
||
|
|
||
|
if(sglpDS == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
WOpenFile((char *)pszFile, &hsFile, 0);
|
||
|
|
||
|
pSnd = (TSnd *)DiabloAllocPtr(sizeof(*pSnd));
|
||
|
memset(pSnd, 0, sizeof(*pSnd));
|
||
|
pSnd->sound_path = (char *)pszFile;
|
||
|
pSnd->start_tc = GetTickCount() - 81;
|
||
|
|
||
|
p = (BYTE *)LoadWaveFile(hsFile, &pSnd->fmt, &pSnd->chunk);
|
||
|
if(p == NULL) {
|
||
|
app_fatal("Invalid sound format on file %s", pSnd->sound_path);
|
||
|
}
|
||
|
|
||
|
sound_CreateSoundBuffer(pSnd);
|
||
|
|
||
|
hDSVal = pSnd->DSB->Lock(0, pSnd->chunk.dwSize, &vAudioPtr1, &dwAudioBytes1, &vAudioPtr2, &dwAudioBytes2, 0);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 318, "C:\\Src\\Diablo\\Source\\SOUND.CPP");
|
||
|
}
|
||
|
|
||
|
memcpy(vAudioPtr1, &p[pSnd->chunk.dwOffset], dwAudioBytes1);
|
||
|
|
||
|
hDSVal = pSnd->DSB->Unlock(vAudioPtr1, dwAudioBytes1, vAudioPtr2, dwAudioBytes2);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 325, "C:\\Src\\Diablo\\Source\\SOUND.CPP");
|
||
|
}
|
||
|
|
||
|
MemFreeDbg(p);
|
||
|
WCloseFile(hsFile);
|
||
|
return pSnd;
|
||
|
}
|
||
|
|
||
|
void sound_file_cleanup(TSnd *pSnd)
|
||
|
{
|
||
|
if(pSnd != NULL) {
|
||
|
if(pSnd->DSB != NULL) {
|
||
|
pSnd->DSB->Stop();
|
||
|
pSnd->DSB->Release();
|
||
|
pSnd->DSB = NULL;
|
||
|
}
|
||
|
MemFreeDbg(pSnd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void sound_create_primary_buffer(HANDLE hMusic)
|
||
|
{
|
||
|
HRESULT hDSVal;
|
||
|
DSCAPS caps;
|
||
|
DSBUFFERDESC dsbd;
|
||
|
WAVEFORMATEX fmt;
|
||
|
|
||
|
/// ASSERT: assert(sglpDS);
|
||
|
|
||
|
if(hMusic == NULL) {
|
||
|
memset(&dsbd, 0, sizeof(dsbd));
|
||
|
dsbd.dwSize = sizeof(dsbd);
|
||
|
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||
|
hDSVal = sglpDS->CreateSoundBuffer(&dsbd, &sglpDSB, NULL);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 375, "C:\\Src\\Diablo\\Source\\SOUND.CPP");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(sglpDSB == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
caps.dwSize = sizeof(caps);
|
||
|
hDSVal = sglpDS->GetCaps(&caps);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 383, "C:\\Src\\Diablo\\Source\\SOUND.CPP");
|
||
|
}
|
||
|
|
||
|
if(hMusic == NULL || !LoadWaveFormat(hMusic, &fmt)) {
|
||
|
memset(&fmt, 0, sizeof(fmt));
|
||
|
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||
|
fmt.nSamplesPerSec = 22050;
|
||
|
fmt.wBitsPerSample = 16;
|
||
|
fmt.nChannels = 2;
|
||
|
fmt.cbSize = 0;
|
||
|
}
|
||
|
fmt.nChannels = 2;
|
||
|
fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
|
||
|
fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
|
||
|
hDSVal = sglpDSB->SetFormat(&fmt);
|
||
|
#ifdef _DEBUG
|
||
|
if(hDSVal != DS_OK && hDSVal != DSERR_BADFORMAT) {
|
||
|
if(hDSVal != DS_OK) {
|
||
|
DSErrMsg(hDSVal, 383, "C:\\Diablo\\Direct\\SOUND.CPP");
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static HRESULT sound_DirectSoundCreate(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter)
|
||
|
{
|
||
|
DSCREATEPROC dscp;
|
||
|
|
||
|
if(hDsound_dll == NULL) {
|
||
|
hDsound_dll = LoadLibrary("dsound.dll");
|
||
|
if(hDsound_dll == NULL) {
|
||
|
ErrDlg(IDD_DIALOG5, GetLastError(), "C:\\Src\\Diablo\\Source\\SOUND.CPP", 422);
|
||
|
}
|
||
|
}
|
||
|
dscp = (DSCREATEPROC)GetProcAddress(hDsound_dll, "DirectSoundCreate");
|
||
|
if(dscp == NULL) {
|
||
|
ErrDlg(IDD_DIALOG5, GetLastError(), "C:\\Src\\Diablo\\Source\\SOUND.CPP", 427);
|
||
|
}
|
||
|
|
||
|
return dscp(lpGUID, lplpDS, pUnkOuter);
|
||
|
}
|
||
|
|
||
|
void snd_init(HWND hWnd)
|
||
|
{
|
||
|
HRESULT hDSVal;
|
||
|
BOOL bSuccess;
|
||
|
|
||
|
snd_get_volume("Sound Volume", &sglSoundVolume);
|
||
|
gbSoundOn = sglSoundVolume > VOLUME_MIN;
|
||
|
snd_get_volume("Music Volume", &sglMusicVolume);
|
||
|
gbMusicOn = sglMusicVolume > VOLUME_MIN;
|
||
|
|
||
|
/// ASSERT: assert(! sglpDS);
|
||
|
hDSVal = sound_DirectSoundCreate(NULL, &sglpDS, NULL);
|
||
|
if(hDSVal != DS_OK) {
|
||
|
sglpDS = NULL;
|
||
|
}
|
||
|
if(sglpDS != NULL && sglpDS->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE) == DS_OK) {
|
||
|
sound_create_primary_buffer(NULL);
|
||
|
}
|
||
|
|
||
|
bSuccess = SVidInitialize(sglpDS);
|
||
|
/// ASSERT: assert(! sglpDS || bSuccess);
|
||
|
|
||
|
bSuccess = SFileDdaInitialize(sglpDS);
|
||
|
/// ASSERT: assert(! sglpDS || bSuccess);
|
||
|
|
||
|
gbSndInited = sglpDS != NULL;
|
||
|
}
|
||
|
|
||
|
void sound_cleanup()
|
||
|
{
|
||
|
snd_update(TRUE);
|
||
|
SVidDestroy();
|
||
|
SFileDdaDestroy();
|
||
|
|
||
|
if(sglpDS != NULL) {
|
||
|
sglpDS->Release();
|
||
|
sglpDS = NULL;
|
||
|
}
|
||
|
if(gbSndInited) {
|
||
|
gbSndInited = 0;
|
||
|
snd_set_volume("Sound Volume", sglSoundVolume);
|
||
|
snd_set_volume("Music Volume", sglMusicVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void music_stop()
|
||
|
{
|
||
|
if(sghMusic != NULL) {
|
||
|
SFileDdaEnd(sghMusic);
|
||
|
SFileCloseFile(sghMusic);
|
||
|
sghMusic = NULL;
|
||
|
sgnMusicTrack = NUM_MUSIC;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void music_start(int nTrack)
|
||
|
{
|
||
|
BOOL bSuccess;
|
||
|
|
||
|
/// ASSERT: assert((DWORD) nTrack < NUM_MUSIC);
|
||
|
|
||
|
music_stop();
|
||
|
|
||
|
if(sglpDS == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
if(!gbMusicOn) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
SFileEnableDirectAccess(FALSE);
|
||
|
#endif
|
||
|
bSuccess = SFileOpenFile(sgszMusicTracks[nTrack], &sghMusic);
|
||
|
#ifdef _DEBUG
|
||
|
SFileEnableDirectAccess(TRUE);
|
||
|
#endif
|
||
|
|
||
|
sound_create_primary_buffer(sghMusic);
|
||
|
|
||
|
if(!bSuccess) {
|
||
|
sghMusic = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SFileDdaBeginEx(sghMusic, 0x40000, 0x40000, 0, sglMusicVolume, 0, 0);
|
||
|
sgnMusicTrack = nTrack;
|
||
|
}
|
||
|
|
||
|
void sound_disable_music(BOOL disable)
|
||
|
{
|
||
|
if(disable) {
|
||
|
music_stop();
|
||
|
} else if(sgnMusicTrack != NUM_MUSIC) {
|
||
|
music_start(sgnMusicTrack);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long sound_get_or_set_music_volume(long lVolume)
|
||
|
{
|
||
|
if(lVolume == 1) {
|
||
|
return sglMusicVolume;
|
||
|
}
|
||
|
|
||
|
/// ASSERT: assert(lVolume >= VOLUME_MIN);
|
||
|
/// ASSERT: assert(lVolume <= VOLUME_MAX);
|
||
|
sglMusicVolume = lVolume;
|
||
|
|
||
|
if(sghMusic != NULL) {
|
||
|
SFileDdaSetVolume(sghMusic, sglMusicVolume, 0);
|
||
|
}
|
||
|
|
||
|
return sglMusicVolume;
|
||
|
}
|
||
|
|
||
|
long sound_get_or_set_sound_volume(long lVolume)
|
||
|
{
|
||
|
if(lVolume == 1) {
|
||
|
return sglSoundVolume;
|
||
|
}
|
||
|
|
||
|
/// ASSERT: assert(lVolume >= VOLUME_MIN);
|
||
|
/// ASSERT: assert(lVolume <= VOLUME_MAX);
|
||
|
sglSoundVolume = lVolume;
|
||
|
|
||
|
return sglSoundVolume;
|
||
|
}
|