diff --git a/Assets/Scripts/UniQuake.cs b/Assets/Scripts/UniQuake.cs index 6b33500..367882f 100644 --- a/Assets/Scripts/UniQuake.cs +++ b/Assets/Scripts/UniQuake.cs @@ -84,7 +84,7 @@ public class UniQuake: MonoBehaviour try { - // UniQuake_SetFmodSystem(AudioManager.Instance.FmodSystem.handle); + UniQuake_SetFmodSystem(AudioManager.Instance.FmodSystem.handle); UniQuake_Init(quakeParms.ToNativePtr(), systemModule.CallbacksPtr, renderModule.CallbacksPtr); initialized = true; } @@ -178,7 +178,7 @@ public class UniQuake: MonoBehaviour UniQuake_Init = LoadLibraryFunction("UniQuake_Init"); UniQuake_Update = LoadLibraryFunction("UniQuake_Update"); UniQuake_Shutdown = LoadLibraryFunction("UniQuake_Shutdown"); - // UniQuake_SetFmodSystem = LoadLibraryFunction("UniQuake_SetFmodSystem"); + UniQuake_SetFmodSystem = LoadLibraryFunction("UniQuake_SetFmodSystem"); } private TDelegate LoadLibraryFunction(string functionName) diff --git a/engine/Quake/bgmusic.c b/engine/Quake/bgmusic.c index 65df3ca..3e9042f 100644 --- a/engine/Quake/bgmusic.c +++ b/engine/Quake/bgmusic.c @@ -26,54 +26,29 @@ #include "snd_codec.h" #include "bgmusic.h" +#if USE_FMOD +#include "fmod.h" +#include "fmod_errors.h" + #define MUSIC_DIRNAME "music" qboolean bgmloop; cvar_t bgm_extmusic = {"bgm_extmusic", "1", CVAR_ARCHIVE}; -static qboolean no_extmusic= false; +static qboolean no_extmusic = false; static float old_volume = -1.0f; -typedef enum _bgm_player -{ - BGM_NONE = -1, - BGM_MIDIDRV = 1, - BGM_STREAMER -} bgm_player_t; +extern FMOD_SYSTEM *fmod_system; +FMOD_CHANNELGROUP *bgm_channelGroup; +FMOD_CHANNEL *bgm_channel; +FMOD_SOUND *bgm_sound; +byte *bgm_data; -typedef struct music_handler_s +static const char *extensions[] = { - unsigned int type; /* 1U << n (see snd_codec.h) */ - bgm_player_t player; /* Enumerated bgm player type */ - int is_available; /* -1 means not present */ - const char *ext; /* Expected file extension */ - const char *dir; /* Where to look for music file */ - struct music_handler_s *next; -} music_handler_t; - -static music_handler_t wanted_handlers[] = -{ - { CODECTYPE_VORBIS,BGM_STREAMER,-1, "ogg", MUSIC_DIRNAME, NULL }, - { CODECTYPE_OPUS, BGM_STREAMER, -1, "opus", MUSIC_DIRNAME, NULL }, - { CODECTYPE_MP3, BGM_STREAMER, -1, "mp3", MUSIC_DIRNAME, NULL }, - { CODECTYPE_FLAC, BGM_STREAMER, -1, "flac", MUSIC_DIRNAME, NULL }, - { CODECTYPE_WAV, BGM_STREAMER, -1, "wav", MUSIC_DIRNAME, NULL }, - { CODECTYPE_MOD, BGM_STREAMER, -1, "it", MUSIC_DIRNAME, NULL }, - { CODECTYPE_MOD, BGM_STREAMER, -1, "s3m", MUSIC_DIRNAME, NULL }, - { CODECTYPE_MOD, BGM_STREAMER, -1, "xm", MUSIC_DIRNAME, NULL }, - { CODECTYPE_MOD, BGM_STREAMER, -1, "mod", MUSIC_DIRNAME, NULL }, - { CODECTYPE_UMX, BGM_STREAMER, -1, "umx", MUSIC_DIRNAME, NULL }, - { CODECTYPE_NONE, BGM_NONE, -1, NULL, NULL, NULL } + "wav", "flac", "ogg", "mp3" }; -static music_handler_t *music_handlers = NULL; - -#define ANY_CODECTYPE 0xFFFFFFFF -#define CDRIP_TYPES (CODECTYPE_VORBIS | CODECTYPE_MP3 | CODECTYPE_FLAC | CODECTYPE_WAV | CODECTYPE_OPUS) -#define CDRIPTYPE(x) (((x) & CDRIP_TYPES) != 0) - -static snd_stream_t *bgmstream = NULL; - static void BGM_Play_f (void) { if (Cmd_Argc() == 2) @@ -124,8 +99,7 @@ static void BGM_Stop_f (void) qboolean BGM_Init (void) { - music_handler_t *handlers = NULL; - int i; + FMOD_RESULT result; Cvar_RegisterVariable(&bgm_extmusic); Cmd_AddCommand("music", BGM_Play_f); @@ -139,34 +113,17 @@ qboolean BGM_Init (void) bgmloop = true; - for (i = 0; wanted_handlers[i].type != CODECTYPE_NONE; i++) + if (!fmod_system) { - switch (wanted_handlers[i].player) - { - case BGM_MIDIDRV: - /* not supported in quake */ - break; - case BGM_STREAMER: - wanted_handlers[i].is_available = - S_CodecIsAvailable(wanted_handlers[i].type); - break; - case BGM_NONE: - default: - break; - } - if (wanted_handlers[i].is_available != -1) - { - if (handlers) - { - handlers->next = &wanted_handlers[i]; - handlers = handlers->next; - } - else - { - music_handlers = &wanted_handlers[i]; - handlers = music_handlers; - } - } + Con_Printf("FMOD System not initialized! Cannot start FMOD music codec.\n"); + return false; + } + + result = FMOD_System_CreateChannelGroup(fmod_system, "BGM", &bgm_channelGroup); + if (result != FMOD_OK) + { + Con_Printf("Failed to create FMOD music channel group: %s\n", FMOD_ErrorString(result)); + return false; } return true; @@ -175,46 +132,74 @@ qboolean BGM_Init (void) void BGM_Shutdown (void) { BGM_Stop(); -/* sever our connections to - * midi_drv and snd_codec */ - music_handlers = NULL; } -static void BGM_Play_noext (const char *filename, unsigned int allowed_types) +static qboolean BGM_PlayStream(const char *filename) +{ + FILE *f; + int len; + FMOD_CREATESOUNDEXINFO exinfo; + FMOD_RESULT result; + + len = COM_FOpenFile(filename, &f, NULL); + fclose(f); + if (len < 1) + { + Con_Printf("Could not open BGM file %s, file not found\n", filename); + return false; + } + + bgm_data = COM_LoadMallocFile(filename, NULL); // TODO is there really no better way to pre-cache this data than with malloc? + if (!bgm_data) + { + Con_Printf("Failed to load BGM file %s\n", filename); + return false; + } + + Con_DPrintf("BGM_PlayStream: Successfully loaded %s\n", filename); + + memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); + exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); + exinfo.length = len; + + result = FMOD_System_CreateSound(fmod_system, (const char*)bgm_data, FMOD_OPENMEMORY | FMOD_2D, &exinfo, &bgm_sound); + if (result != FMOD_OK || !bgm_sound) + { + Con_Printf("Failed to create FMOD sound: %s\n", FMOD_ErrorString(result)); + BGM_Stop(); + return false; + } + + result = FMOD_System_PlaySound(fmod_system, bgm_sound, bgm_channelGroup, false, &bgm_channel); + if (result != FMOD_OK || !bgm_channel) + { + Con_Printf("Failed to play FMOD sound: %s\n", FMOD_ErrorString(result)); + BGM_Stop(); + return false; + } + + if (bgmloop) + { + FMOD_Channel_SetMode(bgm_channel, FMOD_LOOP_NORMAL); + } + else + { + FMOD_Channel_SetMode(bgm_channel, FMOD_LOOP_OFF); + FMOD_Channel_SetLoopCount(bgm_channel, 0); + } + + return true; +} + +static void BGM_Play_noext (const char *filename) { char tmp[MAX_QPATH]; - music_handler_t *handler; - handler = music_handlers; - while (handler) + for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); ++i) { - if (! (handler->type & allowed_types)) - { - handler = handler->next; - continue; - } - if (!handler->is_available) - { - handler = handler->next; - continue; - } - q_snprintf(tmp, sizeof(tmp), "%s/%s.%s", - handler->dir, filename, handler->ext); - switch (handler->player) - { - case BGM_MIDIDRV: - /* not supported in quake */ - break; - case BGM_STREAMER: - bgmstream = S_CodecOpenStreamType(tmp, handler->type); - if (bgmstream) - return; /* success */ - break; - case BGM_NONE: - default: - break; - } - handler = handler->next; + q_snprintf(tmp, sizeof(tmp), "%s/%s.%s", MUSIC_DIRNAME, filename, extensions[i]); + if (BGM_PlayStream(tmp)) + return; } Con_Printf("Couldn't handle music file %s\n", filename); @@ -224,13 +209,9 @@ void BGM_Play (const char *filename) { char tmp[MAX_QPATH]; const char *ext; - music_handler_t *handler; BGM_Stop(); - if (music_handlers == NULL) - return; - if (!filename || !*filename) { Con_DPrintf("null music file name\n"); @@ -240,38 +221,13 @@ void BGM_Play (const char *filename) ext = COM_FileGetExtension(filename); if (! *ext) /* try all things */ { - BGM_Play_noext(filename, ANY_CODECTYPE); + BGM_Play_noext(filename); return; } - handler = music_handlers; - while (handler) - { - if (handler->is_available && - !q_strcasecmp(ext, handler->ext)) - break; - handler = handler->next; - } - if (!handler) - { - Con_Printf("Unhandled extension for %s\n", filename); + q_snprintf(tmp, sizeof(tmp), "%s/%s", MUSIC_DIRNAME, filename); + if (BGM_PlayStream(tmp)) return; - } - q_snprintf(tmp, sizeof(tmp), "%s/%s", handler->dir, filename); - switch (handler->player) - { - case BGM_MIDIDRV: - /* not supported in quake */ - break; - case BGM_STREAMER: - bgmstream = S_CodecOpenStreamType(tmp, handler->type); - if (bgmstream) - return; /* success */ - break; - case BGM_NONE: - default: - break; - } Con_Printf("Couldn't handle music file %s\n", filename); } @@ -287,169 +243,76 @@ void BGM_PlayCDtrack (byte track, qboolean looping) */ char tmp[MAX_QPATH]; const char *ext; - unsigned int path_id, prev_id, type; - music_handler_t *handler; + unsigned int path_id, prev_id; BGM_Stop(); if (CDAudio_Play(track, looping) == 0) return; /* success */ - if (music_handlers == NULL) - return; - if (no_extmusic || !bgm_extmusic.value) return; prev_id = 0; - type = 0; ext = NULL; - handler = music_handlers; - while (handler) + + for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); ++i) { - if (! handler->is_available) - goto _next; - if (! CDRIPTYPE(handler->type)) - goto _next; - q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", - MUSIC_DIRNAME, (int)track, handler->ext); - if (! COM_FileExists(tmp, &path_id)) - goto _next; + q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", MUSIC_DIRNAME, (int)track, extensions[i]); + if (!COM_FileExists(tmp, &path_id)) + continue; + if (path_id > prev_id) { prev_id = path_id; - type = handler->type; - ext = handler->ext; + ext = extensions[i]; } - _next: - handler = handler->next; } + if (ext == NULL) - Con_Printf("Couldn't find a cdrip for track %d\n", (int)track); - else { - q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", - MUSIC_DIRNAME, (int)track, ext); - bgmstream = S_CodecOpenStreamType(tmp, type); - if (! bgmstream) - Con_Printf("Couldn't handle music file %s\n", tmp); + Con_Printf("Couldn't find a cdrip for track %d\n", (int)track); + return; } + + q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", MUSIC_DIRNAME, (int)track, ext); + if (!BGM_PlayStream(tmp)) + Con_Printf("Couldn't handle music file %s\n", tmp); } -void BGM_Stop (void) +void BGM_Stop(void) { - if (bgmstream) + if (bgm_channel) { - bgmstream->status = STREAM_NONE; - S_CodecCloseStream(bgmstream); - bgmstream = NULL; - s_rawend = 0; + FMOD_Channel_Stop(bgm_channel); + bgm_channel = NULL; } -} -void BGM_Pause (void) -{ - if (bgmstream) + if (bgm_sound) + { + FMOD_Sound_Release(bgm_sound); + bgm_sound = NULL; + } + + if (bgm_data) { - if (bgmstream->status == STREAM_PLAY) - bgmstream->status = STREAM_PAUSE; + free(bgm_data); + bgm_data = NULL; } } -void BGM_Resume (void) +void BGM_Pause (void) { - if (bgmstream) + if (bgm_channel) { - if (bgmstream->status == STREAM_PAUSE) - bgmstream->status = STREAM_PLAY; + FMOD_Channel_SetPaused(bgm_channel, true); } } -static void BGM_UpdateStream (void) +void BGM_Resume (void) { - qboolean did_rewind = false; - int res; /* Number of bytes read. */ - int bufferSamples; - int fileSamples; - int fileBytes; - byte raw[16384]; - - if (bgmstream->status != STREAM_PLAY) - return; - - /* don't bother playing anything if musicvolume is 0 */ - if (bgmvolume.value <= 0) - return; - - /* see how many samples should be copied into the raw buffer */ - if (s_rawend < paintedtime) - s_rawend = paintedtime; - - while (s_rawend < paintedtime + MAX_RAW_SAMPLES) + if (bgm_channel) { - bufferSamples = MAX_RAW_SAMPLES - (s_rawend - paintedtime); - - /* decide how much data needs to be read from the file */ - fileSamples = bufferSamples * bgmstream->info.rate / shm->speed; - if (!fileSamples) - return; - - /* our max buffer size */ - fileBytes = fileSamples * (bgmstream->info.width * bgmstream->info.channels); - if (fileBytes > (int) sizeof(raw)) - { - fileBytes = (int) sizeof(raw); - fileSamples = fileBytes / - (bgmstream->info.width * bgmstream->info.channels); - } - - /* Read */ - res = S_CodecReadStream(bgmstream, fileBytes, raw); - if (res < fileBytes) - { - fileBytes = res; - fileSamples = res / (bgmstream->info.width * bgmstream->info.channels); - } - - if (res > 0) /* data: add to raw buffer */ - { - S_RawSamples(fileSamples, bgmstream->info.rate, - bgmstream->info.width, - bgmstream->info.channels, - raw, bgmvolume.value); - did_rewind = false; - } - else if (res == 0) /* EOF */ - { - if (bgmloop) - { - if (did_rewind) - { - Con_Printf("Stream keeps returning EOF.\n"); - BGM_Stop(); - return; - } - - res = S_CodecRewindStream(bgmstream); - if (res != 0) - { - Con_Printf("Stream seek error (%i), stopping.\n", res); - BGM_Stop(); - return; - } - did_rewind = true; - } - else - { - BGM_Stop(); - return; - } - } - else /* res < 0: some read error */ - { - Con_Printf("Stream read error (%i), stopping.\n", res); - BGM_Stop(); - return; - } + FMOD_Channel_SetPaused(bgm_channel, false); } } @@ -461,9 +324,56 @@ void BGM_Update (void) Cvar_SetQuick (&bgmvolume, "0"); else if (bgmvolume.value > 1) Cvar_SetQuick (&bgmvolume, "1"); + old_volume = bgmvolume.value; } - if (bgmstream) - BGM_UpdateStream (); + + if (fmod_system) + { + FMOD_System_Update(fmod_system); // TODO: move this to main FMOD sound handler (snd_fmod.c) + + if (bgm_channelGroup) + { + FMOD_ChannelGroup_SetVolume(bgm_channelGroup, bgmvolume.value); + } + } +} + +#else + +qboolean BGM_Init(void) +{ + Con_Printf("BGM disabled at compile time\n"); + return false; +} + +void BGM_Shutdown(void) +{ +} + +void BGM_Play(const char *filename) +{ +} + +void BGM_Stop(void) +{ +} + +void BGM_Update(void) +{ +} + +void BGM_Pause(void) +{ +} + +void BGM_Resume(void) +{ +} + +void BGM_PlayCDtrack(byte track, qboolean looping) +{ + CDAudio_Play(track, looping); } +#endif // USE_FMOD diff --git a/engine/Quake/snd_fmod.c b/engine/Quake/snd_fmod.c new file mode 100644 index 0000000..330fc31 --- /dev/null +++ b/engine/Quake/snd_fmod.c @@ -0,0 +1,9 @@ +#include "quakedef.h" + +#ifdef USE_FMOD +#include "fmod.h" +#include "fmod_errors.h" + +FMOD_SYSTEM *fmod_system; + +#endif // USE_FMOD diff --git a/engine/UniQuake/uniquake.c b/engine/UniQuake/uniquake.c index d9e1de0..950d7f3 100644 --- a/engine/UniQuake/uniquake.c +++ b/engine/UniQuake/uniquake.c @@ -3,6 +3,9 @@ #include "../Quake/quakedef.h" #if USE_FMOD +typedef struct FMOD_SYSTEM FMOD_SYSTEM; +extern FMOD_SYSTEM *fmod_system; + UNIQUAKE_API void UniQuake_SetFmodSystem(FMOD_SYSTEM *system) { fmod_system = system; diff --git a/engine/Windows/VisualStudio/uniquake.vcxproj b/engine/Windows/VisualStudio/uniquake.vcxproj index 537aa06..e5b0a62 100644 --- a/engine/Windows/VisualStudio/uniquake.vcxproj +++ b/engine/Windows/VisualStudio/uniquake.vcxproj @@ -90,7 +90,7 @@ Disabled ..\SDL2\include;..\..\FMOD\inc;..\..\Quake;%(AdditionalIncludeDirectories) - UNIQUAKE_EXPORTS;UQ_SDLREF;WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_SDL2;%(PreprocessorDefinitions) + UNIQUAKE_EXPORTS;UQ_SDLREF;WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_SDL2;USE_FMOD;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -145,7 +145,7 @@ copy "$(SolutionDir)\..\SDL2\lib\*.dll" "$(TargetDir)" Disabled ..\SDL2\include;..\..\FMOD\inc;..\..\Quake;%(AdditionalIncludeDirectories) - UNIQUAKE_EXPORTS;UQ_SDLREF;WIN32;_DEBUG;_WINDOWS;_USE_WINSOCK2;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_SDL2;%(PreprocessorDefinitions) + UNIQUAKE_EXPORTS;UQ_SDLREF;WIN32;_DEBUG;_WINDOWS;_USE_WINSOCK2;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_SDL2;USE_FMOD;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -198,7 +198,7 @@ copy "$(SolutionDir)\..\SDL2\lib64\*.dll" "$(TargetDir)" - + @@ -251,6 +251,7 @@ copy "$(SolutionDir)\..\SDL2\lib64\*.dll" "$(TargetDir)" + diff --git a/engine/Windows/VisualStudio/uniquake.vcxproj.filters b/engine/Windows/VisualStudio/uniquake.vcxproj.filters index 7ffbf02..24de093 100644 --- a/engine/Windows/VisualStudio/uniquake.vcxproj.filters +++ b/engine/Windows/VisualStudio/uniquake.vcxproj.filters @@ -4,9 +4,6 @@ engine - - engine - engine @@ -154,9 +151,6 @@ engine - - engine - engine @@ -235,6 +229,15 @@ obsolete + + engine + + + engine + + + obsolete + @@ -372,12 +375,6 @@ engine - - engine - - - engine - engine @@ -453,6 +450,12 @@ fmod + + obsolete + + + obsolete +