diff --git a/src/sound/SESound.cpp b/src/sound/SESound.cpp index b898635..78577ec 100644 --- a/src/sound/SESound.cpp +++ b/src/sound/SESound.cpp @@ -1,10 +1,18 @@ #include "sound/SESound.hpp" +#include "console/CVar.hpp" +#include "util/SFile.hpp" #include +#include +#include #define LOG_WRITE(result, ...) \ SESound::Log_Write(__LINE__, __FILE__, result, __VA_ARGS__); int32_t SESound::s_Initialized; +SCritSect SESound::s_InternalCritSect; +TSHashTable SESound::s_InternalLookupTable; +HASHKEY_NONE SESound::s_InternalLookupKey; +SCritSect SESound::s_LoadingCritSect; FMOD::System* SESound::s_pGameSystem; uint32_t SESound::s_UniqueID; @@ -20,6 +28,68 @@ void FSoundFreeCallback(void* ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) SMemFree(ptr, "FMod", 0, 0x0); } +FMOD_RESULT DoneLoadingCallback(FMOD_SOUND* sound, FMOD_RESULT result) { + // TODO + return FMOD_OK; +} + +FMOD_RESULT SEOpenCallback(const char* name, uint32_t* filesize, void** handle, void* userdata) { + uint32_t hashval = std::atol(name); + + SESound::s_InternalCritSect.Enter(); + + auto lookup = SESound::s_InternalLookupTable.Ptr(hashval, SESound::s_InternalLookupKey); + + if (!lookup) { + SESound::s_InternalCritSect.Leave(); + + return FMOD_ERR_FILE_NOTFOUND; + } + + auto internal = static_cast(lookup->m_internal); + + *filesize = SFile::GetFileSize(internal->m_file, nullptr); + *handle = internal->m_file; + *(&userdata) = nullptr; + + return FMOD_OK; +} + +FMOD_RESULT SECloseCallback(void* handle, void* userdata) { + auto file = static_cast(handle); + + if (SFile::Close(file)) { + return FMOD_OK; + } else { + return FMOD_ERR_INVALID_HANDLE; + } +} + +FMOD_RESULT SEReadCallback(void* handle, void* buffer, uint32_t sizebytes, uint32_t* bytesread, void* userdata) { + // TODO + + size_t read = 0; + auto file = static_cast(handle); + + auto result = SFile::Read(file, buffer, sizebytes, &read, nullptr, nullptr); + + *bytesread = read; + + // TODO + + if (result) { + return FMOD_OK; + } else { + // TODO + return FMOD_ERR_FILE_EOF; + } +} + +FMOD_RESULT SESeekCallback(void* handle, uint32_t pos, void* userdata) { + // TODO + return FMOD_OK; +} + FMOD::SoundGroup* SESound::CreateSoundGroup(const char* name, int32_t maxAudible) { FMOD::SoundGroup* group = nullptr; FMOD_RESULT result; @@ -165,6 +235,137 @@ int32_t SESound::IsInitialized() { return SESound::s_Initialized == 1; } +int32_t SESound::LoadDiskSound(FMOD::System* fmodSystem, const char* filename, FMOD_MODE fmodMode, SESound* sound, FMOD::SoundGroup* fmodSoundGroup1, FMOD::SoundGroup* fmodSoundGroup2, bool a7, int32_t a8, uint32_t a9, int32_t a10, uint32_t decodeBufferSize, int32_t a12, float a13, float a14, float a15, float* a16) { + SESound::s_LoadingCritSect.Enter(); + + FMOD_RESULT result; + + // TODO + + auto internal = STORM_NEW(SEDiskSound); + + // TODO populate various SEDiskSound members + + internal->m_fmodSystem = fmodSystem; + internal->m_fmodMode = fmodMode; + internal->m_type = 1; + internal->m_useCache = 0; + internal->m_fmodChannel = nullptr; + + internal->m_sound = sound; + sound->m_internal = internal; + + FMOD_CREATESOUNDEXINFO info = {}; + info.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); + info.nonblockcallback = &DoneLoadingCallback; + info.fileuseropen = &SEOpenCallback; + info.fileuserclose = &SECloseCallback; + info.fileuserread = &SEReadCallback; + info.fileuserseek = &SESeekCallback; + info.decodebuffersize = decodeBufferSize; + info.userdata = &internal->m_uniqueID; + info.suggestedsoundtype = FMOD_SOUND_TYPE_UNKNOWN; + info.initialseekposition = 0; + info.initialseekpostype = 0; + + bool useCache = true; + + auto ext = SStrChrR(filename, '.'); + if (ext) { + if (!SStrCmpI(ext, ".wav")) { + info.suggestedsoundtype = SFile::IsStreamingTrial() ? FMOD_SOUND_TYPE_UNKNOWN: FMOD_SOUND_TYPE_WAV; + } else if (!SStrCmpI(ext, ".mp3")) { + useCache = false; + fmodMode |= FMOD_MPEGSEARCH; + info.suggestedsoundtype = FMOD_SOUND_TYPE_MPEG; + } + } + + char fmodName[300]; + SStrPrintf(fmodName, sizeof(fmodName), "%-24d%s", internal->m_uniqueID, filename); + + // TODO + + if (useCache) { + // TODO + } + + // Validate file exists + + if (!SFile::OpenEx(nullptr, filename, 1, &internal->m_file)) { + LOG_WRITE(FMOD_ERR_FILE_NOTFOUND, filename); + + SESound::s_InternalCritSect.Enter(); + + // TODO + + SESound::s_InternalCritSect.Leave(); + + SESound::s_LoadingCritSect.Leave(); + + return 0; + } + + int32_t loaded = 0; + + fmodMode |= FMOD_VIRTUAL_PLAYFROMSTART | FMOD_IGNORETAGS | FMOD_NONBLOCKING; + + uint32_t maxCacheSize = 1048576; + static auto maxCacheSizeVar = CVar::Lookup("Sound_MaxCacheableSizeInBytes"); + if (maxCacheSizeVar) { + maxCacheSize = maxCacheSizeVar->GetInt() > 2097152 ? 2097152 : maxCacheSizeVar->GetInt(); + } + + uint32_t fileSize = internal->m_file ? SFile::GetFileSize(internal->m_file, nullptr) : 0; + + // Create FMOD stream or sound + + if (fileSize > maxCacheSize || !useCache) { + useCache = false; + + result = fmodSystem->createStream(fmodName, fmodMode, &info, &internal->m_fmodSound); + + // TODO counter + } else { + result = fmodSystem->createSound(fmodName, fmodMode, &info, &internal->m_fmodSound); + + // TODO other counter + } + + // Create FMOD stream or sound failed + + if (result != FMOD_OK) { + if (result != FMOD_ERR_OUTPUT_CREATEBUFFER) { + LOG_WRITE(result, filename); + } + + s_InternalCritSect.Enter(); + + SFile::Close(internal->m_file); + internal->m_file = nullptr; + + // TODO + + s_InternalCritSect.Leave(); + + s_LoadingCritSect.Leave(); + + return 0; + } + + if (useCache) { + // TODO + } + + // TODO + + internal->m_loaded = loaded; + + s_LoadingCritSect.Leave(); + + return 1; +} + void SESound::Log_Write(int32_t line, const char* file, FMOD_RESULT result, const char* fmt, ...) { // TODO } @@ -203,8 +404,3 @@ int32_t SESound::Load(const char* filename, int32_t a3, FMOD::SoundGroup* soundG nullptr ); } - -int32_t SESound::LoadDiskSound(FMOD::System* system, const char* filename, FMOD_MODE mode, SESound* sound, FMOD::SoundGroup* soundGroup1, FMOD::SoundGroup* soundGroup2, bool a7, int32_t a8, uint32_t a9, int32_t a10, uint32_t decodeBufferSize, int32_t a12, float a13, float a14, float a15, float* a16) { - // TODO - return 0; -} diff --git a/src/sound/SESound.hpp b/src/sound/SESound.hpp index b2d7836..b47fb23 100644 --- a/src/sound/SESound.hpp +++ b/src/sound/SESound.hpp @@ -3,12 +3,22 @@ #include "sound/SESoundInternal.hpp" #include +#include +#include #include +struct SOUND_INTERNAL_LOOKUP : TSHashObject { + SESoundInternal* m_internal; +}; + class SESound { public: // Public static variables static int32_t s_Initialized; + static SCritSect s_InternalCritSect; + static TSHashTable s_InternalLookupTable; + static HASHKEY_NONE s_InternalLookupKey; + static SCritSect s_LoadingCritSect; static FMOD::System* s_pGameSystem; static uint32_t s_UniqueID; @@ -24,7 +34,7 @@ class SESound { private: // Private static functions - static int32_t LoadDiskSound(FMOD::System* system, const char* filename, FMOD_MODE mode, SESound* sound, FMOD::SoundGroup* soundGroup1, FMOD::SoundGroup* soundGroup2, bool a7, int32_t a8, uint32_t a9, int32_t a10, uint32_t decodeBufferSize, int32_t a12, float a13, float a14, float a15, float* a16); + static int32_t LoadDiskSound(FMOD::System* fmodSystem, const char* filename, FMOD_MODE fmodMode, SESound* sound, FMOD::SoundGroup* fmodSoundGroup1, FMOD::SoundGroup* fmodSoundGroup2, bool a7, int32_t a8, uint32_t a9, int32_t a10, uint32_t decodeBufferSize, int32_t a12, float a13, float a14, float a15, float* a16); // Private member variables SESoundInternal* m_internal = nullptr; diff --git a/src/sound/SESoundInternal.cpp b/src/sound/SESoundInternal.cpp index f478d96..e0d1f4c 100644 --- a/src/sound/SESoundInternal.cpp +++ b/src/sound/SESoundInternal.cpp @@ -23,6 +23,15 @@ void SESoundInternal::Play() { } } +SEDiskSound::SEDiskSound() : SESoundInternal() { + SESound::s_InternalCritSect.Enter(); + + auto lookup = SESound::s_InternalLookupTable.New(this->m_uniqueID, SESound::s_InternalLookupKey, 0, 0x0); + lookup->m_internal = this; + + SESound::s_InternalCritSect.Leave(); +} + void SEDiskSound::Abort(FMOD_RESULT result) { // TODO } diff --git a/src/sound/SESoundInternal.hpp b/src/sound/SESoundInternal.hpp index 3ba030f..5056ef0 100644 --- a/src/sound/SESoundInternal.hpp +++ b/src/sound/SESoundInternal.hpp @@ -52,6 +52,7 @@ class SEDiskSound : public SESoundInternal { SoundCacheNode* m_cacheNode = nullptr; // Member functions + SEDiskSound(); void Abort(FMOD_RESULT result); void CompleteNonBlockingLoad(); };