client: play arbitrary CDTRACK ogg file

https://github.com/yquake2/yquake2remaster/issues/18
This commit is contained in:
Denis Pauk 2024-07-29 22:50:06 +03:00
parent 005dfa0ed5
commit 87c0029b2b
8 changed files with 145 additions and 58 deletions

View File

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

View File

@ -46,21 +46,21 @@ cvar_t *crosshair_3d_glow_b;
cvar_t *cl_stats;
int r_numdlights;
dlight_t r_dlights[MAX_DLIGHTS];
static int r_numdlights;
static dlight_t r_dlights[MAX_DLIGHTS];
int r_numentities;
entity_t r_entities[MAX_ENTITIES];
static int r_numentities;
static entity_t r_entities[MAX_ENTITIES];
int r_numparticles;
particle_t r_particles[MAX_PARTICLES];
static int r_numparticles;
static particle_t r_particles[MAX_PARTICLES];
lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
static lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
int num_cl_weaponmodels;
void V_Render3dCrosshair(void);
static void V_Render3dCrosshair(void);
/*
* Specifies the model that will be used as the world
@ -139,7 +139,7 @@ V_AddLightStyle(int style, float r, float g, float b)
/*
*If cl_testparticles is set, create 4096 particles in the view
*/
void
static void
V_TestParticles(void)
{
particle_t *p;
@ -169,7 +169,7 @@ V_TestParticles(void)
/*
* If cl_testentities is set, create 32 player models
*/
void
static void
V_TestEntities(void)
{
int i, j;
@ -200,18 +200,20 @@ V_TestEntities(void)
/*
* If cl_testlights is set, create 32 lights models
*/
void
static void
V_TestLights(void)
{
int i, j;
float f, r;
dlight_t *dl;
int i;
r_numdlights = 32;
memset(r_dlights, 0, sizeof(r_dlights));
for (i = 0; i < r_numdlights; i++)
{
dlight_t *dl;
float f, r;
int j;
dl = &r_dlights[i];
r = 64 * ((i % 4) - 1.5f);
@ -362,9 +364,7 @@ CL_PrepRefresh(void)
cl.force_refdef = true; /* make sure we have a valid refdef */
/* start the cd track */
int track = (int)strtol(cl.configstrings[CS_CDTRACK], (char **)NULL, 10);
OGG_PlayTrack(track, true, true);
OGG_PlayTrack(cl.configstrings[CS_CDTRACK], true, true);
}
float
@ -388,14 +388,14 @@ CalcFov(float fov_x, float width, float height)
}
/* gun frame debugging functions */
void
static void
V_Gun_Next_f(void)
{
gun_frame++;
Com_Printf("frame %i\n", gun_frame);
}
void
static void
V_Gun_Prev_f(void)
{
gun_frame--;
@ -408,7 +408,7 @@ V_Gun_Prev_f(void)
Com_Printf("frame %i\n", gun_frame);
}
void
static void
V_Gun_Model_f(void)
{
char name[MAX_QPATH];
@ -423,7 +423,7 @@ V_Gun_Model_f(void)
gun_model = R_RegisterModel(name);
}
int
static int
entitycmpfnc(const entity_t *a, const entity_t *b)
{
/* all other models are sorted by model then skin */
@ -600,7 +600,7 @@ V_RenderView(float stereo_separation)
SCR_DrawCrosshair();
}
void
static void
V_Render3dCrosshair(void)
{
trace_t crosshair_trace;
@ -646,7 +646,7 @@ V_Render3dCrosshair(void)
}
}
void
static void
V_Viewpos_f(void)
{
Com_Printf("position: %i %i %i, angles: %i %i %i\n",

View File

@ -2299,8 +2299,7 @@ EnableOGGMusic(void *unused)
if (cls.state == ca_active)
{
int track = (int)strtol(cl.configstrings[CS_CDTRACK], (char **)NULL, 10);
OGG_PlayTrack(track, true, true);
OGG_PlayTrack(cl.configstrings[CS_CDTRACK], true, true);
}
}
else

View File

@ -37,7 +37,7 @@ typedef enum
int OGG_Status(void);
void OGG_InitTrackList(void);
void OGG_Init(void);
void OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate);
void OGG_PlayTrack(const char* track, qboolean cdtrack, qboolean immediate);
void OGG_RecoverState(void);
void OGG_SaveState(void);
void OGG_Shutdown(void);

View File

@ -64,7 +64,7 @@ enum GameType {
rogue
};
struct {
static struct {
qboolean saved;
int curfile;
int numsamples;
@ -88,15 +88,24 @@ OGG_TogglePlayback(void);
static int getMappedGOGtrack(int track, enum GameType gameType)
{
if(track <= 0)
{
return 0;
}
if(track == 1)
{
return 0; // 1 is illegal (=> data track on CD), 0 means "no track"
}
if(gameType == other)
{
return track;
}
if(gameType == rogue)
{
return track + 10;
}
// apparently it's xatrix => map the track to the corresponding TrackXX.ogg from GOG
switch(track)
@ -185,14 +194,16 @@ OGG_InitTrackList(void)
char testFileName[MAX_OSPATH];
// the simple case (like before: $mod/music/02.ogg - 11.ogg or whatever)
/* the simple case (like before: $mod/music/02.ogg - 11.ogg or whatever) */
snprintf(testFileName, MAX_OSPATH, "%s02.ogg", fullMusicPath);
if(Sys_IsFile(testFileName))
{
int i;
ogg_tracks[2] = strdup(testFileName);
for(int i=3; i<MAX_NUM_OGGTRACKS; ++i)
for(i = 3; i < MAX_NUM_OGGTRACKS; ++i)
{
snprintf(testFileName, MAX_OSPATH, "%s%02i.ogg", fullMusicPath, i);
@ -206,13 +217,15 @@ OGG_InitTrackList(void)
return;
}
// the GOG case: music/Track02.ogg to Track21.ogg
/* the GOG case: music/Track02.ogg to Track21.ogg */
snprintf(testFileName, MAX_OSPATH, "%sTrack%02i.ogg",
fullMusicPath, getMappedGOGtrack(8, gameType));
if(Sys_IsFile(testFileName))
{
for(int i=2; i<MAX_NUM_OGGTRACKS; ++i)
int i;
for(i = 2; i < MAX_NUM_OGGTRACKS; ++i)
{
int gogTrack = getMappedGOGtrack(i, gameType);
@ -227,10 +240,34 @@ OGG_InitTrackList(void)
return;
}
/* the ReRelease case: music/track02.ogg to track79.ogg */
snprintf(testFileName, MAX_OSPATH, "%strack%02i.ogg",
fullMusicPath, getMappedGOGtrack(8, gameType));
if(Sys_IsFile(testFileName))
{
int i;
for(i = 2; i < MAX_NUM_OGGTRACKS; ++i)
{
int gogTrack = getMappedGOGtrack(i, gameType);
snprintf(testFileName, MAX_OSPATH, "%strack%02i.ogg", fullMusicPath, gogTrack);
if(Sys_IsFile(testFileName))
{
ogg_tracks[i] = strdup(testFileName);
ogg_maxfileindex = i;
}
}
return;
}
}
}
// if tracks have been found above, we would've returned there
/* if tracks have been found above, we would've returned there */
Com_Printf("No Ogg Vorbis music tracks have been found, so there will be no music.\n");
}
@ -267,7 +304,7 @@ static OGG_Read(void)
ogg_numbufs = 0;
ogg_numsamples = 0;
OGG_PlayTrack(ogg_curfile, false, false);
OGG_PlayTrack(va("%d", ogg_curfile), false, false);
}
}
@ -357,7 +394,7 @@ OGG_Stream(void)
// Ogg playback has stopped and shuffle was modified, play the map cdtrack.
ogg_shuffle->modified = false;
OGG_PlayTrack(ogg_mapcdtrack, true, true);
OGG_PlayTrack(va("%d", ogg_mapcdtrack), true, true);
}
}
@ -367,8 +404,11 @@ OGG_Stream(void)
* play the ogg file that corresponds to the CD track with the given number
*/
void
OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
OGG_PlayTrack(const char *track, qboolean cdtrack, qboolean immediate)
{
char name[MAX_OSPATH], *path = NULL;
int trackNo;
if (sound_started == SS_NOT)
{
return; // sound is not initialized
@ -379,6 +419,53 @@ OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
return;
}
while (1)
{
int res = 0;
FILE* f;
path = FS_NextPath(path);
if (!path)
{
break;
}
Com_sprintf(name, sizeof(name), "%s/music/%s", path, track);
/* Open ogg vorbis file. */
f = Q_fopen(name, "rb");
if (f == NULL)
{
continue;
}
/* Check running music. */
if (ogg_status == PLAY)
{
OGG_Stop();
}
// fclose is not required on error with close_on_free=true
ogg_file = stb_vorbis_open_file(f, true, &res, NULL);
if (res != 0)
{
Com_Printf("%s: '%s' is not a valid Ogg Vorbis file (error %i).\n",
__func__, name, res);
return;
}
/* Play file. */
ogg_curfile = 0;
ogg_numsamples = 0;
ogg_status = PLAY;
return;
}
trackNo = (int)strtol(track, (char **)NULL, 10);
// Track 0 means "stop music".
if (trackNo == 0)
{
@ -439,7 +526,7 @@ OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
return;
} break;
case 2: // sequential
{
{
newtrack = (curtrack + 1) % (ogg_maxfileindex + 1) != 0 ? (curtrack + 1) : 2;
} break;
case 3: // random
@ -474,7 +561,8 @@ OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
if (ogg_tracks[trackNo] == NULL)
{
Com_Printf("%s: Don't have a .ogg file for track %d\n", __func__, trackNo);
Com_Printf("%s: Don't have a .ogg file for track %d\n",
__func__, trackNo);
}
/* Check running music. */
@ -492,7 +580,8 @@ OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
if (ogg_tracks[trackNo] == NULL)
{
Com_Printf("OGG_PlayTrack: I don't have a file for track %d!\n", trackNo);
Com_Printf("%s: I don't have a file for track %d!\n",
__func__, trackNo);
return;
}
@ -502,7 +591,8 @@ OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
if (f == NULL)
{
Com_Printf("%s: could not open file %s for track %d: %s.\n", __func__, ogg_tracks[trackNo], trackNo, strerror(errno));
Com_Printf("%s: could not open file %s for track %d: %s.\n",
__func__, ogg_tracks[trackNo], trackNo, strerror(errno));
ogg_tracks[trackNo] = NULL;
return;
@ -515,7 +605,8 @@ OGG_PlayTrack(int trackNo, qboolean cdtrack, qboolean immediate)
if (res != 0)
{
Com_Printf("%s: '%s' is not a valid Ogg Vorbis file (error %i).\n", __func__, ogg_tracks[trackNo], res);
Com_Printf("%s: '%s' is not a valid Ogg Vorbis file (error %i).\n",
__func__, ogg_tracks[trackNo], res);
return;
}
@ -626,7 +717,7 @@ OGG_TogglePlayback(void)
/*
* Prints a help message for the 'ogg' cmd.
*/
void
static void
OGG_HelpMsg(void)
{
Com_Printf("Unknown sub command %s\n\n", Cmd_Argv(1));
@ -641,7 +732,7 @@ OGG_HelpMsg(void)
/*
* The 'ogg' cmd. Gives some control and information about the playback state.
*/
void
static void
OGG_Cmd(void)
{
if (Cmd_Argc() < 2)
@ -662,17 +753,7 @@ OGG_Cmd(void)
return;
}
int track = (int)strtol(Cmd_Argv(2), NULL, 10);
if (track < 2 || track > ogg_maxfileindex)
{
Com_Printf("invalid track %s, must be an number between 2 and %d\n", Cmd_Argv(1), ogg_maxfileindex);
return;
}
else
{
OGG_PlayTrack(track, false, true);
}
OGG_PlayTrack(Cmd_Argv(2), false, true);
}
else if (Q_stricmp(Cmd_Argv(1), "stop") == 0)
{
@ -727,7 +808,7 @@ OGG_RecoverState(void)
int shuffle_state = ogg_shuffle->value;
Cvar_SetValue("ogg_shuffle", 0);
OGG_PlayTrack(ogg_saved_state.curfile, false, true);
OGG_PlayTrack(va("%d", ogg_saved_state.curfile), false, true);
stb_vorbis_seek_frame(ogg_file, ogg_saved_state.numsamples);
ogg_numsamples = ogg_saved_state.numsamples;

View File

@ -908,7 +908,14 @@ SP_worldspawn(edict_t *ent)
gi.configstring(CS_SKYAXIS, va("%f %f %f",
st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]));
gi.configstring(CS_CDTRACK, va("%i", ent->sounds));
if (st.music && st.music[0])
{
gi.configstring(CS_CDTRACK, st.music);
}
else
{
gi.configstring(CS_CDTRACK, va("%i", ent->sounds));
}
gi.configstring(CS_MAXCLIENTS, va("%i", (int)(maxclients->value)));

View File

@ -344,6 +344,7 @@ typedef struct
float skyrotate;
vec3_t skyaxis;
char *nextmap;
char *music;
int lip;
int distance;

View File

@ -104,5 +104,6 @@
{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
{"music", STOFS(music), F_LSTRING, FFL_SPAWNTEMP},
{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
{0, 0, 0, 0}