From bc5926be4f0dc213571fd4062cb8a1e3ec42a278 Mon Sep 17 00:00:00 2001 From: apartfromtime <42292382+apartfromtime@users.noreply.github.com> Date: Sat, 29 Apr 2023 13:27:38 +1000 Subject: [PATCH] Sound backend and ogg pause features Playback features outlined in issue #715 . Reintroduce activate\deactivate sound backend when window focus in changed. Added "windowed_pauseonfocuslost" cvar to allowing user control of pause when the window changes focus. Added "ogg_pausewithgame" cvar to allow user control of ogg playback whenever the game is paused. Introduced ogg playback command "mute" as an additional playback option for the console, command buffer and key binds. If the window focus is changed all sound playback will stop and resume as expected. Setting "window_pauseonfocuslost" to 1 will force the game to pause when the window focus is lost, "cl_paused" is ignored in multiplayer. Setting "ogg_pausewithgame" to 1 will force ogg playback to pause whenever the game is paused. Toggling ogg mute through "ogg mute" sets the volume to 0 while playback resumes. --- src/client/cl_console.c | 14 +++++++++++++ src/client/cl_main.c | 11 +++++++++++ src/client/input/sdl.c | 32 ++++++++++++++++++++++++++++++ src/client/menu/menu.c | 14 +++++++++++++ src/client/sound/header/sound.h | 1 + src/client/sound/header/vorbis.h | 1 + src/client/sound/ogg.c | 34 +++++++++++++++++++++++++++++++- src/client/sound/sound.c | 27 +++++++++++++++++++++++++ 8 files changed, 133 insertions(+), 1 deletion(-) diff --git a/src/client/cl_console.c b/src/client/cl_console.c index 4c597704..827ad6db 100644 --- a/src/client/cl_console.c +++ b/src/client/cl_console.c @@ -96,6 +96,13 @@ Con_ToggleConsole_f(void) { M_ForceMenuOff(); Cvar_Set("paused", "0"); + + /* play music */ + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PAUSE) + { + Cbuf_AddText("ogg toggle\n"); + } } else { @@ -106,6 +113,13 @@ Con_ToggleConsole_f(void) Com_ServerState()) { Cvar_Set("paused", "1"); + + /* pause music */ + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PLAY) + { + Cbuf_AddText("ogg toggle\n"); + } } } } diff --git a/src/client/cl_main.c b/src/client/cl_main.c index f91da3c9..85111595 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -309,6 +309,17 @@ CL_Pause_f(void) } Cvar_SetValue("paused", !cl_paused->value); + + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PAUSE && cl_paused->value == 0) /* play music */ + { + Cbuf_AddText("ogg toggle\n"); + } + else if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PLAY && cl_paused->value == 1) /* pause music */ + { + Cbuf_AddText("ogg toggle\n"); + } } void diff --git a/src/client/input/sdl.c b/src/client/input/sdl.c index d65170c5..57c23a88 100644 --- a/src/client/input/sdl.c +++ b/src/client/input/sdl.c @@ -104,6 +104,7 @@ static cvar_t *sensitivity; static cvar_t *exponential_speedup; static cvar_t *in_grab; static cvar_t *m_filter; +static cvar_t *windowed_pauseonfocuslost; static cvar_t *windowed_mouse; static cvar_t *haptic_feedback_filter; @@ -687,6 +688,36 @@ IN_Update(void) event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { Key_MarkAllUp(); + + if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) + { + S_Activate(false); + + if (windowed_pauseonfocuslost->value == 1) + { + Cvar_SetValue("paused", 1); + } + + /* pause music */ + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PLAY && cl.attractloop == false) + { + Cbuf_AddText("ogg toggle\n"); + } + } + + if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) + { + S_Activate(true); + + /* play music */ + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PAUSE && cl.attractloop == false && + cl_paused->value == 0) + { + Cbuf_AddText("ogg toggle\n"); + } + } } else if (event.window.event == SDL_WINDOWEVENT_MOVED) { @@ -2287,6 +2318,7 @@ IN_Init(void) gyro_active = true; } + windowed_pauseonfocuslost = Cvar_Get("windowed_pauseonfocuslost", "0", CVAR_USERINFO | CVAR_ARCHIVE); windowed_mouse = Cvar_Get("windowed_mouse", "1", CVAR_USERINFO | CVAR_ARCHIVE); Cmd_AddCommand("+mlook", IN_MLookDown); diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index 0bdab0e9..e3166210 100644 --- a/src/client/menu/menu.c +++ b/src/client/menu/menu.c @@ -124,6 +124,13 @@ M_ForceMenuOff(void) void M_PopMenu(void) { + /* play music */ + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PAUSE && cl.attractloop == false) + { + Cbuf_AddText("ogg toggle\n"); + } + S_StartLocalSound(menu_out_sound); if (m_menudepth < 1) @@ -179,6 +186,13 @@ M_PushMenu(void (*draw)(void), const char *(*key)(int)) } #endif + /* pause music */ + if (Cvar_VariableValue("ogg_pausewithgame") == 1 && + OGG_Status() == PLAY && cl.attractloop == false) + { + Cbuf_AddText("ogg toggle\n"); + } + /* if this menu is already open (and on top), close it => toggling behaviour */ if ((m_drawfunc == draw) && (m_keyfunc == key)) diff --git a/src/client/sound/header/sound.h b/src/client/sound/header/sound.h index fee53e41..88b32af6 100644 --- a/src/client/sound/header/sound.h +++ b/src/client/sound/header/sound.h @@ -30,6 +30,7 @@ struct sfx_s; +void S_Activate(qboolean active); void S_Init(void); void S_Shutdown(void); diff --git a/src/client/sound/header/vorbis.h b/src/client/sound/header/vorbis.h index 0f05e5a2..5389a5a8 100644 --- a/src/client/sound/header/vorbis.h +++ b/src/client/sound/header/vorbis.h @@ -34,6 +34,7 @@ typedef enum STOP } ogg_status_t; +int OGG_Status(void); void OGG_InitTrackList(void); void OGG_Init(void); void OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate); diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index c37e0e42..7d588f2e 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -40,6 +40,7 @@ #define STB_VORBIS_NO_PUSHDATA_API #include "header/stb_vorbis.h" +static cvar_t *ogg_pausewithgame; /* Pause music when the game is paused */ static cvar_t *ogg_enabled; /* Backend is enabled */ static cvar_t *ogg_shuffle; /* Shuffle playback */ static cvar_t *ogg_ignoretrack0; /* Toggle track 0 playing */ @@ -51,6 +52,7 @@ static int ogg_mapcdtrack; /* Index of current map cdtrack */ static ogg_status_t ogg_status; /* Status indicator. */ static stb_vorbis *ogg_file; /* Ogg Vorbis file. */ static qboolean ogg_started; /* Initialization flag. */ +static qboolean ogg_mutemusic; /* Mute music */ enum { MAX_NUM_OGGTRACKS = 128 }; static char* ogg_tracks[MAX_NUM_OGGTRACKS]; @@ -68,6 +70,9 @@ struct { int numsamples; } ogg_saved_state; +static void +OGG_TogglePlayback(void); + // -------- /* @@ -238,6 +243,7 @@ void static OGG_Read(void) { short samples[4096] = {0}; + float volume = (ogg_mutemusic == true) ? 0.0f : ogg_volume->value; int read_samples = stb_vorbis_get_samples_short_interleaved(ogg_file, ogg_file->channels, samples, sizeof(samples) / sizeof(short)); @@ -247,7 +253,7 @@ static OGG_Read(void) ogg_numsamples += read_samples; S_RawSamples(read_samples, ogg_file->sample_rate, sizeof(short), ogg_file->channels, - (byte *)samples, ogg_volume->value); + (byte *)samples, volume); } else { @@ -285,6 +291,17 @@ OGG_Stream(void) return; } + if (ogg_pausewithgame->modified) + { + if ((ogg_pausewithgame->value == 0 && ogg_status == PAUSE) || + (ogg_pausewithgame->value == 1 && ogg_status == PLAY)) + { + OGG_TogglePlayback(); + } + + ogg_pausewithgame->modified = false; + } + if (ogg_status == PLAY) { #ifdef USE_OPENAL @@ -618,6 +635,7 @@ OGG_HelpMsg(void) Com_Printf(" - play : Play track number \n"); Com_Printf(" - stop: Stop playback\n"); Com_Printf(" - toggle: Toggle pause\n"); + Com_Printf(" - mute: Mute playback\n"); } /* @@ -664,6 +682,10 @@ OGG_Cmd(void) { OGG_TogglePlayback(); } + else if (Q_stricmp(Cmd_Argv(1), "mute") == 0) + { + ogg_mutemusic = !ogg_mutemusic; + } else { OGG_HelpMsg(); @@ -712,6 +734,14 @@ OGG_RecoverState(void) Cvar_SetValue("ogg_shuffle", shuffle_state); } +/* + * Returns ogg status. + */ +int +OGG_Status(void) +{ + return ogg_status; +} // -------- /* @@ -721,6 +751,7 @@ void OGG_Init(void) { // Cvars + ogg_pausewithgame = Cvar_Get("ogg_pausewithgame", "0", CVAR_ARCHIVE); ogg_shuffle = Cvar_Get("ogg_shuffle", "0", CVAR_ARCHIVE); ogg_ignoretrack0 = Cvar_Get("ogg_ignoretrack0", "0", CVAR_ARCHIVE); ogg_volume = Cvar_Get("ogg_volume", "0.7", CVAR_ARCHIVE); @@ -741,6 +772,7 @@ OGG_Init(void) ogg_mapcdtrack = 0; + ogg_mutemusic = false; ogg_started = true; } diff --git a/src/client/sound/sound.c b/src/client/sound/sound.c index 8007df97..513c5bfa 100644 --- a/src/client/sound/sound.c +++ b/src/client/sound/sound.c @@ -89,6 +89,7 @@ static sfx_t known_sfx[MAX_SFX]; sndstarted_t sound_started = SS_NOT; sound_t sound; static qboolean s_registering; +qboolean s_active; qboolean snd_is_underwater; qboolean snd_is_underwater_enabled; @@ -1066,6 +1067,13 @@ S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, return; } + /* A hack to prevent temporary entities generating sounds when the sound + backend is not active and the game is not paused */ + if (s_active == false) + { + return; + } + if (!sfx) { return; @@ -1412,6 +1420,11 @@ S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) return; } + if (s_active == false) + { + return; + } + VectorCopy(origin, listener_origin); VectorCopy(forward, listener_forward); VectorCopy(right, listener_right); @@ -1564,6 +1577,19 @@ S_SoundInfo_f(void) } } +/* + * Activate or deactivate sound backend + */ +void S_Activate(qboolean active) +{ + s_active = active; + + if (active == false) + { + S_StopAllSounds(); + } +} + /* * Initializes the sound system * and it's requested backend @@ -1630,6 +1656,7 @@ S_Init(void) num_sfx = 0; paintedtime = 0; sound_max = 0; + s_active = true; OGG_Init();