Browse Source

Rewrote the BGM system using FMOD, making the whole codec system rather obsolete

console
Nico de Poel 5 years ago
parent
commit
243bb70613
  1. 4
      Assets/Scripts/UniQuake.cs
  2. 432
      engine/Quake/bgmusic.c
  3. 9
      engine/Quake/snd_fmod.c
  4. 3
      engine/UniQuake/uniquake.c
  5. 7
      engine/Windows/VisualStudio/uniquake.vcxproj
  6. 27
      engine/Windows/VisualStudio/uniquake.vcxproj.filters

4
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_InitFunc>("UniQuake_Init");
UniQuake_Update = LoadLibraryFunction<UniQuake_UpdateFunc>("UniQuake_Update");
UniQuake_Shutdown = LoadLibraryFunction<UniQuake_ShutdownFunc>("UniQuake_Shutdown");
// UniQuake_SetFmodSystem = LoadLibraryFunction<UniQuake_SetFmodSystemFunc>("UniQuake_SetFmodSystem");
UniQuake_SetFmodSystem = LoadLibraryFunction<UniQuake_SetFmodSystemFunc>("UniQuake_SetFmodSystem");
}
private TDelegate LoadLibraryFunction<TDelegate>(string functionName)

432
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

9
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

3
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;

7
engine/Windows/VisualStudio/uniquake.vcxproj

@ -90,7 +90,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\SDL2\include;..\..\FMOD\inc;..\..\Quake;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>UNIQUAKE_EXPORTS;UQ_SDLREF;WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -145,7 +145,7 @@ copy "$(SolutionDir)\..\SDL2\lib\*.dll" "$(TargetDir)"</Command>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\SDL2\include;..\..\FMOD\inc;..\..\Quake;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>UNIQUAKE_EXPORTS;UQ_SDLREF;WIN32;_DEBUG;_WINDOWS;_USE_WINSOCK2;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -198,7 +198,7 @@ copy "$(SolutionDir)\..\SDL2\lib64\*.dll" "$(TargetDir)"</Command>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\Quake\bgmusic.c" />
<ClCompile Include="..\..\Quake\cd_sdl.c" />
<ClCompile Include="..\..\Quake\cd_null.c" />
<ClCompile Include="..\..\Quake\cfgfile.c" />
<ClCompile Include="..\..\Quake\chase.c" />
<ClCompile Include="..\..\Quake\cl_demo.c" />
@ -251,6 +251,7 @@ copy "$(SolutionDir)\..\SDL2\lib64\*.dll" "$(TargetDir)"</Command>
<ClCompile Include="..\..\Quake\snd_codec.c" />
<ClCompile Include="..\..\Quake\snd_dma.c" />
<ClCompile Include="..\..\Quake\snd_flac.c" />
<ClCompile Include="..\..\Quake\snd_fmod.c" />
<ClCompile Include="..\..\Quake\snd_mem.c" />
<ClCompile Include="..\..\Quake\snd_mikmod.c" />
<ClCompile Include="..\..\Quake\snd_mix.c" />

27
engine/Windows/VisualStudio/uniquake.vcxproj.filters

@ -4,9 +4,6 @@
<ClCompile Include="..\..\Quake\bgmusic.c">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\cd_sdl.c">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\cfgfile.c">
<Filter>engine</Filter>
</ClCompile>
@ -154,9 +151,6 @@
<ClCompile Include="..\..\Quake\sbar.c">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\snd_codec.c">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\snd_dma.c">
<Filter>engine</Filter>
</ClCompile>
@ -235,6 +229,15 @@
<ClCompile Include="..\..\Quake\sys_sdl_win.c">
<Filter>obsolete</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\snd_fmod.c">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\cd_null.c">
<Filter>engine</Filter>
</ClCompile>
<ClCompile Include="..\..\Quake\snd_codec.c">
<Filter>obsolete</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Quake\anorm_dots.h">
@ -372,12 +375,6 @@
<ClInclude Include="..\..\Quake\server.h">
<Filter>engine</Filter>
</ClInclude>
<ClInclude Include="..\..\Quake\snd_codec.h">
<Filter>engine</Filter>
</ClInclude>
<ClInclude Include="..\..\Quake\snd_codeci.h">
<Filter>engine</Filter>
</ClInclude>
<ClInclude Include="..\..\Quake\spritegn.h">
<Filter>engine</Filter>
</ClInclude>
@ -453,6 +450,12 @@
<ClInclude Include="..\..\FMOD\inc\fmod_output.h">
<Filter>fmod</Filter>
</ClInclude>
<ClInclude Include="..\..\Quake\snd_codeci.h">
<Filter>obsolete</Filter>
</ClInclude>
<ClInclude Include="..\..\Quake\snd_codec.h">
<Filter>obsolete</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="engine">

Loading…
Cancel
Save