Playback Features

Playback features outlined in issue #729.

Added shuffle playback parameters:

default - Ogg track currently active repeats. This is the quake2 default behaviour.
play once - Ogg track currently active plays once then stops.
sequential - Ogg tracks play in numerical order, from the currently playing track and like default repeats.
random - Ogg tracks play randomly, but never the same track twice.

Ogg tracks can be played from a full-screen console and tracks played will adhere to the shuffle parameter.

Loading a game map the map cd-track takes precedence as the first played track then subsequent playback of tracks will adhere to the shuffle parameter.

Any currently playing track can be overridden from the console with "ogg play <track>" command and subsequent playback of tracks will adhere to the shuffle parameter.

If a sound restart occurs the ogg backend will attempt to save and recover the currently playing track, though some data in the audio queue may be lost in the process.
This commit is contained in:
apartfromtime 2023-03-26 14:43:28 +11:00
parent c2d80c64ee
commit f96deee197
5 changed files with 102 additions and 25 deletions

View file

@ -1095,7 +1095,9 @@ CL_ParseConfigString(void)
{
if (cl.refresh_prepped)
{
OGG_PlayTrack((int)strtol(cl.configstrings[CS_CDTRACK], (char **)NULL, 10));
int track = (int)strtol(cl.configstrings[CS_CDTRACK], (char **)NULL, 10);
OGG_PlayTrack(track, true, true);
}
}
else if ((i >= CS_MODELS) && (i < CS_MODELS + MAX_MODELS))

View file

@ -363,8 +363,8 @@ CL_PrepRefresh(void)
/* start the cd track */
int track = (int)strtol(cl.configstrings[CS_CDTRACK], (char **)NULL, 10);
OGG_PlayTrack(track);
OGG_PlayTrack(track, true, true);
}
float

View file

@ -2174,7 +2174,7 @@ FreeLookFunc(void *unused)
static void
ControlsSetMenuItemValues(void)
{
s_options_oggshuffle_box.curvalue = (Cvar_VariableValue("ogg_shuffle") != 0);
s_options_oggshuffle_box.curvalue = Cvar_VariableValue("ogg_shuffle");
s_options_oggenable_box.curvalue = (Cvar_VariableValue("ogg_enable") != 0);
s_options_quality_list.curvalue = (Cvar_VariableValue("s_loadas8bit") == 0);
s_options_alwaysrun_box.curvalue = (cl_run->value != 0);
@ -2192,6 +2192,7 @@ ControlsResetDefaultsFunc(void *unused)
Cbuf_Execute();
ControlsSetMenuItemValues();
s_options_oggshuffle_box.curvalue = 0;
}
static void
@ -2226,7 +2227,7 @@ EnableOGGMusic(void *unused)
if (cls.state == ca_active)
{
int track = (int)strtol(cl.configstrings[CS_CDTRACK], (char **)NULL, 10);
OGG_PlayTrack(track);
OGG_PlayTrack(track, true, true);
}
}
else
@ -2292,6 +2293,15 @@ Options_MenuInit(void)
{
extern qboolean show_gamepad;
static const char *ogg_shuffle_items[] =
{
"default",
"play once",
"sequential",
"random",
0
};
static const char *able_items[] =
{
"disabled",
@ -2356,7 +2366,7 @@ Options_MenuInit(void)
s_options_oggshuffle_box.generic.y = (y += 10);
s_options_oggshuffle_box.generic.name = "OGG shuffle";
s_options_oggshuffle_box.generic.callback = OGGShuffleFunc;
s_options_oggshuffle_box.itemnames = able_items;
s_options_oggshuffle_box.itemnames = ogg_shuffle_items;
s_options_quality_list.generic.type = MTYPE_SPINCONTROL;
s_options_quality_list.generic.x = 0;

View file

@ -36,7 +36,7 @@ typedef enum
void OGG_InitTrackList(void);
void OGG_Init(void);
void OGG_PlayTrack(int trackNo);
void OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate);
void OGG_RecoverState(void);
void OGG_SaveState(void);
void OGG_Shutdown(void);

View file

@ -47,6 +47,7 @@ static cvar_t *ogg_volume; /* Music volume. */
static int ogg_curfile; /* Index of currently played file. */
static int ogg_numbufs; /* Number of buffers for OpenAL */
static int ogg_numsamples; /* Number of sambles read from the current file */
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. */
@ -260,7 +261,7 @@ static OGG_Read(void)
ogg_numbufs = 0;
ogg_numsamples = 0;
OGG_PlayTrack(ogg_curfile);
OGG_PlayTrack(ogg_curfile, false, false);
}
}
@ -323,6 +324,24 @@ OGG_Stream(void)
}
}
}
if (ogg_status == PLAY && ogg_shuffle->modified)
{
// Shuffle was modified before last track finished.
ogg_shuffle->modified = false;
}
else if (ogg_status == STOP && ogg_shuffle->modified)
{
// If fullscreen console, clear the map cdtrack.
if (cls.state == ca_disconnected)
{
ogg_mapcdtrack = 0; // Track 0 means "stop music".
}
// Ogg playback has stopped and shuffle was modified, play the map cdtrack.
ogg_shuffle->modified = false;
OGG_PlayTrack(ogg_mapcdtrack, true, true);
}
}
// --------
@ -331,7 +350,7 @@ OGG_Stream(void)
* play the ogg file that corresponds to the CD track with the given number
*/
void
OGG_PlayTrack(int trackNo)
OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
{
if (sound_started == SS_NOT)
{
@ -344,7 +363,7 @@ OGG_PlayTrack(int trackNo)
}
// Track 0 means "stop music".
if(trackNo == 0)
if (trackNo == 0)
{
if(ogg_ignoretrack0->value == 0)
{
@ -367,21 +386,65 @@ OGG_PlayTrack(int trackNo)
}
}
// Player has requested shuffle playback.
if((trackNo == 0) || ogg_shuffle->value)
if (cdtrack == true) // the map cdtrack.
{
if(ogg_maxfileindex >= 0)
{
trackNo = randk() % (ogg_maxfileindex+1);
int retries = 100;
while(ogg_tracks[trackNo] == NULL && retries-- > 0)
{
trackNo = randk() % (ogg_maxfileindex+1);
}
}
ogg_mapcdtrack = trackNo;
}
if(ogg_maxfileindex == -1)
int playback = ogg_shuffle->value;
int curtrack = 0;
// If loading a map, restarting sound or video, the ogg backend or console issued
// a playtrack or no tracks have been played, apply shuffle parameters to the next
// track.
if ((immediate == false && (cls.state == ca_connecting || cls.state == ca_connected)) ||
immediate == true || ogg_curfile == -1)
{
curtrack = trackNo;
playback = 0;
}
else
{
curtrack = ogg_curfile;
}
int newtrack = 0;
// These must match those in menu.c - Options_MenuInit().
switch (playback)
{
case 0: // default
{
newtrack = curtrack;
} break;
case 1: // play once
{
return;
} break;
case 2: // sequential
{
newtrack = (curtrack + 1) % (ogg_maxfileindex + 1) != 0 ? (curtrack + 1) : 2;
} break;
case 3: // random
{
int retries = 100;
newtrack = 0;
while (retries-- > 0 && newtrack < 2)
{
newtrack = randk() % (ogg_maxfileindex + 1);
if (newtrack == curtrack)
{
newtrack = 0;
}
}
} break;
}
trackNo = newtrack;
if (ogg_maxfileindex == -1)
{
return; // no ogg files at all, ignore this silently instead of printing warnings all the time
}
@ -392,7 +455,7 @@ OGG_PlayTrack(int trackNo)
return;
}
if(ogg_tracks[trackNo] == NULL)
if (ogg_tracks[trackNo] == NULL)
{
Com_Printf("%s: Don't have a .ogg file for track %d\n", __func__, trackNo);
}
@ -592,7 +655,7 @@ OGG_Cmd(void)
}
else
{
OGG_PlayTrack(track);
OGG_PlayTrack(track, false, true);
}
}
else if (Q_stricmp(Cmd_Argv(1), "stop") == 0)
@ -644,7 +707,7 @@ OGG_RecoverState(void)
int shuffle_state = ogg_shuffle->value;
Cvar_SetValue("ogg_shuffle", 0);
OGG_PlayTrack(ogg_saved_state.curfile);
OGG_PlayTrack(ogg_saved_state.curfile, false, true);
stb_vorbis_seek_frame(ogg_file, ogg_saved_state.numsamples);
ogg_numsamples = ogg_saved_state.numsamples;
@ -678,6 +741,8 @@ OGG_Init(void)
ogg_numsamples = 0;
ogg_status = STOP;
ogg_mapcdtrack = 0;
ogg_started = true;
}