1
0
Fork 0
mirror of https://github.com/galaxyhaxz/devilution synced 2024-11-14 16:29:02 +00:00
devilution/2020_03_31/Source/sound.cpp
PrisonOfMirrors b720183846 initial up
2020-11-28 18:24:54 -06:00

509 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;
}