Migrate sound to SDL (#70)

This commit is contained in:
Alexander Batalov 2022-07-12 12:09:53 +03:00 committed by GitHub
parent bbfd7785b5
commit 07d1f9fd81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 639 additions and 687 deletions

View File

@ -233,7 +233,8 @@ add_executable(${EXECUTABLE_NAME} WIN32 MACOSX_BUNDLE
) )
target_sources(${EXECUTABLE_NAME} PUBLIC target_sources(${EXECUTABLE_NAME} PUBLIC
"src/dsound_compat.h" "src/audio_engine.cc"
"src/audio_engine.h"
"src/fps_limiter.cc" "src/fps_limiter.cc"
"src/fps_limiter.h" "src/fps_limiter.h"
"src/platform_compat.cc" "src/platform_compat.cc"

432
src/audio_engine.cc Normal file
View File

@ -0,0 +1,432 @@
#include "audio_engine.h"
#include <string.h>
#include <mutex>
#include <SDL.h>
#define AUDIO_ENGINE_SOUND_BUFFERS 8
struct AudioEngineSoundBuffer {
bool active;
unsigned int size;
int bitsPerSample;
int channels;
int rate;
void* data;
int volume;
bool playing;
bool looping;
unsigned int pos;
SDL_AudioStream* stream;
std::recursive_mutex mutex;
};
extern bool gProgramIsActive;
static bool soundBufferIsValid(int soundBufferIndex);
static void audioEngineMixin(void* userData, Uint8* stream, int length);
static SDL_AudioSpec gAudioEngineSpec;
static SDL_AudioDeviceID gAudioEngineDeviceId = -1;
static AudioEngineSoundBuffer gAudioEngineSoundBuffers[AUDIO_ENGINE_SOUND_BUFFERS];
static bool soundBufferIsValid(int soundBufferIndex)
{
return soundBufferIndex >= 0 && soundBufferIndex < AUDIO_ENGINE_SOUND_BUFFERS;
}
static void audioEngineMixin(void* userData, Uint8* stream, int length)
{
memset(stream, gAudioEngineSpec.silence, length);
if (!gProgramIsActive) {
return;
}
for (int index = 0; index < AUDIO_ENGINE_SOUND_BUFFERS; index++) {
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[index]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (soundBuffer->active && soundBuffer->playing) {
int srcFrameSize = soundBuffer->bitsPerSample / 8 * soundBuffer->channels;
unsigned char buffer[1024];
int pos = 0;
while (pos < length) {
int remaining = length - pos;
if (remaining > sizeof(buffer)) {
remaining = sizeof(buffer);
}
// TODO: Make something better than frame-by-frame convertion.
SDL_AudioStreamPut(soundBuffer->stream, (unsigned char*)soundBuffer->data + soundBuffer->pos, srcFrameSize);
soundBuffer->pos += srcFrameSize;
int bytesRead = SDL_AudioStreamGet(soundBuffer->stream, buffer, remaining);
if (bytesRead == -1) {
break;
}
SDL_MixAudioFormat(stream + pos, buffer, gAudioEngineSpec.format, bytesRead, soundBuffer->volume);
if (soundBuffer->pos >= soundBuffer->size) {
if (soundBuffer->looping) {
soundBuffer->pos %= soundBuffer->size;
} else {
soundBuffer->playing = false;
break;
}
}
pos += bytesRead;
}
}
}
}
bool audioEngineInit()
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) {
return false;
}
SDL_AudioSpec desiredSpec;
desiredSpec.freq = 22050;
desiredSpec.format = AUDIO_S16;
desiredSpec.channels = 2;
desiredSpec.samples = 1024;
desiredSpec.callback = audioEngineMixin;
gAudioEngineDeviceId = SDL_OpenAudioDevice(NULL, 0, &desiredSpec, &gAudioEngineSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (gAudioEngineDeviceId == -1) {
return false;
}
SDL_PauseAudioDevice(gAudioEngineDeviceId, 0);
return true;
}
void audioEngineExit()
{
if (gAudioEngineDeviceId != -1) {
SDL_CloseAudioDevice(gAudioEngineDeviceId);
gAudioEngineDeviceId = -1;
}
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
void audioEnginePause()
{
if (gAudioEngineDeviceId != -1) {
SDL_PauseAudioDevice(gAudioEngineDeviceId, 1);
}
}
void audioEngineResume()
{
if (gAudioEngineDeviceId != -1) {
SDL_PauseAudioDevice(gAudioEngineDeviceId, 0);
}
}
int audioEngineCreateSoundBuffer(unsigned int size, int bitsPerSample, int channels, int rate)
{
for (int index = 0; index < AUDIO_ENGINE_SOUND_BUFFERS; index++) {
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[index]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
soundBuffer->active = true;
soundBuffer->size = size;
soundBuffer->bitsPerSample = bitsPerSample;
soundBuffer->channels = channels;
soundBuffer->rate = rate;
soundBuffer->volume = SDL_MIX_MAXVOLUME;
soundBuffer->playing = false;
soundBuffer->looping = false;
soundBuffer->pos = 0;
soundBuffer->data = malloc(size);
soundBuffer->stream = SDL_NewAudioStream(bitsPerSample == 16 ? AUDIO_S16 : AUDIO_S8, channels, rate, gAudioEngineSpec.format, gAudioEngineSpec.channels, gAudioEngineSpec.freq);
return index;
}
}
return -1;
}
bool audioEngineSoundBufferRelease(int soundBufferIndex)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
soundBuffer->active = false;
free(soundBuffer->data);
soundBuffer->data = NULL;
SDL_FreeAudioStream(soundBuffer->stream);
soundBuffer->stream = NULL;
return true;
}
bool audioEngineSoundBufferSetVolume(int soundBufferIndex, int volume)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
soundBuffer->volume = volume;
return true;
}
bool audioEngineSoundBufferGetVolume(int soundBufferIndex, int* volumePtr)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
*volumePtr = soundBuffer->volume;
return true;
}
bool audioEngineSoundBufferSetPan(int soundBufferIndex, int pan)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
// NOTE: Audio engine does not support sound panning. I'm not sure it's
// even needed. For now this value is silently ignored.
return true;
}
bool audioEngineSoundBufferPlay(int soundBufferIndex, unsigned int flags)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
soundBuffer->playing = true;
if ((flags & AUDIO_ENGINE_SOUND_BUFFER_PLAY_LOOPING) != 0) {
soundBuffer->looping = true;
}
return true;
}
bool audioEngineSoundBufferStop(int soundBufferIndex)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
soundBuffer->playing = false;
return true;
}
bool audioEngineSoundBufferGetCurrentPosition(int soundBufferIndex, unsigned int* readPosPtr, unsigned int* writePosPtr)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
if (readPosPtr != NULL) {
*readPosPtr = soundBuffer->pos;
}
if (writePosPtr != NULL) {
*writePosPtr = soundBuffer->pos;
if (soundBuffer->playing) {
// 15 ms lead
// See: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/mt708925(v=vs.85)#remarks
*writePosPtr += soundBuffer->rate / 150;
*writePosPtr %= soundBuffer->size;
}
}
return true;
}
bool audioEngineSoundBufferSetCurrentPosition(int soundBufferIndex, unsigned int pos)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
soundBuffer->pos = pos % soundBuffer->size;
return true;
}
bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, unsigned int writeBytes, void** audioPtr1, unsigned int* audioBytes1, void** audioPtr2, unsigned int* audioBytes2, unsigned int flags)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
if (audioBytes1 == NULL) {
return false;
}
if ((flags & AUDIO_ENGINE_SOUND_BUFFER_LOCK_FROM_WRITE_POS) != 0) {
if (!audioEngineSoundBufferGetCurrentPosition(soundBufferIndex, NULL, &writePos)) {
return false;
}
}
if ((flags & AUDIO_ENGINE_SOUND_BUFFER_LOCK_ENTIRE_BUFFER) != 0) {
writeBytes = soundBuffer->size;
}
if (writePos + writeBytes <= soundBuffer->size) {
*(unsigned char**)audioPtr1 = (unsigned char*)soundBuffer->data + writePos;
*audioBytes1 = writeBytes;
if (audioPtr2 != NULL) {
*audioPtr2 = NULL;
}
if (audioBytes2 != NULL) {
*audioBytes2 = 0;
}
} else {
unsigned int remainder = writePos + writeBytes - soundBuffer->size;
*(unsigned char**)audioPtr1 = (unsigned char*)soundBuffer->data + writePos;
*audioBytes1 = soundBuffer->size - writePos;
if (audioPtr2 != NULL) {
*(unsigned char**)audioPtr2 = (unsigned char*)soundBuffer->data;
}
if (audioBytes2 != NULL) {
*audioBytes2 = writeBytes - (soundBuffer->size - writePos);
}
}
// TODO: Mark range as locked.
return true;
}
bool audioEngineSoundBufferUnlock(int soundBufferIndex, void* audioPtr1, unsigned int audioBytes1, void* audioPtr2, unsigned int audioBytes2)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
// TODO: Mark range as unlocked.
return true;
}
bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* statusPtr)
{
if (!soundBufferIsValid(soundBufferIndex)) {
return false;
}
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[soundBufferIndex]);
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
if (!soundBuffer->active) {
return false;
}
if (statusPtr == NULL) {
return false;
}
*statusPtr = 0;
if (soundBuffer->playing) {
*statusPtr |= AUDIO_ENGINE_SOUND_BUFFER_STATUS_PLAYING;
if (soundBuffer->looping) {
*statusPtr |= AUDIO_ENGINE_SOUND_BUFFER_STATUS_LOOPING;
}
}
return true;
}

29
src/audio_engine.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef AUDIO_ENGINE_H
#define AUDIO_ENGINE_H
#define AUDIO_ENGINE_SOUND_BUFFER_LOCK_FROM_WRITE_POS 0x00000001
#define AUDIO_ENGINE_SOUND_BUFFER_LOCK_ENTIRE_BUFFER 0x00000002
#define AUDIO_ENGINE_SOUND_BUFFER_PLAY_LOOPING 0x00000001
#define AUDIO_ENGINE_SOUND_BUFFER_STATUS_PLAYING 0x00000001
#define AUDIO_ENGINE_SOUND_BUFFER_STATUS_LOOPING 0x00000004
bool audioEngineInit();
void audioEngineExit();
void audioEnginePause();
void audioEngineResume();
int audioEngineCreateSoundBuffer(unsigned int size, int bitsPerSample, int channels, int rate);
bool audioEngineSoundBufferRelease(int soundBufferIndex);
bool audioEngineSoundBufferSetVolume(int soundBufferIndex, int volume);
bool audioEngineSoundBufferGetVolume(int soundBufferIndex, int* volumePtr);
bool audioEngineSoundBufferSetPan(int soundBufferIndex, int pan);
bool audioEngineSoundBufferPlay(int soundBufferIndex, unsigned int flags);
bool audioEngineSoundBufferStop(int soundBufferIndex);
bool audioEngineSoundBufferGetCurrentPosition(int soundBufferIndex, unsigned int* readPosPtr, unsigned int* writePosPtr);
bool audioEngineSoundBufferSetCurrentPosition(int soundBufferIndex, unsigned int pos);
bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, unsigned int writeBytes, void** audioPtr1, unsigned int* audioBytes1, void** audioPtr2, unsigned int* audioBytes2, unsigned int flags);
bool audioEngineSoundBufferUnlock(int soundBufferIndex, void* audioPtr1, unsigned int audioBytes1, void* audioPtr2, unsigned int audioBytes2);
bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* status);
#endif /* AUDIO_ENGINE_H */

View File

@ -1,5 +1,6 @@
#include "core.h" #include "core.h"
#include "audio_engine.h"
#include "config.h" #include "config.h"
#include "color.h" #include "color.h"
#include "dinput.h" #include "dinput.h"
@ -15,9 +16,6 @@
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <SDL.h> #include <SDL.h>
#if _WIN32
#include <SDL_syswm.h>
#endif
// NOT USED. // NOT USED.
void (*_idle_func)() = NULL; void (*_idle_func)() = NULL;
@ -1276,9 +1274,11 @@ void _GNW95_process_message()
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
gProgramIsActive = true; gProgramIsActive = true;
windowRefreshAll(&_scr_size); windowRefreshAll(&_scr_size);
audioEngineResume();
break; break;
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
gProgramIsActive = false; gProgramIsActive = false;
audioEnginePause();
break; break;
} }
break; break;
@ -2055,18 +2055,6 @@ int _GNW95_init_window(int width, int height, bool fullscreen)
if (gSdlTextureSurface == NULL) { if (gSdlTextureSurface == NULL) {
goto err; goto err;
} }
#if _WIN32
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(gSdlWindow, &info)) {
goto err;
}
// Needed for DirectSound.
gProgramWindow = info.info.win.window;
#endif
} }
return 0; return 0;

View File

@ -1,17 +0,0 @@
#ifndef DSOUND_COMPAT_H
#define DSOUND_COMPAT_H
#ifdef _WIN32
#define HAVE_DSOUND 1
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <mmreg.h>
#define DIRECTSOUND_VERSION 0x0300
#include <dsound.h>
#endif
#endif /* DSOUND_COMPAT_H */

View File

@ -163,9 +163,6 @@ static int _movieX;
// 0x638EB4 // 0x638EB4
static int _movieY; static int _movieY;
// 0x638EB8
static bool gMovieDirectSoundInitialized;
// 0x638EBC // 0x638EBC
static File* _alphaHandle; static File* _alphaHandle;
@ -364,12 +361,6 @@ static int _noop()
void movieInit() void movieInit()
{ {
movieLibSetMemoryProcs(movieMallocImpl, movieFreeImpl); movieLibSetMemoryProcs(movieMallocImpl, movieFreeImpl);
#ifdef HAVE_DSOUND
movieLibSetDirectSound(gDirectSound);
gMovieDirectSoundInitialized = (gDirectSound != NULL);
#else
gMovieDirectSoundInitialized = false;
#endif
movieLibSetPaletteEntriesProc(movieSetPaletteEntriesImpl); movieLibSetPaletteEntriesProc(movieSetPaletteEntriesImpl);
_MVE_sfSVGA(640, 480, 480, 0, 0, 0, 0, 0, 0); _MVE_sfSVGA(640, 480, 480, 0, 0, 0, 0, 0, 0);
movieLibSetReadProc(movieReadImpl); movieLibSetReadProc(movieReadImpl);
@ -835,10 +826,8 @@ void movieSetBuildSubtitleFilePathProc(MovieBuildSubtitleFilePathProc* proc)
// 0x487BD0 // 0x487BD0
void movieSetVolume(int volume) void movieSetVolume(int volume)
{ {
if (gMovieDirectSoundInitialized) { int normalizedVolume = _soundVolumeHMItoDirectSound(volume);
int normalizedVolume = _soundVolumeHMItoDirectSound(volume); movieLibSetVolume(normalizedVolume);
movieLibSetVolume(normalizedVolume);
}
} }
// 0x487BEC // 0x487BEC

View File

@ -4,6 +4,7 @@
#include "movie_lib.h" #include "movie_lib.h"
#include "audio_engine.h"
#include "platform_compat.h" #include "platform_compat.h"
#include <assert.h> #include <assert.h>
@ -146,16 +147,6 @@ static int _sync_late = 0;
// 0x51EDEC // 0x51EDEC
static int _sync_FrameDropped = 0; static int _sync_FrameDropped = 0;
#ifdef HAVE_DSOUND
// 0x51EDF0
static LPDIRECTSOUND gMovieLibDirectSound = NULL;
#endif
#ifdef HAVE_DSOUND
// 0x51EDF4
static LPDIRECTSOUNDBUFFER gMovieLibDirectSoundBuffer = NULL;
#endif
// 0x51EDF8 // 0x51EDF8
static int gMovieLibVolume = 0; static int gMovieLibVolume = 0;
@ -348,11 +339,6 @@ static unsigned int _$$R0063[256] = {
// 0x6B3660 // 0x6B3660
static int dword_6B3660; static int dword_6B3660;
#ifdef HAVE_DSOUND
// 0x6B3668
static DSBCAPS stru_6B3668;
#endif
// 0x6B367C // 0x6B367C
static int _sf_ScreenWidth; static int _sf_ScreenWidth;
@ -520,6 +506,8 @@ static int dword_6B403F;
static SDL_Surface* gMovieSdlSurface1; static SDL_Surface* gMovieSdlSurface1;
static SDL_Surface* gMovieSdlSurface2; static SDL_Surface* gMovieSdlSurface2;
static int gMveSoundBuffer = -1;
static unsigned int gMveBufferBytes;
// 0x4F4800 // 0x4F4800
void movieLibSetMemoryProcs(MallocProc* mallocProc, FreeProc* freeProc) void movieLibSetMemoryProcs(MallocProc* mallocProc, FreeProc* freeProc)
@ -558,24 +546,14 @@ static void _MVE_MemFree(STRUCT_6B3690* a1)
a1->field_4 = 0; a1->field_4 = 0;
} }
#ifdef HAVE_DSOUND
// 0x4F48F0
void movieLibSetDirectSound(LPDIRECTSOUND ds)
{
gMovieLibDirectSound = ds;
}
#endif
// 0x4F4900 // 0x4F4900
void movieLibSetVolume(int volume) void movieLibSetVolume(int volume)
{ {
gMovieLibVolume = volume; gMovieLibVolume = volume;
#ifdef HAVE_DSOUND if (gMveSoundBuffer != -1) {
if (gMovieLibDirectSoundBuffer != NULL) { audioEngineSoundBufferSetVolume(gMveSoundBuffer, volume);
IDirectSoundBuffer_SetVolume(gMovieLibDirectSoundBuffer, volume);
} }
#endif
} }
// 0x4F4920 // 0x4F4920
@ -583,11 +561,9 @@ void movieLibSetPan(int pan)
{ {
gMovieLibPan = pan; gMovieLibPan = pan;
#ifdef HAVE_DSOUND if (gMveSoundBuffer != -1) {
if (gMovieLibDirectSoundBuffer != NULL) { audioEngineSoundBufferSetPan(gMveSoundBuffer, pan);
IDirectSoundBuffer_SetPan(gMovieLibDirectSoundBuffer, pan);
} }
#endif
} }
// 0x4F4940 // 0x4F4940
@ -832,11 +808,9 @@ static int _syncWait()
// 0x4F4EA0 // 0x4F4EA0
static void _MVE_sndPause() static void _MVE_sndPause()
{ {
#ifdef HAVE_DSOUND if (gMveSoundBuffer != -1) {
if (gMovieLibDirectSoundBuffer != NULL) { audioEngineSoundBufferStop(gMveSoundBuffer);
IDirectSoundBuffer_Stop(gMovieLibDirectSoundBuffer);
} }
#endif
} }
// 0x4F4EC0 // 0x4F4EC0
@ -1151,55 +1125,28 @@ static void _syncReset(int a1)
// 0x4F5570 // 0x4F5570
static int _MVE_sndConfigure(int a1, int a2, int a3, int a4, int a5, int a6) static int _MVE_sndConfigure(int a1, int a2, int a3, int a4, int a5, int a6)
{ {
#ifdef HAVE_DSOUND
DSBUFFERDESC dsbd;
WAVEFORMATEX wfxFormat;
if (gMovieLibDirectSound == NULL) {
return 1;
}
_MVE_sndReset(); _MVE_sndReset();
_snd_comp = a3; _snd_comp = a3;
dword_6B36A0 = a5; dword_6B36A0 = a5;
_snd_buf = a6; _snd_buf = a6;
dsbd.dwSize = sizeof(DSBUFFERDESC); gMveBufferBytes = (a2 + (a2 >> 1)) & 0xFFFFFFFC;
dsbd.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
dsbd.dwBufferBytes = (a2 + (a2 >> 1)) & 0xFFFFFFFC;
dsbd.dwReserved = 0;
dsbd.lpwfxFormat = &wfxFormat;
wfxFormat.wFormatTag = 1;
wfxFormat.nSamplesPerSec = a4;
wfxFormat.nChannels = 2 - (a3 < 1);
wfxFormat.nBlockAlign = wfxFormat.nChannels * (2 - (a5 < 1));
wfxFormat.cbSize = 0;
wfxFormat.nAvgBytesPerSec = wfxFormat.nSamplesPerSec * wfxFormat.nBlockAlign;
wfxFormat.wBitsPerSample = a5 < 1 ? 8 : 16;
dword_6B3AE4 = 0; dword_6B3AE4 = 0;
dword_6B3660 = 0; dword_6B3660 = 0;
if (IDirectSound_CreateSoundBuffer(gMovieLibDirectSound, &dsbd, &gMovieLibDirectSoundBuffer, NULL) != DS_OK) { gMveSoundBuffer = audioEngineCreateSoundBuffer(gMveBufferBytes, a5 < 1 ? 8 : 16, 2 - (a3 < 1), a4);
if (gMveSoundBuffer == -1) {
return 0; return 0;
} }
IDirectSoundBuffer_SetVolume(gMovieLibDirectSoundBuffer, gMovieLibVolume); audioEngineSoundBufferSetVolume(gMveSoundBuffer, gMovieLibVolume);
IDirectSoundBuffer_SetPan(gMovieLibDirectSoundBuffer, gMovieLibPan); audioEngineSoundBufferSetPan(gMveSoundBuffer, gMovieLibPan);
dword_6B36A4 = 0; dword_6B36A4 = 0;
stru_6B3668.dwSize = sizeof(DSBCAPS);
if (IDirectSoundBuffer_GetCaps(gMovieLibDirectSoundBuffer, &stru_6B3668) != DS_OK) {
return 0;
}
return 1; return 1;
#else
return 0;
#endif
} }
// 0x4F56C0 // 0x4F56C0
@ -1214,23 +1161,20 @@ static void _MVE_syncSync()
// 0x4F56F0 // 0x4F56F0
static void _MVE_sndReset() static void _MVE_sndReset()
{ {
#ifdef HAVE_DSOUND if (gMveSoundBuffer != -1) {
if (gMovieLibDirectSoundBuffer != NULL) { audioEngineSoundBufferStop(gMveSoundBuffer);
IDirectSoundBuffer_Stop(gMovieLibDirectSoundBuffer); audioEngineSoundBufferRelease(gMveSoundBuffer);
IDirectSoundBuffer_Release(gMovieLibDirectSoundBuffer); gMveSoundBuffer = -1;
gMovieLibDirectSoundBuffer = NULL;
} }
#endif
} }
// 0x4F5720 // 0x4F5720
static void _MVE_sndSync() static void _MVE_sndSync()
{ {
#ifdef HAVE_DSOUND unsigned int dwCurrentPlayCursor;
DWORD dwCurrentPlayCursor; unsigned int dwCurrentWriteCursor;
DWORD dwCurrentWriteCursor;
bool v10; bool v10;
DWORD dwStatus; unsigned int dwStatus;
unsigned int v1; unsigned int v1;
bool v2; bool v2;
int v3; int v3;
@ -1247,27 +1191,23 @@ static void _MVE_sndSync()
_sync_late = _syncWaitLevel(_sync_wait_quanta >> 2) > -_sync_wait_quanta >> 1 && !_sync_FrameDropped; _sync_late = _syncWaitLevel(_sync_wait_quanta >> 2) > -_sync_wait_quanta >> 1 && !_sync_FrameDropped;
_sync_FrameDropped = 0; _sync_FrameDropped = 0;
if (gMovieLibDirectSound == NULL) { if (gMveSoundBuffer == -1) {
return;
}
if (gMovieLibDirectSoundBuffer == NULL) {
return; return;
} }
while (1) { while (1) {
if (IDirectSoundBuffer_GetStatus(gMovieLibDirectSoundBuffer, &dwStatus) != DS_OK) { if (!audioEngineSoundBufferGetStatus(gMveSoundBuffer, &dwStatus)) {
return; return;
} }
if (IDirectSoundBuffer_GetCurrentPosition(gMovieLibDirectSoundBuffer, &dwCurrentPlayCursor, &dwCurrentWriteCursor) != DS_OK) { if (!audioEngineSoundBufferGetCurrentPosition(gMveSoundBuffer, &dwCurrentPlayCursor, &dwCurrentWriteCursor)) {
return; return;
} }
dwCurrentWriteCursor = dword_6B36A4; dwCurrentWriteCursor = dword_6B36A4;
v1 = (stru_6B3668.dwBufferBytes + dword_6B39E0[dword_6B3660] - _gSoundTimeBase) v1 = (gMveBufferBytes + dword_6B39E0[dword_6B3660] - _gSoundTimeBase)
% stru_6B3668.dwBufferBytes; % gMveBufferBytes;
if (dwCurrentPlayCursor <= dword_6B36A4) { if (dwCurrentPlayCursor <= dword_6B36A4) {
if (v1 < dwCurrentPlayCursor || v1 >= dword_6B36A4) { if (v1 < dwCurrentPlayCursor || v1 >= dword_6B36A4) {
@ -1283,15 +1223,15 @@ static void _MVE_sndSync()
} }
} }
if (!v2 || !(dwStatus & DSBSTATUS_PLAYING)) { if (!v2 || !(dwStatus & AUDIO_ENGINE_SOUND_BUFFER_STATUS_PLAYING)) {
if (v0) { if (v0) {
_syncReset(_sync_wait_quanta + (_sync_wait_quanta >> 2)); _syncReset(_sync_wait_quanta + (_sync_wait_quanta >> 2));
} }
v3 = dword_6B39E0[dword_6B3660]; v3 = dword_6B39E0[dword_6B3660];
if (!(dwStatus & DSBSTATUS_PLAYING)) { if (!(dwStatus & AUDIO_ENGINE_SOUND_BUFFER_STATUS_PLAYING)) {
v4 = (stru_6B3668.dwBufferBytes + v3) % stru_6B3668.dwBufferBytes; v4 = (gMveBufferBytes + v3) % gMveBufferBytes;
if (dwCurrentWriteCursor >= dwCurrentPlayCursor) { if (dwCurrentWriteCursor >= dwCurrentPlayCursor) {
if (v4 >= dwCurrentPlayCursor && v4 < dwCurrentWriteCursor) { if (v4 >= dwCurrentPlayCursor && v4 < dwCurrentWriteCursor) {
@ -1306,11 +1246,11 @@ static void _MVE_sndSync()
} }
if (v5) { if (v5) {
if (IDirectSoundBuffer_SetCurrentPosition(gMovieLibDirectSoundBuffer, v4) != DS_OK) { if (!audioEngineSoundBufferSetCurrentPosition(gMveSoundBuffer, v4)) {
return; return;
} }
if (IDirectSoundBuffer_Play(gMovieLibDirectSoundBuffer, 0, 0, 1) != DS_OK) { if (!audioEngineSoundBufferPlay(gMveSoundBuffer, 1)) {
return; return;
} }
} }
@ -1318,20 +1258,20 @@ static void _MVE_sndSync()
break; break;
} }
v6 = (stru_6B3668.dwBufferBytes + _gSoundTimeBase + v3) % stru_6B3668.dwBufferBytes; v6 = (gMveBufferBytes + _gSoundTimeBase + v3) % gMveBufferBytes;
v7 = dwCurrentWriteCursor - dwCurrentPlayCursor; v7 = dwCurrentWriteCursor - dwCurrentPlayCursor;
if (((dwCurrentWriteCursor - dwCurrentPlayCursor) & 0x80000000) != 0) { if (((dwCurrentWriteCursor - dwCurrentPlayCursor) & 0x80000000) != 0) {
v7 += stru_6B3668.dwBufferBytes; v7 += gMveBufferBytes;
} }
v8 = stru_6B3668.dwBufferBytes - v7 - 1; v8 = gMveBufferBytes - v7 - 1;
// NOTE: Original code uses signed comparison. // NOTE: Original code uses signed comparison.
if ((int)stru_6B3668.dwBufferBytes / 2 < v8) { if ((int)gMveBufferBytes / 2 < v8) {
v8 = stru_6B3668.dwBufferBytes >> 1; v8 = gMveBufferBytes >> 1;
} }
v9 = (stru_6B3668.dwBufferBytes + dwCurrentPlayCursor - v8) % stru_6B3668.dwBufferBytes; v9 = (gMveBufferBytes + dwCurrentPlayCursor - v8) % gMveBufferBytes;
dwCurrentPlayCursor = v9; dwCurrentPlayCursor = v9;
@ -1350,7 +1290,7 @@ static void _MVE_sndSync()
} }
if (!v10) { if (!v10) {
IDirectSoundBuffer_Stop(gMovieLibDirectSoundBuffer); audioEngineSoundBufferStop(gMveSoundBuffer);
} }
break; break;
@ -1365,10 +1305,6 @@ static void _MVE_sndSync()
++dword_6B3660; ++dword_6B3660;
} }
} }
#else
_sync_late = _syncWaitLevel(_sync_wait_quanta >> 2) > -_sync_wait_quanta >> 1 && !_sync_FrameDropped;
_sync_FrameDropped = 0;
#endif
} }
// 0x4F59B0 // 0x4F59B0
@ -1394,20 +1330,19 @@ static int _syncWaitLevel(int a1)
// 0x4F5A00 // 0x4F5A00
static void _CallsSndBuff_Loc(unsigned char* a1, int a2) static void _CallsSndBuff_Loc(unsigned char* a1, int a2)
{ {
#ifdef HAVE_DSOUND
int v2; int v2;
int v3; int v3;
int v5; int v5;
DWORD dwCurrentPlayCursor; unsigned int dwCurrentPlayCursor;
DWORD dwCurrentWriteCursor; unsigned int dwCurrentWriteCursor;
LPVOID lpvAudioPtr1; void* lpvAudioPtr1;
DWORD dwAudioBytes1; unsigned int dwAudioBytes1;
LPVOID lpvAudioPtr2; void* lpvAudioPtr2;
DWORD dwAudioBytes2; unsigned int dwAudioBytes2;
_gSoundTimeBase = a2; _gSoundTimeBase = a2;
if (gMovieLibDirectSoundBuffer == NULL) { if (gMveSoundBuffer == -1) {
return; return;
} }
@ -1420,13 +1355,13 @@ static void _CallsSndBuff_Loc(unsigned char* a1, int a2)
return; return;
} }
if (IDirectSoundBuffer_GetCurrentPosition(gMovieLibDirectSoundBuffer, &dwCurrentPlayCursor, &dwCurrentWriteCursor) != DS_OK) { if (!audioEngineSoundBufferGetCurrentPosition(gMveSoundBuffer, &dwCurrentPlayCursor, &dwCurrentWriteCursor)) {
return; return;
} }
dwCurrentWriteCursor = dword_6B36A4; dwCurrentWriteCursor = dword_6B36A4;
if (IDirectSoundBuffer_Lock(gMovieLibDirectSoundBuffer, dword_6B36A4, a2, &lpvAudioPtr1, &dwAudioBytes1, &lpvAudioPtr2, &dwAudioBytes2, 0) != DS_OK) { if (!audioEngineSoundBufferLock(gMveSoundBuffer, dword_6B36A4, a2, &lpvAudioPtr1, &dwAudioBytes1, &lpvAudioPtr2, &dwAudioBytes2, 0)) {
return; return;
} }
@ -1443,11 +1378,11 @@ static void _CallsSndBuff_Loc(unsigned char* a1, int a2)
dword_6B36A4 = dwAudioBytes2; dword_6B36A4 = dwAudioBytes2;
} }
if (dword_6B36A4 == stru_6B3668.dwBufferBytes) { if (dword_6B36A4 == gMveBufferBytes) {
dword_6B36A4 = 0; dword_6B36A4 = 0;
} }
IDirectSoundBuffer_Unlock(gMovieLibDirectSoundBuffer, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); audioEngineSoundBufferUnlock(gMveSoundBuffer, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
dword_6B39E0[dword_6B3AE4] = dwCurrentWriteCursor; dword_6B39E0[dword_6B3AE4] = dwCurrentWriteCursor;
@ -1456,7 +1391,6 @@ static void _CallsSndBuff_Loc(unsigned char* a1, int a2)
} else { } else {
++dword_6B3AE4; ++dword_6B3AE4;
} }
#endif
} }
// 0x4F5B70 // 0x4F5B70

View File

@ -1,7 +1,6 @@
#ifndef MOVIE_LIB_H #ifndef MOVIE_LIB_H
#define MOVIE_LIB_H #define MOVIE_LIB_H
#include "dsound_compat.h"
#include "memory_defs.h" #include "memory_defs.h"
#include <SDL.h> #include <SDL.h>
@ -11,9 +10,6 @@ typedef void(MovieShowFrameProc)(SDL_Surface*, int, int, int, int, int, int, int
void movieLibSetMemoryProcs(MallocProc* mallocProc, FreeProc* freeProc); void movieLibSetMemoryProcs(MallocProc* mallocProc, FreeProc* freeProc);
void movieLibSetReadProc(MovieReadProc* readProc); void movieLibSetReadProc(MovieReadProc* readProc);
#ifdef HAVE_DSOUND
void movieLibSetDirectSound(LPDIRECTSOUND ds);
#endif
void movieLibSetVolume(int volume); void movieLibSetVolume(int volume);
void movieLibSetPan(int pan); void movieLibSetPan(int pan);
void _MVE_sfSVGA(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9); void _MVE_sfSVGA(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9);

File diff suppressed because it is too large Load Diff

View File

@ -41,8 +41,6 @@ typedef enum SoundError {
SOUND_INVALID_HANDLE = 30, SOUND_INVALID_HANDLE = 30,
SOUND_NO_MEMORY_AVAILABLE = 31, SOUND_NO_MEMORY_AVAILABLE = 31,
SOUND_UNKNOWN_ERROR = 32, SOUND_UNKNOWN_ERROR = 32,
// TODO: Remove once DirectX -> SDL transition is completed.
SOUND_NOT_IMPLEMENTED = 33,
SOUND_ERR_COUNT, SOUND_ERR_COUNT,
} SoundError; } SoundError;
@ -70,10 +68,10 @@ typedef void SoundCallback(void* userData, int a2);
typedef struct Sound { typedef struct Sound {
SoundFileIO io; SoundFileIO io;
unsigned char* field_20; unsigned char* field_20;
#ifdef HAVE_DSOUND int soundBuffer;
LPDIRECTSOUNDBUFFER directSoundBuffer; int bitsPerSample;
DSBUFFERDESC directSoundBufferDescription; int channels;
#endif int rate;
int field_3C; int field_3C;
// flags // flags
int field_40; int field_40;
@ -91,9 +89,7 @@ typedef struct Sound {
int field_68; int field_68;
int readLimit; int readLimit;
int field_70; int field_70;
#ifdef HAVE_DSOUND unsigned int field_74;
DWORD field_74;
#endif
int field_78; int field_78;
int field_7C; int field_7C;
int field_80; int field_80;
@ -106,10 +102,6 @@ typedef struct Sound {
struct Sound* prev; struct Sound* prev;
} Sound; } Sound;
#ifdef HAVE_DSOUND
extern LPDIRECTSOUND gDirectSound;
#endif
void soundSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc); void soundSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
const char* soundGetErrorDescription(int err); const char* soundGetErrorDescription(int err);
int soundInit(int a1, int a2, int a3, int a4, int rate); int soundInit(int a1, int a2, int a3, int a4, int rate);

View File

@ -8,77 +8,26 @@
#include <stdlib.h> #include <stdlib.h>
#ifdef _WIN32 #ifdef _WIN32
#ifdef HAVE_DSOUND
// 0x51E430
DirectSoundCreateProc* gDirectSoundCreateProc = NULL;
#endif
// 0x51E434
HWND gProgramWindow = NULL;
// 0x51E444 // 0x51E444
bool gProgramIsActive = false; bool gProgramIsActive = false;
// GNW95MUTEX // GNW95MUTEX
HANDLE _GNW95_mutex = NULL; HANDLE _GNW95_mutex = NULL;
#ifdef HAVE_DSOUND
// 0x51E454
HMODULE gDSoundDLL = NULL;
#endif
// 0x4DE700 // 0x4DE700
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
_GNW95_mutex = CreateMutexA(0, TRUE, "GNW95MUTEX"); _GNW95_mutex = CreateMutexA(0, TRUE, "GNW95MUTEX");
if (GetLastError() == ERROR_SUCCESS) { if (GetLastError() == ERROR_SUCCESS) {
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
if (_LoadDirectX()) {
gProgramIsActive = true; gProgramIsActive = true;
falloutMain(argc, argv); falloutMain(argc, argv);
}
CloseHandle(_GNW95_mutex); CloseHandle(_GNW95_mutex);
} }
return 0; return 0;
} }
// 0x4DE8D0
bool _LoadDirectX()
{
#ifdef HAVE_DSOUND
gDSoundDLL = LoadLibraryA("DSOUND.DLL");
if (gDSoundDLL == NULL) {
goto err;
}
gDirectSoundCreateProc = (DirectSoundCreateProc*)GetProcAddress(gDSoundDLL, "DirectSoundCreate");
if (gDirectSoundCreateProc == NULL) {
goto err;
}
#endif
atexit(_UnloadDirectX);
return true;
err:
_UnloadDirectX();
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not load DirectX", "This program requires DirectX 3.0a or later.", NULL);
return false;
}
// 0x4DE988
void _UnloadDirectX(void)
{
#ifdef HAVE_DSOUND
if (gDSoundDLL != NULL) {
FreeLibrary(gDSoundDLL);
gDSoundDLL = NULL;
}
#endif
}
#else #else
bool gProgramIsActive = false; bool gProgramIsActive = false;

View File

@ -1,28 +1,13 @@
#ifndef WIN32_H #ifndef WIN32_H
#define WIN32_H #define WIN32_H
#include "dsound_compat.h"
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define NOMINMAX #define NOMINMAX
#include <windows.h> #include <windows.h>
#ifdef HAVE_DSOUND
typedef HRESULT(__stdcall DirectSoundCreateProc)(GUID*, LPDIRECTSOUND*, IUnknown*);
#endif
#ifdef HAVE_DSOUND
extern DirectSoundCreateProc* gDirectSoundCreateProc;
#endif
extern HWND gProgramWindow;
extern bool gProgramIsActive; extern bool gProgramIsActive;
extern HANDLE _GNW95_mutex; extern HANDLE _GNW95_mutex;
#ifdef HAVE_DSOUND
extern HMODULE gDSoundDLL;
#endif
bool _LoadDirectX();
void _UnloadDirectX(void);
#else #else
extern bool gProgramIsActive; extern bool gProgramIsActive;
#endif #endif