diff --git a/Source/effects.cpp b/Source/effects.cpp index 904675ae3..7f6ee0027 100644 --- a/Source/effects.cpp +++ b/Source/effects.cpp @@ -1093,7 +1093,7 @@ static void stream_play(TSFX *pSFX, int lVolume, int lPan) if (lVolume > VOLUME_MAX) lVolume = VOLUME_MAX; if (pSFX->pSnd == NULL) - pSFX->pSnd = sound_file_load(pSFX->pszName); + pSFX->pSnd = sound_file_load(pSFX->pszName, /*stream=*/true); pSFX->pSnd->DSB->Play(lVolume, lPan, 0); sgpStreamSFX = pSFX; } diff --git a/Source/sound.h b/Source/sound.h index b23c3d8bb..4eb13866b 100644 --- a/Source/sound.h +++ b/Source/sound.h @@ -17,7 +17,7 @@ void snd_update(BOOL bStopAll); void snd_stop_snd(TSnd *pSnd); BOOL snd_playing(TSnd *pSnd); void snd_play_snd(TSnd *pSnd, int lVolume, int lPan); -TSnd *sound_file_load(const char *path); +TSnd *sound_file_load(const char *path, bool stream = false); void sound_file_cleanup(TSnd *sound_file); void snd_init(); void sound_cleanup(); diff --git a/SourceS/miniwin/misc.h b/SourceS/miniwin/misc.h index 831b358a7..0415d569a 100644 --- a/SourceS/miniwin/misc.h +++ b/SourceS/miniwin/misc.h @@ -66,6 +66,8 @@ bool PostMessage(UINT Msg, WPARAM wParam, LPARAM lParam); #define DVL_FILE_CURRENT 1 #define DVL_FILE_END 2 +#define DVL_ERROR_HANDLE_EOF 1002 + #define DVL_WM_QUIT 0x0012 // diff --git a/SourceS/soundsample.h b/SourceS/soundsample.h index 49a67ab39..08fa0a547 100644 --- a/SourceS/soundsample.h +++ b/SourceS/soundsample.h @@ -3,17 +3,18 @@ namespace dvl { -typedef struct SoundSample final { +class SoundSample final { public: void Release(); bool IsPlaying(); void Play(int lVolume, int lPan, int channel = -1); void Stop(); + int SetChunkStream(HANDLE stormHandle); int SetChunk(BYTE *fileData, DWORD dwBytes); int GetLength(); private: Mix_Chunk *chunk; -} SoundSample; +}; } // namespace dvl diff --git a/SourceX/sound.cpp b/SourceX/sound.cpp index c1e3e9654..557bbb7e9 100644 --- a/SourceX/sound.cpp +++ b/SourceX/sound.cpp @@ -94,28 +94,37 @@ void snd_play_snd(TSnd *pSnd, int lVolume, int lPan) pSnd->start_tc = tc; } -TSnd *sound_file_load(const char *path) +TSnd *sound_file_load(const char *path, bool stream) { HANDLE file; - BYTE *wave_file; TSnd *pSnd; - DWORD dwBytes; - int error; + int error = 0; - SFileOpenFile(path, &file); + if (!SFileOpenFile(path, &file)) { + ErrDlg("SFileOpenFile failed", path, __FILE__, __LINE__); + return NULL; + } pSnd = (TSnd *)DiabloAllocPtr(sizeof(TSnd)); memset(pSnd, 0, sizeof(TSnd)); pSnd->sound_path = path; pSnd->start_tc = SDL_GetTicks() - 80 - 1; - - dwBytes = SFileGetFileSize(file, NULL); - wave_file = DiabloAllocPtr(dwBytes); - SFileReadFile(file, wave_file, dwBytes, NULL, NULL); - pSnd->DSB = new SoundSample(); - error = pSnd->DSB->SetChunk(wave_file, dwBytes); - SFileCloseFile(file); - mem_free_dbg(wave_file); + + if (stream) { + pSnd->file_handle = file; + error = pSnd->DSB->SetChunkStream(file); + if (error != 0) { + SFileCloseFile(file); + ErrSdl(); + } + } else { + DWORD dwBytes = SFileGetFileSize(file, NULL); + BYTE *wave_file = DiabloAllocPtr(dwBytes); + SFileReadFile(file, wave_file, dwBytes, NULL, NULL); + error = pSnd->DSB->SetChunk(wave_file, dwBytes); + SFileCloseFile(file); + mem_free_dbg(wave_file); + } if (error != 0) { ErrSdl(); } @@ -132,6 +141,8 @@ void sound_file_cleanup(TSnd *sound_file) delete sound_file->DSB; sound_file->DSB = NULL; } + if (sound_file->file_handle != NULL) + SFileCloseFile(sound_file->file_handle); mem_free_dbg(sound_file); } diff --git a/SourceX/soundsample.cpp b/SourceX/soundsample.cpp index 3c3edffd8..cbfc2a0a9 100644 --- a/SourceX/soundsample.cpp +++ b/SourceX/soundsample.cpp @@ -2,6 +2,8 @@ #include "stubs.h" #include +#include "storm_sdl_rw.h" + namespace dvl { ///// SoundSample ///// @@ -9,6 +11,7 @@ namespace dvl { void SoundSample::Release() { Mix_FreeChunk(chunk); + chunk = NULL; }; /** @@ -66,6 +69,16 @@ void SoundSample::Stop() } }; +int SoundSample::SetChunkStream(HANDLE stormHandle) +{ + chunk = Mix_LoadWAV_RW(SFileRw_FromStormHandle(stormHandle), /*freesrc=*/1); + if (chunk == NULL) { + SDL_Log("Mix_LoadWAV_RW: %s", Mix_GetError()); + return -1; + } + return 0; +} + /** * @brief This can load WAVE, AIFF, RIFF, OGG, and VOC formats * @param fileData Buffer containing file data diff --git a/SourceX/storm_sdl_rw.cpp b/SourceX/storm_sdl_rw.cpp index 686745a22..41003ef15 100644 --- a/SourceX/storm_sdl_rw.cpp +++ b/SourceX/storm_sdl_rw.cpp @@ -19,10 +19,7 @@ static void SFileRw_SetHandle(struct SDL_RWops *context, HANDLE handle) #ifndef USE_SDL1 static Sint64 SFileRw_size(struct SDL_RWops *context) { - DWORD result; - if (!SFileGetFileSize(SFileRw_GetHandle(context), &result)) - return -1; - return result; + return SFileGetFileSize(SFileRw_GetHandle(context), NULL); } #endif @@ -46,7 +43,11 @@ static int SFileRw_seek(struct SDL_RWops *context, int offset, int whence) default: return -1; } - return SFileSetFilePointer(SFileRw_GetHandle(context), offset, NULL, swhence); + DWORD result = SFileSetFilePointer(SFileRw_GetHandle(context), offset, NULL, swhence); + if (result == (DWORD)-1) { + SDL_Log("SFileRw_seek error: %ud", (unsigned int)SErrGetLastError()); + } + return result; } #ifndef USE_SDL1 @@ -56,8 +57,13 @@ static int SFileRw_read(struct SDL_RWops *context, void *ptr, int size, int maxn #endif { DWORD num_read = 0; - SFileReadFile(SFileRw_GetHandle(context), ptr, maxnum * size, &num_read, NULL); - return num_read; + if (!SFileReadFile(SFileRw_GetHandle(context), ptr, maxnum * size, &num_read, NULL)) { + const DWORD err_code = SErrGetLastError(); + if (err_code != DVL_ERROR_HANDLE_EOF) { + SDL_Log("SFileRw_read error: %u %u ERROR CODE %u", (unsigned int)size, (unsigned int)maxnum, (unsigned int)err_code); + } + } + return num_read / size; } static int SFileRw_close(struct SDL_RWops *context) diff --git a/structs.h b/structs.h index 52fdcdebf..e24b5ecc4 100644 --- a/structs.h +++ b/structs.h @@ -23,6 +23,7 @@ typedef struct TextDataStruct { typedef struct TSnd { const char *sound_path; + HANDLE file_handle; // for streamed audio SoundSample *DSB; int start_tc; } TSnd;