Merge branch 'music-technology' into 'master'

Replace music handling

See merge request KartKrew/Kart!1369
This commit is contained in:
James R 2023-08-08 22:19:36 +00:00
commit e89ecc7a2d
34 changed files with 1321 additions and 1918 deletions

View file

@ -148,6 +148,8 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
k_mapuser.c
k_powerup.cpp
k_hitlag.c
music.cpp
music_manager.cpp
)
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)

View file

@ -63,6 +63,7 @@
#include "k_vote.h"
#include "k_serverstats.h"
#include "k_zvote.h"
#include "music.h"
// cl loading screen
#include "v_video.h"
@ -2747,7 +2748,10 @@ static void Command_connect(void)
// Menu restore state.
restoreMenu = &PLAY_MP_OptSelectDef;
S_ChangeMusicInternal("NETMD2", true);
Music_Remap("menu", "NETMD2");
Music_Play("menu");
if (setup_numplayers == 0)
{
setup_numplayers = 1;

View file

@ -83,6 +83,7 @@
#include "k_podium.h"
#include "k_vote.h"
#include "k_serverstats.h"
#include "music.h"
#ifdef HWRENDER
#include "hardware/hw_main.h" // 3D View Rendering
@ -926,6 +927,8 @@ void D_SRB2Loop(void)
}
#endif
Music_Tick();
// Fully completed frame made.
finishprecise = I_GetPreciseTime();
if (!singletics)
@ -1015,8 +1018,7 @@ void D_ClearState(void)
//
void D_StartTitle(void)
{
if (!demo.title)
S_StopMusic();
Music_StopAll();
D_ClearState();
F_StartTitleScreen();
@ -1654,6 +1656,9 @@ void D_SRB2Main(void)
I_InitMusic();
S_InitSfxChannels(cv_soundvolume.value);
}
Music_Init();
CON_SetLoadingProgress(LOADED_SINITSFXCHANNELS);
S_InitMusicDefs();

View file

@ -6609,14 +6609,6 @@ struct int_const_s const INT_CONST[] = {
{"int_score",int_score},
{"int_scoreortimeattack", int_scoreortimeattack},
// Jingles (jingletype_t)
{"JT_NONE",JT_NONE},
{"JT_OTHER",JT_OTHER},
{"JT_MASTER",JT_MASTER},
{"JT_INVINCIBILITY",JT_INVINCIBILITY},
{"JT_GROW",JT_GROW},
// Overlay exception settings
{"OV_DONTSCREENOFFSET", OV_DONTSCREENOFFSET},
{"OV_DONT3DOFFSET", OV_DONT3DOFFSET},

View file

@ -46,6 +46,7 @@
// SRB2Kart
#include "k_menu.h"
#include "k_grandprix.h"
#include "music.h"
// Stage of animation:
// 0 = text, 1 = art screen
@ -298,8 +299,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
void F_StartIntro(void)
{
S_StopMusicCredit();
if (gamestate)
{
F_WipeStartScreen();
@ -308,7 +307,7 @@ void F_StartIntro(void)
F_RunWipe(wipe_intro_toblack, wipedefs[wipe_intro_toblack], false, "FADEMAP0", false, false);
}
S_StopMusic();
Music_StopAll();
S_StopSounds();
if (introtoplay)
@ -331,7 +330,8 @@ void F_StartIntro(void)
intro_scenenum = 0;
finalecount = animtimer = skullAnimCounter = stoptimer = 0;
timetonext = introscenetime[intro_scenenum];
S_StopMusic();
Music_StopAll();
}
//
@ -701,11 +701,10 @@ void F_StartCredits(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
S_StopMusic();
Music_StopAll();
S_StopSounds();
S_ChangeMusicInternal("_creds", false);
S_ShowMusicCredit();
Music_Play("credits");
finalecount = 0;
animtimer = 0;
@ -907,7 +906,9 @@ UINT16 finaleemeralds = 0;
void F_StartGameEvaluation(void)
{
S_FadeMusic(0, MUSICRATE/4);
Music_DelayEnd("credits", TICRATE/4);
Music_Tick(); // it needs to fade out right now
S_StopMusicCredit();
// Credits option in extras menu
@ -1253,7 +1254,8 @@ void F_GameEvaluationTicker(void)
if (finalecount == 1)
{
// sitting on that distant _shore
S_ChangeMusicInternal("_SHORE", false);
Music_Remap("shore", "_SHORE");
Music_Play("shore");
}
}
else
@ -1261,7 +1263,8 @@ void F_GameEvaluationTicker(void)
if (finalecount == 1)
{
// _drift across open waters
S_ChangeMusicInternal("_DRIFT", false);
Music_Remap("shore", "_DRIFT");
Music_Play("shore");
}
}
@ -1766,8 +1769,12 @@ void F_TitleScreenTicker(boolean run)
{
if (finalecount == 0)
{
// Now start the music
S_ChangeMusicInternal("_title", looptitle);
if (!Music_Playing("title"))
{
// Now start the music
Music_Loop("title", looptitle);
Music_Play("title");
}
}
else if (menumessage.active)
{
@ -1956,7 +1963,7 @@ void F_WaitingPlayersTicker(void)
// dumb hack, only start the music on the 1st tick so if you instantly go into the map you aren't hearing a tic of music
if (finalecount == 2)
S_ChangeMusicInternal("WAIT2J", true);
Music_Play("wait");
}
void F_WaitingPlayersDrawer(void)
@ -2002,11 +2009,14 @@ static void F_AdvanceToNextScene(void)
picxpos = cutscenes[cutnum]->scene[scenenum].xcoord[picnum];
picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
// FIXME - port to new music system
#if 0
if (cutscenes[cutnum]->scene[scenenum].musswitch[0])
S_ChangeMusicEx(cutscenes[cutnum]->scene[scenenum].musswitch,
cutscenes[cutnum]->scene[scenenum].musswitchflags,
cutscenes[cutnum]->scene[scenenum].musicloop,
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
#endif
// Fade to the next
F_NewCutscene(cutscenes[cutnum]->scene[scenenum].text);
@ -2075,6 +2085,8 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
animtimer = cutscenes[cutnum]->scene[0].picduration[0]; // Picture duration
stoptimer = 0;
// FIXME - port to new music system
#if 0
if (cutscenes[cutnum]->scene[0].musswitch[0])
S_ChangeMusicEx(cutscenes[cutnum]->scene[0].musswitch,
cutscenes[cutnum]->scene[0].musswitchflags,
@ -2082,6 +2094,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
else
S_StopMusic();
#endif
S_StopSounds();
}
@ -2365,11 +2378,14 @@ static void F_AdvanceToNextPage(void)
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
// FIXME - port to new music system
#if 0
// music change
if (textprompts[cutnum]->page[scenenum].musswitch[0])
S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch,
textprompts[cutnum]->page[scenenum].musswitchflags,
textprompts[cutnum]->page[scenenum].musicloop);
#endif
}
}
@ -2453,11 +2469,14 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
// FIXME - port to new music system
#if 0
// music change
if (textprompts[cutnum]->page[scenenum].musswitch[0])
S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch,
textprompts[cutnum]->page[scenenum].musswitchflags,
textprompts[cutnum]->page[scenenum].musicloop);
#endif
// get the calling player
if (promptblockcontrols && mo && mo->player)

View file

@ -69,6 +69,7 @@
#include "k_vote.h"
#include "k_serverstats.h"
#include "k_zvote.h"
#include "music.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
@ -2402,7 +2403,7 @@ void G_Ticker(boolean run)
musiccountdown--;
if (musiccountdown == 1)
{
S_ChangeMusicInternal("racent", true);
Music_Play("intermission");
}
else if (musiccountdown == (MUSICCOUNTDOWNMAX - (3*TICRATE)/2))
{
@ -2410,6 +2411,8 @@ void G_Ticker(boolean run)
}
}
P_InvincGrowMusic();
K_TickMidVote();
}
}
@ -2510,7 +2513,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT32 itemtype;
INT32 itemamount;
INT32 growshrinktimer;
boolean songcredit = false;
UINT16 nocontrol;
INT32 khudfault;
INT32 kickstartaccel;
@ -2850,11 +2852,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
if (exiting)
return;
P_RestoreMusic(p);
if (songcredit)
S_ShowMusicCredit();
}
//
@ -4695,7 +4692,7 @@ void G_EndGame(void)
// In a netgame, don't unwittingly boot everyone.
if (netgame)
{
S_StopMusic();
Music_StopAll();
G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat
if (server)

View file

@ -47,6 +47,7 @@
#include "k_podium.h"
#include "k_powerup.h"
#include "k_hitlag.h"
#include "music.h"
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
@ -3847,8 +3848,6 @@ void K_RemoveGrowShrink(player_t *player)
}
player->growshrinktimer = 0;
P_RestoreMusic(player);
}
boolean K_IsBigger(mobj_t *compare, mobj_t *other)
@ -4384,7 +4383,7 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A
{
P_DamageMobj(player->mo, inflictor, source, 1, DMG_INSTAKILL);
player->SPBdistance = 0;
S_StopMusic();
Music_StopAll();
}
spbMultiplier = inflictor->movefactor;
@ -6201,18 +6200,12 @@ void K_DoInvincibility(player_t *player, tic_t time)
P_SetScale(overlay, player->mo->scale);
}
if (P_IsLocalPlayer(player) == true && player->invincibilitytimer == 0)
{
S_ChangeMusicSpecial("kinvnc");
}
else //used to be "if (P_IsDisplayPlayer(player) == false)"
if (P_IsLocalPlayer(player) == false)
{
S_StartSound(player->mo, sfx_alarmi);
}
player->invincibilitytimer += time;
P_RestoreMusic(player);
}
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source)
@ -11285,25 +11278,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
}
if (player->invincibilitytimer > 0)
{
; // invincibility has priority in P_RestoreMusic, no point in starting here
}
else if (P_IsLocalPlayer(player) == true)
{
if (player->growshrinktimer < 1)
S_ChangeMusicSpecial("kgrow");
}
else //used to be "if (P_IsDisplayPlayer(player) == false)"
if (P_IsLocalPlayer(player) == false && player->invincibilitytimer == 0)
{
// don't play this if the player has invincibility -- that takes priority
S_StartSound(player->mo, sfx_alarmg);
}
player->growshrinktimer = max(0, player->growshrinktimer);
player->growshrinktimer += ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE;
P_RestoreMusic(player);
S_StartSound(player->mo, sfx_kc5a);
player->itemamount--;
@ -11938,7 +11921,7 @@ void K_CheckSpectateStatus(boolean considermapreset)
// Reset the match when 3P joins 1P and 2P, DUEL mode must be disabled
if (i > 0 && !mapreset && gamestate == GS_LEVEL && (numingame < 3 && numingame+i >= 2))
{
S_ChangeMusicInternal("chalng", false); // COME ON
Music_Play("comeon"); // COME ON
mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD
}
}

View file

@ -61,6 +61,9 @@
// Condition Sets
#include "m_cond.h"
// Sound Test
#include "music.h"
// And just some randomness for the exits.
#include "m_random.h"
@ -6477,22 +6480,22 @@ void M_DrawSoundTest(void)
titleoffset += titlewidth;
}
V_DrawRightAlignedString(x + 272-1, 18+32, 0,
va("%02u:%02u",
G_TicsToMinutes(soundtest.currenttime, true),
G_TicsToSeconds(soundtest.currenttime)
)
);
{
UINT32 currenttime = min(Music_Elapsed(soundtest.tune), Music_TotalDuration(soundtest.tune));
V_DrawRightAlignedString(x + 272-1, 18+32, 0,
va("%02u:%02u",
G_TicsToMinutes(currenttime, true),
G_TicsToSeconds(currenttime)
)
);
}
if ((soundtest.playing && soundtest.current)
&& (soundtest.current->basenoloop[soundtest.currenttrack] == true
|| soundtest.autosequence == true))
{
UINT32 exittime = soundtest.sequencemaxtime;
if (soundtest.dosequencefadeout == true)
{
exittime += SOUNDTEST_FADEOUTSECONDS*TICRATE;
}
UINT32 exittime = Music_TotalDuration(soundtest.tune);
V_DrawRightAlignedString(x + 272-1, 18+32+10, 0,
va("%02u:%02u",
@ -6546,12 +6549,12 @@ void M_DrawSoundTest(void)
// The following are springlocks.
else if (currentMenu->menuitems[i].mvar2 == stereospecial_pause) // pause
{
if (soundtest.paused == true)
if (Music_Paused(soundtest.tune) == true)
y = currentMenu->y + 6;
}
else if (currentMenu->menuitems[i].mvar2 == stereospecial_play) // play
{
if (soundtest.playing == true && soundtest.paused == false)
if (soundtest.playing == true && Music_Paused(soundtest.tune) == false)
y = currentMenu->y + 6;
}
else if (currentMenu->menuitems[i].mvar2 == stereospecial_seq) // seq

View file

@ -16,6 +16,7 @@
#include "f_finale.h"
#include "m_misc.h"
#include "m_cond.h"
#include "music.h"
#ifdef PC_DOS
#include <stdio.h> // for snprintf
@ -366,7 +367,7 @@ boolean M_Responder(event_t *ev)
return true;
}
#define NotCurrentlyPlaying(desiredname) (!S_MusicPlaying() || strcmp(desiredname, S_MusicName()))
#define NotCurrentlyPlaying(desiredname) strcmp(desiredname, Music_CurrentSong())
void M_PlayMenuJam(void)
{
@ -375,8 +376,7 @@ void M_PlayMenuJam(void)
if (challengesmenu.pending)
{
S_StopMusic();
S_StopMusicCredit();
Music_StopAll();
musicstatepermitted = true;
return;
@ -391,16 +391,15 @@ void M_PlayMenuJam(void)
{
if (refMenu->music[0] == '.' && refMenu->music[1] == '\0')
{
S_StopMusic();
S_StopMusicCredit();
Music_StopAll();
return;
}
else if (override == 0)
{
if (NotCurrentlyPlaying(refMenu->music))
{
S_ChangeMusicInternal(refMenu->music, true);
S_ShowMusicCredit();
Music_Remap("menu", refMenu->music);
Music_Play("menu");
}
return;
}
@ -416,8 +415,8 @@ void M_PlayMenuJam(void)
if (refMenu != NULL && NotCurrentlyPlaying(overridetotrack[override - 1]))
{
S_ChangeMusicInternal(overridetotrack[override - 1], true);
S_ShowMusicCredit();
Music_Remap("menu", overridetotrack[override - 1]);
Music_Play("menu");
if (override < GDMUSIC_KEEPONMENU)
gamedata->musicstate = GDMUSIC_NONE;
@ -435,8 +434,8 @@ void M_PlayMenuJam(void)
if (!NotCurrentlyPlaying(cv_menujam.string))
return;
S_ChangeMusicInternal(cv_menujam.string, true);
S_ShowMusicCredit();
Music_Remap("menu", cv_menujam.string);
Music_Play("menu");
}
#undef IsCurrentlyPlaying
@ -574,6 +573,8 @@ void M_StartControlPanel(void)
modeattacking = ATTACKING_NONE;
}
Music_Stop("title");
if (cv_currprofile.value == -1) // Only ask once per session.
{
// Make sure the profile data is ready now since we need to select a profile.
@ -596,7 +597,8 @@ void M_StartControlPanel(void)
CV_StealthSetValue(&cv_currprofile, -1); // Make sure to reset that as it is set by PR_ApplyProfile which we kind of hack together to force it.
// Ambient ocean sounds
S_ChangeMusicInternal("_OCEAN", true);
Music_Remap("menu_nocred", "_OCEAN");
Music_Play("menu_nocred");
}
else
{

View file

@ -51,6 +51,7 @@
#include "k_pwrlv.h"
#include "k_grandprix.h"
#include "k_color.h"
#include "music.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -1174,7 +1175,7 @@ static void Y_TickVoteRoulette(void)
vote.roulette.endOffset++;
}
S_ChangeMusicInternal("voteeb", false);
Music_Play("vote_end");
break;
}
}
@ -1461,8 +1462,7 @@ void Y_VoteTicker(void)
if (vote.tic == 0)
{
S_ChangeMusicInternal("vote", true);
S_ShowMusicCredit();
Music_Play("vote");
}
if (g_pickedVote != VOTE_NOT_PICKED)
@ -1728,13 +1728,13 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level)
{
// Only one unique vote, so just end it immediately.
vote.endtic = vote.tic + (5*TICRATE);
S_ChangeMusicInternal("voteeb", false);
Music_Play("vote_end");
Y_VoteStops(pick, level);
break;
}
default:
{
S_ChangeMusicInternal("voteea", true);
Music_Play("vote_suspense");
break;
}
}

View file

@ -1185,72 +1185,6 @@ static int lib_pSetObjectMomZ(lua_State *L)
return 0;
}
static int lib_pPlayJingle(lua_State *L)
{
player_t *player = NULL;
jingletype_t jingletype = luaL_checkinteger(L, 2);
//NOHUD
//INLEVEL
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (jingletype >= NUMJINGLES)
return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1);
P_PlayJingle(player, jingletype);
return 0;
}
static int lib_pPlayJingleMusic(lua_State *L)
{
player_t *player = NULL;
const char *musnamearg = luaL_checkstring(L, 2);
char musname[7], *p = musname;
UINT16 musflags = luaL_optinteger(L, 3, 0);
boolean looping = lua_opttrueboolean(L, 4);
jingletype_t jingletype = luaL_optinteger(L, 5, JT_OTHER);
//NOHUD
//INLEVEL
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (jingletype >= NUMJINGLES)
return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1);
musname[6] = '\0';
strncpy(musname, musnamearg, 6);
while (*p) {
*p = tolower(*p);
++p;
}
P_PlayJingleMusic(player, musname, musflags, looping, jingletype);
return 0;
}
static int lib_pRestoreMusic(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//NOHUD
//INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (P_IsLocalPlayer(player))
{
P_RestoreMusic(player);
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_pSpawnGhostMobj(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -2536,349 +2470,6 @@ static int lib_sStopSoundByID(lua_State *L)
return 0;
}
static int lib_sChangeMusic(lua_State *L)
{
const char *music_name = luaL_checkstring(L, 1);
UINT32 position, prefadems, fadeinms;
boolean looping = (boolean)lua_opttrueboolean(L, 2);
player_t *player = NULL;
UINT16 music_flags = 0;
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
music_flags = (UINT16)luaL_optinteger(L, 4, 0);
position = (UINT32)luaL_optinteger(L, 5, 0);
prefadems = (UINT32)luaL_optinteger(L, 6, 0);
fadeinms = (UINT32)luaL_optinteger(L, 7, 0);
if (!player || P_IsLocalPlayer(player))
{
S_ChangeMusicEx(music_name, music_flags, looping, position, prefadems, fadeinms);
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sSpeedMusic(lua_State *L)
{
fixed_t fixedspeed = luaL_checkfixed(L, 1);
float speed = FIXED_TO_FLOAT(fixedspeed);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_SpeedMusic(speed));
else
lua_pushnil(L);
return 1;
}
static int lib_sMusicType(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushstring(L, S_MusicType());
else
lua_pushnil(L);
return 1;
}
static int lib_sMusicPlaying(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_MusicPlaying());
else
lua_pushnil(L);
return 1;
}
static int lib_sMusicPaused(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_MusicPaused());
else
lua_pushnil(L);
return 1;
}
static int lib_sMusicName(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushstring(L, S_MusicName());
else
lua_pushnil(L);
return 1;
}
static int lib_sSetMusicLoopPoint(lua_State *L)
{
UINT32 looppoint = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_SetMusicLoopPoint(looppoint));
else
lua_pushnil(L);
return 1;
}
static int lib_sGetMusicLoopPoint(lua_State *L)
{
lua_pushinteger(L, S_GetMusicLoopPoint());
return 1;
}
static int lib_sGetMusicLength(lua_State *L)
{
lua_pushinteger(L, S_GetMusicLength());
return 1;
}
static int lib_sGetMusicPosition(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
lua_pushinteger(L, (int)S_GetMusicPosition());
else
lua_pushnil(L);
return 1;
}
static int lib_sSetMusicPosition(lua_State *L)
{
UINT32 pos = (UINT32)luaL_checkinteger(L, 1);
lua_pushboolean(L, S_SetMusicPosition(pos));
return 1;
}
static int lib_sStopMusic(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_StopMusic();
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sPauseMusic(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_PauseAudio();
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sResumeMusic(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_ResumeAudio();
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sMusicExists(lua_State *L)
{
const char *music_name = luaL_checkstring(L, 1);
NOHUD
lua_pushboolean(L, S_MusicExists(music_name));
return 1;
}
static int lib_sSetInternalMusicVolume(lua_State *L)
{
UINT32 volume = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_SetInternalMusicVolume(volume);
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sStopFadingMusic(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_StopFadingMusic();
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sFadeMusic(lua_State *L)
{
UINT32 target_volume = (UINT32)luaL_checkinteger(L, 1);
UINT32 ms;
INT32 source_volume;
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
ms = (UINT32)luaL_checkinteger(L, 2);
source_volume = -1;
}
else if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
{
player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
source_volume = (INT32)luaL_checkinteger(L, 2);
ms = (UINT32)luaL_checkinteger(L, 3);
}
else if (luaL_optinteger(L, 3, INT32_MAX) == INT32_MAX)
{
ms = (UINT32)luaL_checkinteger(L, 2);
source_volume = -1;
}
else
{
source_volume = (INT32)luaL_checkinteger(L, 2);
ms = (UINT32)luaL_checkinteger(L, 3);
}
NOHUD
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_FadeMusicFromVolume(target_volume, source_volume, ms));
else
lua_pushnil(L);
return 1;
}
static int lib_sFadeOutStopMusic(lua_State *L)
{
UINT32 ms = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
lua_pushboolean(L, S_FadeOutStopMusic(ms));
}
else
lua_pushnil(L);
return 1;
}
static int lib_sOriginPlaying(lua_State *L)
{
void *origin = NULL;
@ -4008,9 +3599,6 @@ static luaL_Reg lib[] = {
{"P_IsObjectOnGround",lib_pIsObjectOnGround},
{"P_InQuicksand",lib_pInQuicksand},
{"P_SetObjectMomZ",lib_pSetObjectMomZ},
{"P_PlayJingle",lib_pPlayJingle},
{"P_PlayJingleMusic",lib_pPlayJingleMusic},
{"P_RestoreMusic",lib_pRestoreMusic},
{"P_SpawnGhostMobj",lib_pSpawnGhostMobj},
{"P_SpawnFakeShadow",lib_pSpawnFakeShadow},
{"P_GivePlayerRings",lib_pGivePlayerRings},
@ -4110,28 +3698,6 @@ static luaL_Reg lib[] = {
{"S_StartSoundAtVolume",lib_sStartSoundAtVolume},
{"S_StopSound",lib_sStopSound},
{"S_StopSoundByID",lib_sStopSoundByID},
{"S_ChangeMusic",lib_sChangeMusic},
{"S_SpeedMusic",lib_sSpeedMusic},
{"S_MusicType",lib_sMusicType},
{"S_MusicPlaying",lib_sMusicPlaying},
{"S_MusicPaused",lib_sMusicPaused},
{"S_MusicName",lib_sMusicName},
{"S_MusicExists",lib_sMusicExists},
{"S_GetMusicLength",lib_sGetMusicLength},
{"S_SetMusicLoopPoint",lib_sSetMusicLoopPoint},
{"S_GetMusicLoopPoint",lib_sGetMusicLoopPoint},
{"S_SetMusicPosition",lib_sSetMusicPosition},
{"S_GetMusicPosition",lib_sGetMusicPosition},
{"S_PauseMusic",lib_sPauseMusic},
{"S_ResumeMusic",lib_sResumeMusic},
{"S_StopMusic",lib_sStopMusic},
{"S_SetInternalMusicVolume", lib_sSetInternalMusicVolume},
{"S_StopFadingMusic",lib_sStopFadingMusic},
{"S_FadeMusic",lib_sFadeMusic},
{"S_FadeOutStopMusic",lib_sFadeOutStopMusic},
{"S_GetMusicLength",lib_sGetMusicLength},
{"S_GetMusicPosition",lib_sGetMusicPosition},
{"S_SetMusicPosition",lib_sSetMusicPosition},
{"S_OriginPlaying",lib_sOriginPlaying},
{"S_IdPlaying",lib_sIdPlaying},
{"S_SoundPlaying",lib_sSoundPlaying},

View file

@ -77,12 +77,10 @@ automatically.
X (PlayerThink),/* P_PlayerThink */\
X (GameQuit),\
X (PlayerCmd),/* building the player's ticcmd struct */\
X (MusicChange),\
X (VoteThinker),/* Y_VoteTicker */\
#define STRING_HOOK_LIST(X) \
X (SpecialExecute),\
X (ShouldJingleContinue),/* should jingle of the given music continue playing */\
#define HUD_HOOK_LIST(X) \
X (game),\
@ -147,8 +145,6 @@ void LUA_HookPlayerQuit(player_t *, kickreason_t);
int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble);
int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced);
int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend);
int LUA_HookShouldJingleContinue(player_t *, const char *musname);
int LUA_HookMusicChange(const char *oldname, struct MusicChange *);
#ifdef __cplusplus
} // extern "C"

View file

@ -125,14 +125,6 @@ static void add_string_hook(lua_State *L, int type)
switch (type)
{
case STRING_HOOK(ShouldJingleContinue):
if (lua_isstring(L, 3))
{ // lowercase copy
string = Z_StrDup(lua_tostring(L, 3));
strlwr(string);
}
break;
case STRING_HOOK(SpecialExecute):
string = Z_StrDup(luaL_checkstring(L, 3));
strupr(string);
@ -963,106 +955,4 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend)
return hook.status;
}
int LUA_HookShouldJingleContinue(player_t *player, const char *musname)
{
Hook_State hook;
if (prepare_string_hook
(&hook, false, STRING_HOOK(ShouldJingleContinue), musname))
{
LUA_PushUserdata(gL, player, META_PLAYER);
push_string();
hud_running = true; // local hook
call_hooks(&hook, 1, res_true);
hud_running = false;
}
return hook.status;
}
boolean hook_cmd_running = false;
static void update_music_name(struct MusicChange *musicchange)
{
size_t length;
const char * new = lua_tolstring(gL, -6, &length);
if (length < 7)
{
strcpy(musicchange->newname, new);
lua_pushvalue(gL, -6);/* may as well keep it for next call */
}
else
{
memcpy(musicchange->newname, new, 6);
musicchange->newname[6] = '\0';
lua_pushlstring(gL, new, 6);
}
lua_replace(gL, -7);
}
static void res_musicchange(Hook_State *hook)
{
struct MusicChange *musicchange = hook->userdata;
// output 1: true, false, or string musicname override
if (lua_isstring(gL, -6))
update_music_name(musicchange);
else if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6))
hook->status = true;
// output 2: mflags override
if (lua_isnumber(gL, -5))
*musicchange->mflags = lua_tonumber(gL, -5);
// output 3: looping override
if (lua_isboolean(gL, -4))
*musicchange->looping = lua_toboolean(gL, -4);
// output 4: position override
if (lua_isnumber(gL, -3))
*musicchange->position = lua_tonumber(gL, -3);
// output 5: prefadems override
if (lua_isnumber(gL, -2))
*musicchange->prefadems = lua_tonumber(gL, -2);
// output 6: fadeinms override
if (lua_isnumber(gL, -1))
*musicchange->fadeinms = lua_tonumber(gL, -1);
}
int LUA_HookMusicChange(const char *oldname, struct MusicChange *param)
{
const int type = HOOK(MusicChange);
const hook_t * map = &hookIds[type];
Hook_State hook;
int k;
if (prepare_hook(&hook, false, type))
{
init_hook_call(&hook, 6, res_musicchange);
hook.values = 7;/* values pushed later */
hook.userdata = param;
lua_pushstring(gL, oldname);/* the only constant value */
lua_pushstring(gL, param->newname);/* semi constant */
for (k = 0; k < map->numHooks; ++k)
{
get_hook(&hook, map->ids, k);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
lua_pushinteger(gL, *param->mflags);
lua_pushboolean(gL, *param->looping);
lua_pushinteger(gL, *param->position);
lua_pushinteger(gL, *param->prefadems);
lua_pushinteger(gL, *param->fadeinms);
call_single_hook_no_copy(&hook);
}
lua_settop(gL, 0);
}
return hook.status;
}

View file

@ -1018,7 +1018,6 @@ void Command_ObjectPlace_f(void)
op_oldflags1 = mobjinfo[MT_PLAYER].flags;
++players[0].lives;
players[0].playerstate = PST_LIVE;
P_RestoreMusic(&players[0]);
}
else
op_oldstate = (statenum_t)(players[0].mo->state-states);

View file

@ -4,6 +4,7 @@
#include "../k_menu.h"
#include "../m_cond.h" // Condition Sets
#include "../m_random.h" // And just some randomness for the exits.
#include "../music.h"
#include "../z_zone.h"
#include "../r_skins.h"
#include "../s_sound.h"
@ -220,7 +221,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
if ((challengesmenu.pending = (newunlock != MAXUNLOCKABLES)))
{
S_StopMusic();
Music_StopAll();
MISC_ChallengesDef.prevMenu = desiredmenu;
}

View file

@ -4,6 +4,7 @@
#include "../k_menu.h"
#include "../s_sound.h"
#include "../m_random.h"
#include "../music.h"
#include "../r_skins.h"
struct wrongwarp_s wrongwarp;
@ -22,7 +23,8 @@ void M_WrongWarp(INT32 choice)
M_SetupNextMenu(&MISC_WrongWarpDef, false);
// Done here to avoid immediate music credit
S_ChangeMusicInternal("YEAWAY", true);
Music_Remap("menu_nocred", "YEAWAY");
Music_Play("menu_nocred");
}
static void M_WrongWarpTick(void)

View file

@ -2,6 +2,7 @@
/// \brief Stereo Mode menu
#include "../../k_menu.h"
#include "../../music.h"
#include "../../s_sound.h"
static void M_SoundTestMainControl(INT32 choice)
@ -36,11 +37,11 @@ static void M_SoundTestMainControl(INT32 choice)
if (currentMenu->menuitems[itemOn].mvar1 == 1) // Play
{
if (soundtest.paused == true)
if (Music_Paused(soundtest.tune) == true)
{
S_SoundTestTogglePause();
}
else if (soundtest.playing == false)
else if (Music_Paused(soundtest.tune) == false)
{
S_SoundTestPlay();
}
@ -49,7 +50,7 @@ static void M_SoundTestMainControl(INT32 choice)
{
if (currentMenu->menuitems[itemOn].mvar1 == 2) // Pause
{
if (soundtest.paused == false)
if (Music_Paused(soundtest.tune) == false)
{
S_SoundTestTogglePause();
}

342
src/music.cpp Normal file
View file

@ -0,0 +1,342 @@
// DR ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include "music_manager.hpp"
#include "music_tune.hpp"
#include "doomtype.h"
#include "music.h"
using namespace srb2::music;
namespace
{
TuneManager g_tunes;
}; // namespace
void Music_Init(void)
{
{
Tune& tune = g_tunes.insert("level");
tune.priority = 1;
tune.resume_fade_in = 750;
tune.sync = true;
tune.credit = true;
}
{
Tune& tune = g_tunes.insert("position");
tune.priority = 10;
tune.fade_out = 3500;
}
{
Tune& tune = g_tunes.insert("grow");
tune.song = "kgrow";
tune.priority = 20;
tune.resume_fade_in = 200;
}
{
Tune& tune = g_tunes.insert("invinc");
tune.song = "kinvnc";
tune.priority = 21;
}
{
Tune& tune = g_tunes.insert("finish");
tune.priority = 30;
tune.loop = false;
}
{
Tune& tune = g_tunes.insert("comeon");
tune.song = "chalng";
tune.priority = 35;
tune.loop = false;
}
{
Tune& tune = g_tunes.insert("intermission");
tune.song = "racent";
tune.priority = 40;
}
{
Tune& tune = g_tunes.insert("vote");
tune.song = "vote";
tune.priority = 50;
tune.credit = true;
}
{
Tune& tune = g_tunes.insert("vote_suspense");
tune.song = "voteea";
tune.priority = 51;
}
{
Tune& tune = g_tunes.insert("vote_end");
tune.song = "voteeb";
tune.priority = 52;
tune.loop = false;
}
{
Tune& tune = g_tunes.insert("wait");
tune.song = "WAIT2J";
tune.priority = 60;
}
{
Tune& tune = g_tunes.insert("title");
tune.song = "_title";
tune.priority = 100;
tune.resist = true;
}
{
Tune& tune = g_tunes.insert("menu");
tune.priority = 100;
tune.credit = true;
}
{
Tune& tune = g_tunes.insert("menu_nocred");
tune.priority = 100;
}
{
Tune& tune = g_tunes.insert("credits");
tune.priority = 100;
tune.song = "_creds";
tune.fade_out = 250;
tune.loop = false;
tune.credit = true;
}
{
Tune& tune = g_tunes.insert("shore");
tune.priority = 100;
tune.loop = false;
}
{
Tune& tune = g_tunes.insert("stereo");
tune.priority = 1000;
tune.resist = true;
tune.keep_open = true;
tune.credit = true;
}
{
Tune& tune = g_tunes.insert("stereo_fade");
tune.priority = 1000;
tune.fade_out = 5000;
tune.fade_out_inclusive = false;
tune.resist = true;
tune.keep_open = true;
tune.credit = true;
}
}
void Music_Tick(void)
{
g_tunes.tick();
}
void Music_Play(const char* id)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
tune->play();
g_tunes.tick(); // play this immediately
}
}
void Music_DelayEnd(const char* id, tic_t duration)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
tune->delay_end(duration);
if (tune->time_remaining() <= detail::msec_to_tics(tune->fade_out))
{
// If this action would cause a fade out, start
// fading immediately.
g_tunes.tick();
}
}
}
void Music_Seek(const char* id, tic_t set)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
tune->seek = set;
tune->needs_seek = true;
}
}
void Music_Stop(const char* id)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
g_tunes.stop(*tune);
g_tunes.tick();
}
}
void Music_Pause(const char* id)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
tune->pause();
g_tunes.pause_unpause();
}
}
void Music_UnPause(const char* id)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
tune->unpause();
g_tunes.pause_unpause();
}
}
void Music_PauseAll(void)
{
g_tunes.for_each([](Tune& tune) { tune.pause(); });
g_tunes.pause_unpause();
}
void Music_UnPauseAll(void)
{
g_tunes.for_each([](Tune& tune) { tune.unpause(); });
g_tunes.pause_unpause();
}
void Music_StopAll(void)
{
g_tunes.stop_all();
g_tunes.tick();
}
void Music_Remap(const char* id, const char* song)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
tune->song = song;
}
}
boolean Music_Playing(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune && tune->playing();
}
boolean Music_Paused(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune && tune->paused();
}
tic_t Music_Elapsed(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune ? tune->elapsed() : 0u;
}
tic_t Music_DurationLeft(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune ? tune->time_remaining() : 0u;
}
tic_t Music_TotalDuration(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune ? tune->duration() : 0u;
}
void Music_Loop(const char* id, boolean loop)
{
Tune* tune = g_tunes.find(id);
if (tune)
{
// FIXME: this has no effect if the song is already
// playing
tune->loop = loop;
}
}
boolean Music_CanLoop(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune && tune->loop;
}
boolean Music_CanEnd(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune && tune->can_end();
}
const char* Music_Song(const char* id)
{
const Tune* tune = g_tunes.find(id);
return tune ? tune->song.c_str() : "";
}
const char* Music_CurrentSong(void)
{
return g_tunes.current_song().c_str();
}
const char* Music_CurrentId(void)
{
return g_tunes.current_id();
}

148
src/music.h Normal file
View file

@ -0,0 +1,148 @@
// DR ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
//
// A brief description of "tunes".
//
// Tunes are how the game identifies music. A tune may be
// remapped to any music lump. For example, the "level" tune
// represents the level music, but the actual song that plays
// is different between levels.
//
// Tunes store info, such as for how long they will play (in
// the case of "invinc" and "grow"), or whether they fade in
// or out and for how long they fade.
//
// Tunes are given a priority. Only the highest priority tune
// is heard, even if the others haven't ended. Tunes with the
// same priority are sorted by picking the last one that begun
// playing.
//
#ifndef MUSIC_H
#define MUSIC_H
#include "doomtype.h"
#ifdef __cplusplus
extern "C" {
#endif
//
// Get the currently playing tune.
//
// Returns the song name for the currently playing tune.
// Returns empty string if no tune is playing.
const char *Music_CurrentSong(void);
// Returns the id of the currently playing tune. Returns empty
// string if no tune is playing.
const char *Music_CurrentId(void);
//
// Actions that take effect immediately.
//
// Begin playing a tune, duration is infinite. If the tune was
// already playing, this resets its current position (seeks
// back to the start.)
void Music_Play(const char *id);
// Postpone the end of this tune until N tics from now. The
// tune should already be playing before calling this.
void Music_DelayEnd(const char *id, tic_t duration);
// Stop playing a tune.
void Music_Stop(const char *id);
void Music_StopAll(void);
// Pause a tune. This effectively extends its duration,
// relative to game time. Unpausing will resume the tune
// exactly where it left off.
void Music_Pause(const char *id);
void Music_UnPause(const char *id);
void Music_PauseAll(void);
void Music_UnPauseAll(void);
//
// Change properties. May be called before calling Music_Play.
// These take effect on the next tick.
//
// Seek to a specific time in the tune.
void Music_Seek(const char *id, tic_t set);
// Remap a tune to another song. Use the lump name, with the
// 'O_' at the beginning removed. song is case insensitive.
void Music_Remap(const char *id, const char *song);
// Set whether a tune should loop.
void Music_Loop(const char *id, boolean loop);
//
// Query properties.
//
// Returns true if the tune is configured to loop.
boolean Music_CanLoop(const char *id);
// Returns true if the tune does not play indefinitely, i.e.
// has a limited duration.
boolean Music_CanEnd(const char *id);
// Returns true if the tune is playing. This does not
// necessarily mean it is audible, because it has to be at the
// highest priority to be heard.
boolean Music_Playing(const char *id);
// Returns true if the tune is paused.
boolean Music_Paused(const char *id);
// Returns the number of tics elapsed since the start of the
// tune.
tic_t Music_Elapsed(const char *id);
// Returns the number of tics remaining until the tune ends.
tic_t Music_DurationLeft(const char *id);
// Returns the total duration of the tune, in tics.
tic_t Music_TotalDuration(const char *id);
// Returns the song name mapped to a tune.
const char *Music_Song(const char *id);
//
// Low level program state.
//
// Loads certain data structures used for the lifetime of the
// program. Only needs to be called once, before any other
// functions.
void Music_Init(void);
// Call this every tic to update the music.
void Music_Tick(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // MUSIC_H

38
src/music_detail.hpp Normal file
View file

@ -0,0 +1,38 @@
// DR ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef MUSIC_DETAIL_HPP
#define MUSIC_DETAIL_HPP
#include "doomdef.h"
#include "doomstat.h"
#include "doomtype.h"
namespace srb2::music::detail
{
inline constexpr tic_t msec_to_tics(int msec)
{
return msec * (TICRATE / 1000.f);
}
inline constexpr int tics_to_msec(tic_t tics)
{
return tics * (1000.f / TICRATE);
}
inline tic_t tic_time()
{
// Use gametic so it is synced with game logic.
return gametic;
}
}; // namespace srb2::music::detail
#endif // MUSIC_DETAIL_HPP

204
src/music_manager.cpp Normal file
View file

@ -0,0 +1,204 @@
// DR ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2023 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <fmt/format.h>
#include "music_manager.hpp"
#include "music_tune.hpp"
#include "doomtype.h"
#include "i_sound.h"
#include "i_time.h"
#include "s_sound.h"
#include "w_wad.h"
#include "z_zone.h"
using namespace srb2::music;
namespace
{
// How many tics music is allowed to drift away from game
// logic.
constexpr int kResyncTics = 2;
}; // namespace
void TuneManager::tick()
{
if (S_MusicDisabled())
{
return;
}
Tune* tune = current_tune();
std::string old_song = current_song_;
current_song_ = tune && tune->playing() ? tune->song : std::string{};
bool changed = current_song_ != old_song;
if (stop_credit_)
{
if (changed)
{
// Only stop the music credit if the song actually
// changed.
S_StopMusicCredit();
}
stop_credit_ = false;
}
if (!tune)
{
if (changed)
{
I_UnloadSong();
}
return;
}
if (changed)
{
if (load())
{
I_FadeInPlaySong(tune->resume ? tune->resume_fade_in : tune->fade_in, tune->loop);
seek(tune);
adjust_volume();
I_SetSongSpeed(tune->speed());
if (tune->credit && !tune->resume)
{
S_ShowMusicCredit();
}
tune->resume = true;
gme_ = !std::strcmp(I_SongType(), "GME");
}
else
{
I_UnloadSong();
}
}
else if (tune->needs_seek || (tune->sync && resync()))
{
seek(tune);
}
else if (tune->time_remaining() <= detail::msec_to_tics(tune->fade_out))
{
if (tune->can_fade_out)
{
I_FadeSong(0, tune->fade_out, nullptr);
tune->can_fade_out = false;
}
if (!tune->keep_open)
{
tune->ending = true;
}
}
}
void TuneManager::pause_unpause() const
{
const Tune* tune = current_tune();
if (tune)
{
if (tune->paused())
{
I_PauseSong();
}
else
{
I_ResumeSong();
}
}
}
bool TuneManager::load() const
{
lumpnum_t lumpnum = W_CheckNumForLongName(fmt::format("O_{}", current_song_).c_str());
if (lumpnum == LUMPERROR)
{
return false;
}
return I_LoadSong(static_cast<char*>(W_CacheLumpNum(lumpnum, PU_MUSIC)), W_LumpLength(lumpnum));
}
void TuneManager::adjust_volume() const
{
UINT8 i;
const musicdef_t* def = S_FindMusicDef(current_song_.c_str(), &i);
if (!def)
{
return;
}
I_SetCurrentSongVolume(def->debug_volume != 0 ? def->debug_volume : def->volume);
}
bool TuneManager::resync()
{
if (gme_)
{
// This is dodging the problem. GME can be very slow
// for seeking, since it (probably) just emulates the
// entire song up to where its seeking.
//
// The time loss is not easily predictable, and it
// causes repeated resyncing, so just don't sync if
// it's GME.
return false;
}
long d_local = I_GetTime() - time_local_;
long d_sync = detail::tic_time() - time_sync_;
if (std::abs(d_local - d_sync) >= kResyncTics)
{
time_sync_ = detail::tic_time();
time_local_ = I_GetTime();
return true;
}
return false;
}
void TuneManager::seek(Tune* tune)
{
uint32_t end = I_GetSongLength();
uint32_t loop = I_GetSongLoopPoint();
uint32_t pos = detail::tics_to_msec(tune->seek + tune->elapsed()) * tune->speed();
if (pos > end && (end - loop) > 0u)
{
pos = loop + ((pos - end) % (end - loop));
}
I_SetSongPosition(pos);
tune->needs_seek = false;
}

113
src/music_manager.hpp Normal file
View file

@ -0,0 +1,113 @@
// DR ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef MUSIC_MANAGER_HPP
#define MUSIC_MANAGER_HPP
#include <algorithm>
#include <cstdlib>
#include <string>
#include <unordered_map>
#include "cxxutil.hpp"
#include "music_tune.hpp"
namespace srb2::music
{
class TuneManager
{
public:
const std::string& current_song() const { return current_song_; }
Tune* current_tune() const
{
auto it = current_iterator();
return it != map_.end() ? const_cast<Tune*>(&it->second) : nullptr;
}
const char* current_id() const
{
auto it = current_iterator();
return it != map_.end() ? it->first.c_str() : "";
}
Tune* find(const char* id) const
{
auto it = map_.find(id);
return it != map_.end() ? const_cast<Tune*>(&it->second) : nullptr;
}
Tune& insert(const char* id)
{
auto [it, inserted] = map_.emplace(id, Tune{});
SRB2_ASSERT(inserted);
return it->second;
}
void tick();
void pause_unpause() const;
void stop(Tune& tune)
{
tune.stop();
stop_credit_ = true;
}
void stop_all()
{
for_each([](Tune& tune) { tune.stop(); });
stop_credit_ = true;
}
template <typename F>
void for_each(F&& f)
{
for (auto& [_, tune] : map_)
{
if (!tune.resist)
{
f(tune);
}
}
}
private:
std::unordered_map<std::string, Tune> map_;
std::string current_song_;
tic_t time_sync_;
tic_t time_local_;
bool stop_credit_ = false;
bool gme_; // hack
decltype(map_)::const_iterator current_iterator() const
{
return std::max_element(
map_.begin(),
map_.end(),
[](const auto& a, const auto& b) { return a.second < b.second; }
);
}
bool load() const;
void adjust_volume() const;
bool resync();
static void seek(Tune* tune);
};
}; // namespace srb2::music
#endif // MUSIC_MANAGER_HPP

194
src/music_tune.hpp Normal file
View file

@ -0,0 +1,194 @@
// DR ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef MUSIC_TUNE_HPP
#define MUSIC_TUNE_HPP
#include <algorithm>
#include <optional>
#include <string>
#include "doomdef.h"
#include "doomtype.h"
#include "music_detail.hpp"
namespace srb2::music
{
class Tune
{
public:
explicit Tune() {}
std::string song; // looks up the lump
// Higher priority tunes play first.
int priority = 0;
// Fade at the beginning or end of the tune.
int fade_in = 0; // in milliseconds
int fade_out = 0;
// Fade time subtracts from the duration of the song?
int fade_out_inclusive = true;
// Fade in when a higher priority tune ends and this one
// resumes.
int resume_fade_in = 0;
// Sync this tune to game logic.
bool sync = false;
// This tune loops at the end.
bool loop = true;
// When this tune runs out of duration, keep playing
// silence.
bool keep_open = false;
// This tune does not respect mass stop or pause actions
// from TuneManager::stop_all etc. It must be
// stopped/paused individually.
bool resist = false;
// This tune shows a credit when first played (not
// resumed).
bool credit = false;
// Start playing this number of tics into the tune.
tic_t seek = 0;
// these track state
bool can_fade_out = true;
bool needs_seek = false;
bool resume = false;
bool ending = false;
tic_t elapsed() const { return std::max(pause_.value_or(detail::tic_time()), begin_) - begin_; }
tic_t time_remaining() const { return end_ - std::min(pause_.value_or(detail::tic_time()), end_); }
tic_t duration() const { return end_ - begin_; }
bool playing() const { return begin_ <= detail::tic_time() && (!ending || time_remaining()); }
bool paused() const { return pause_.has_value(); }
bool can_end() const { return end_ != INFTICS; }
float speed() const
{
// Slow level music down a bit in Encore. (Values are vibe-based. WE GET IT YOU VAPE)
if (encoremode && gamestate == GS_LEVEL)
{
return 0.86471f;
}
return 1.f;
}
bool operator <(const Tune& b) const
{
// If this song is not playing, it has lowest
// priority.
if (!playing())
{
return true;
}
// If the other song is not playing, we automatically
// have higher priority.
if (!b.playing())
{
return false;
}
// The highest priority song is preferred.
if (priority != b.priority)
{
return priority < b.priority;
}
// If both songs have the same priority, prefer the
// one that begun later.
return begin_ < b.begin_;
}
void play()
{
if (!needs_seek)
{
seek = 0;
}
can_fade_out = true;
needs_seek = true;
resume = false;
ending = false;
begin_ = detail::tic_time();
end_ = INFTICS;
pause_.reset();
}
void delay_end(tic_t duration)
{
end_ = detail::tic_time() + duration;
if (!fade_out_inclusive)
{
end_ += detail::msec_to_tics(fade_out);
}
if (playing())
{
can_fade_out = true;
ending = false;
}
}
void stop()
{
begin_ = INFTICS;
end_ = 0;
pause_.reset();
}
void pause()
{
pause_ = detail::tic_time();
}
void unpause()
{
if (!pause_)
{
return;
}
if (playing())
{
tic_t n = detail::tic_time() - *pause_;
begin_ += n;
if (can_end())
{
end_ += n;
}
}
pause_.reset();
}
private:
tic_t begin_ = INFTICS;
tic_t end_ = 0;
std::optional<tic_t> pause_;
};
}; // namespace srb2::music
#endif // MUSIC_TUNE_HPP

View file

@ -22,6 +22,7 @@
#include "../g_game.h"
#include "../z_zone.h"
#include "../k_waypoint.h"
#include "../music.h"
//
// ███████╗██╗██╗░░██╗███╗░░░███╗███████╗
@ -556,21 +557,11 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim)
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
}
if (victim->player->invincibilitytimer > 0)
{
; // invincibility has priority in P_RestoreMusic, no point in starting here
}
else if (P_IsLocalPlayer(victim->player) == true)
{
S_ChangeMusicSpecial("kgrow");
}
else //used to be "if (P_IsDisplayPlayer(victim->player) == false)"
if (P_IsLocalPlayer(victim->player) == false && victim->player->invincibilitytimer == 0)
{
// don't play this if the player has invincibility -- that takes priority
S_StartSound(victim, sfx_alarmg);
}
P_RestoreMusic(victim->player);
}
}
else

View file

@ -183,9 +183,9 @@ boolean P_InQuicksand(mobj_t *mo);
boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, angle_t oldRoll);
void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative);
void P_RestoreMusic(player_t *player);
void P_StartPositionMusic(boolean exact);
void P_EndingMusic(void);
void P_InvincGrowMusic(void);
mobj_t *P_SpawnGhostMobj(mobj_t *mobj);
mobj_t *P_SpawnFakeShadow(mobj_t *mobj, UINT8 offset);
INT32 P_GivePlayerRings(player_t *player, INT32 num_rings);
@ -237,36 +237,6 @@ boolean P_GetLives(player_t *player);
boolean P_SpectatorJoinGame(player_t *player);
void P_RestoreMultiMusic(player_t *player);
/// ------------------------
/// Jingle stuff
/// ------------------------
typedef enum
{
JT_NONE, // Null state
JT_OTHER, // Other state
JT_MASTER, // Main level music
JT_INVINCIBILITY, // Invincibility
JT_GROW, // Grow
NUMJINGLES
} jingletype_t;
struct jingle_t
{
char musname[7];
boolean looping;
};
extern jingle_t jingleinfo[NUMJINGLES];
#define JINGLEPOSTFADE 1000
void P_PlayJingle(player_t *player, jingletype_t jingletype);
boolean P_EvaluateMusicStatus(UINT16 status, const char *musname);
void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status);
//
// P_MOBJ
//

View file

@ -104,6 +104,7 @@
#include "k_podium.h"
#include "k_rank.h"
#include "k_mapuser.h"
#include "music.h"
// Replay names have time
#if !defined (UNDER_CE)
@ -7923,6 +7924,23 @@ static void P_InitMinimapInfo(void)
minimapinfo.offs_y = FixedMul((minimapinfo.min_y + minimapinfo.map_h/2) << FRACBITS, minimapinfo.zoom);
}
void P_ResetLevelMusic(void)
{
if (mapheaderinfo[gamemap-1]->musname_size > 1)
mapmusrng = P_RandomKey(PR_MUSICSELECT, mapheaderinfo[gamemap-1]->musname_size);
else
mapmusrng = 0;
}
void P_LoadLevelMusic(void)
{
tic_t level_music_start = starttime + (TICRATE/2);
Music_StopAll();
Music_Remap("level", mapheaderinfo[gamemap-1]->musname[mapmusrng]);
Music_Seek("level", max(leveltime, level_music_start) - level_music_start);
}
/** Loads a level from a lump or external wad.
*
* \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot.
@ -7969,6 +7987,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
P_InitLevelSettings();
if (!demo.title)
{
Music_Stop("title");
}
for (i = 0; i <= r_splitscreen; i++)
postimgtype[i] = postimg_none;
@ -7987,7 +8010,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
{
tic_t locstarttime, endtime, nowtime;
S_StopMusic(); // er, about that...
Music_StopAll(); // er, about that...
// Fade to an inverted screen, with a circle fade...
F_WipeStartScreen();
@ -8072,16 +8095,20 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
{
int wipetype = wipe_level_toblack;
// TODO: What is this?? This does nothing because P_LoadLevelMusic is gonna halt music, anyway.
#if 0
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
if (gamestate == GS_LEVEL)
S_FadeMusic(0, FixedMul(
FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE));
#endif
if (K_PodiumSequence())
{
// mapmusrng is set by local player position in K_ResetCeremony
S_InitLevelMusic(true);
P_ResetLevelMusic();
P_LoadLevelMusic();
}
else if (gamestate == GS_LEVEL)
{
@ -8093,7 +8120,12 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// We should be fine starting music here.
// Don't do this during titlemap, because the menu code handles music by itself.
S_InitLevelMusic(fromnetsave);
// Netsave loading does this itself, because leveltime isn't set yet!
if (!fromnetsave)
{
P_ResetLevelMusic();
P_LoadLevelMusic();
}
}
if (gametyperules & GTR_SPECIALSTART)

View file

@ -103,6 +103,8 @@ extern mapthing_t *mapthings;
void P_SetupLevelSky(const char *skytexname, boolean global);
void P_RespawnThings(void);
void P_ResetLevelMusic(void);
void P_LoadLevelMusic(void);
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
void P_PostLoadLevel(void);
#ifdef HWRENDER

View file

@ -2887,6 +2887,8 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
break;
case 413: // Change music
// FIXME: port to new music system
#if 0
// console player only unless TMM_ALLPLAYERS is set
if ((args[1] & TMM_ALLPLAYERS) || (mo && mo->player && P_IsLocalPlayer(mo->player)) || titlemapinaction)
{
@ -2963,6 +2965,7 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
// Except, you can use the TMM_NORELOAD flag to change this behavior.
// if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn.
}
#endif
break;
case 414: // Play SFX

View file

@ -42,6 +42,7 @@
#include "k_specialstage.h"
#include "acs/interface.h"
#include "k_objects.h"
#include "music.h"
#ifdef PARANOIA
#include "deh_tables.h" // MOBJTYPE_LIST
@ -714,7 +715,6 @@ void P_Ticker(boolean run)
P_MoveChaseCamera(&players[0], &camera[0], false);
R_UpdateViewInterpolation();
P_MapEnd();
S_SetStackAdjustmentStart();
return;
}
}
@ -731,13 +731,9 @@ void P_Ticker(boolean run)
}
else if (demo.freecam && democam.cam) // special case: allow freecam to MOVE during pause!
P_DemoCameraMovement(democam.cam);
S_SetStackAdjustmentStart();
return;
}
if (!S_MusicPaused())
S_AdjustMusicStackTics();
for (i = 0; i <= r_splitscreen; i++)
postimgtype[i] = postimg_none;
@ -874,8 +870,7 @@ void P_Ticker(boolean run)
// Bosses have a punchy start, so no position.
if (leveltime == 1)
{
S_ChangeMusic(mapmusname, mapmusflags, true);
S_ShowMusicCredit();
Music_Play("level");
}
}
else if (leveltime < starttime + TICRATE)
@ -883,8 +878,7 @@ void P_Ticker(boolean run)
if (leveltime == (starttime + (TICRATE/2)))
{
// Plays the music after the starting countdown.
S_ChangeMusic(mapmusname, mapmusflags, true);
S_ShowMusicCredit();
Music_Play("level");
}
else if (starttime != introtime)
{
@ -892,7 +886,6 @@ void P_Ticker(boolean run)
if (leveltime == starttime-(3*TICRATE))
{
S_StartSound(NULL, sfx_s3ka7); // 3,
S_FadeMusic(0, 3500); //S_FadeOutStopMusic(3500); -- TODO the S_StopMusic callback can halt successor music instead
}
else if ((leveltime == starttime-(2*TICRATE))
|| (leveltime == starttime-TICRATE))

View file

@ -64,6 +64,7 @@
#include "k_director.h"
#include "g_party.h"
#include "k_profiles.h"
#include "music.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -78,20 +79,6 @@
static void P_NukeAllPlayers(player_t *player);
#endif
//
// Jingle stuff.
//
jingle_t jingleinfo[NUMJINGLES] = {
// {musname, looping, reset, nest}
{"" , false}, // JT_NONE
{"" , false}, // JT_OTHER
{"" , false}, // JT_MASTER
{"kinvnc" , true}, // JT_INVINCIBILITY
{"kgrow" , true}, // JT_GROW
};
//
// Movement.
//
@ -597,93 +584,6 @@ void P_AddPlayerScore(player_t *player, UINT32 amount)
player->roundscore = MAXSCORE;
}
void P_PlayJingle(player_t *player, jingletype_t jingletype)
{
const char *musname = jingleinfo[jingletype].musname;
UINT16 musflags = 0;
boolean looping = jingleinfo[jingletype].looping;
char newmusic[7];
strncpy(newmusic, musname, 7);
#ifdef HAVE_LUA_MUSICPLUS
if(LUAh_MusicJingle(jingletype, newmusic, &musflags, &looping))
return;
#endif
newmusic[6] = 0;
P_PlayJingleMusic(player, newmusic, musflags, looping, jingletype);
}
//
// P_PlayJingleMusic
//
void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status)
{
// If gamestate != GS_LEVEL, always play the jingle (1-up intermission)
if (gamestate == GS_LEVEL && player && !P_IsLocalPlayer(player))
return;
S_RetainMusic(musname, musflags, looping, 0, status);
//S_StopMusic();
S_ChangeMusicInternal(musname, looping);
}
boolean P_EvaluateMusicStatus(UINT16 status, const char *musname)
{
// \todo lua hook
int i;
boolean result = false;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!P_IsLocalPlayer(&players[i]))
continue;
switch(status)
{
case JT_INVINCIBILITY: // Invincibility
if (players[i].invincibilitytimer > 1)
{
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, players[i].invincibilitytimer);
result = true;
}
else
{
result = false;
}
break;
case JT_GROW: // Grow
if (players[i].growshrinktimer > 1)
{
strlcpy(S_sfx[sfx_None].caption, "Grow", 14);
S_StartCaption(sfx_None, -1, players[i].growshrinktimer);
result = true;
}
else
{
result = false;
}
break;
case JT_OTHER: // Other state
result = LUA_HookShouldJingleContinue(&players[i], musname);
break;
case JT_NONE: // Null state
case JT_MASTER: // Main level music
default:
result = true;
}
if (result)
break;
}
return result;
}
void P_PlayRinglossSound(mobj_t *source)
{
if (source->player && K_GetShieldFromItem(source->player->itemtype) != KSHIELD_NONE)
@ -719,7 +619,7 @@ void P_StartPositionMusic(boolean exact)
: (leveltime < 1))
return;
S_ChangeMusicInternal("encore", true);
Music_Remap("position", "encore");
}
else
{
@ -728,12 +628,15 @@ void P_StartPositionMusic(boolean exact)
: (leveltime < introtime))
return;
S_ChangeMusicInternal(
Music_Remap("position",
(mapheaderinfo[gamemap-1]->positionmus[0]
? mapheaderinfo[gamemap-1]->positionmus
: "postn"
), true);
));
}
Music_Play("position");
Music_DelayEnd("position", (starttime + (TICRATE/2)) - leveltime);
}
//
@ -873,110 +776,54 @@ skippingposition:
if (jingle == NULL)
return;
S_ChangeMusicInternal(jingle, false);
Music_Remap("finish", jingle);
Music_Play("finish");
}
//
// P_RestoreMusic
//
// Restores music after some special music change
//
void P_RestoreMusic(player_t *player)
void P_InvincGrowMusic(void)
{
UINT8 overrideLevel = 0;
SINT8 i;
INT32 invinc = 0;
INT32 grow = 0;
if (P_IsLocalPlayer(player) == false)
{
// Only applies to local players
return;
}
UINT8 i;
// Event - HERE COMES A NEW CHALLENGER
if (mapreset)
for (i = 0; i <= r_splitscreen; ++i)
{
S_ChangeMusicInternal("chalng", false);
return;
}
player_t *player = &players[displayplayers[i]];
// Event - Level Ending
if (musiccountdown > 0)
{
return;
}
// Event - Level Start
if ((K_CheckBossIntro() == false)
&& (leveltime < (starttime + (TICRATE/2)))) // see also where time overs are handled
{
P_StartPositionMusic(false); // inexact timing permitted
return;
}
for (i = 0; i <= r_splitscreen; i++)
{
player_t *checkPlayer = &players[displayplayers[i]];
if (!checkPlayer)
if (!P_IsLocalPlayer(player))
{
// Director cam on another player? Don't play
// this.
continue;
}
if (checkPlayer->exiting)
// Find the longest running timer among splitscreen
// players and use that.
if (player->invincibilitytimer > invinc)
{
return;
invinc = player->invincibilitytimer;
}
if (checkPlayer->invincibilitytimer > 1)
if (player->growshrinktimer > grow)
{
overrideLevel = max(overrideLevel, 2);
}
else if (checkPlayer->growshrinktimer > 1)
{
overrideLevel = max(overrideLevel, 1);
grow = player->growshrinktimer;
}
}
if (overrideLevel != 0)
if (invinc && !Music_Playing("invinc"))
{
// Do a jingle override.
jingletype_t jt = JT_NONE;
switch (overrideLevel)
{
// Lowest priority to highest priority.
case 1:
jt = JT_GROW;
break;
case 2:
jt = JT_INVINCIBILITY;
break;
default:
break;
}
if (jt != JT_NONE)
{
//CONS_Printf("JINGLE: %d\n", jt);
//if (S_RecallMusic(jt, false) == false)
//{
P_PlayJingle(player, jt);
//}
return;
}
Music_Play("invinc");
}
#if 0
// Event - Final Lap
// Still works for GME, but disabled for consistency
if ((gametyperules & GTR_CIRCUIT) && player->laps >= numlaps)
S_SpeedMusic(1.2f);
#endif
if (S_RecallMusic(JT_NONE, false) == false) // go down the stack
if (grow && !Music_Playing("grow"))
{
CONS_Debug(DBG_BASIC, "Cannot find any music in resume stack!\n");
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
Music_Play("grow");
}
Music_DelayEnd("invinc", invinc);
Music_DelayEnd("grow", grow);
}
//
@ -1426,7 +1273,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
if (P_IsLocalPlayer(player) && !specialout)
{
S_StopMusic();
Music_StopAll();
musiccountdown = MUSICCOUNTDOWNMAX;
}
@ -1948,8 +1795,6 @@ static void P_CheckInvincibilityTimer(player_t *player)
{
//K_KartResetPlayerColor(player); -- this gets called every tic anyways
G_GhostAddColor((INT32) (player - players), GHC_NORMAL);
P_RestoreMusic(player);
return;
}
}
@ -4039,7 +3884,7 @@ void P_DoTimeOver(player_t *player)
if (P_IsLocalPlayer(player))
{
S_StopMusic();
Music_StopAll();
musiccountdown = MUSICCOUNTDOWNMAX;
}

File diff suppressed because it is too large Load diff

View file

@ -157,22 +157,8 @@ void S_StopSound(void *origin);
boolean S_DigMusicDisabled(void);
boolean S_MusicDisabled(void);
boolean S_MusicPlaying(void);
boolean S_MusicPaused(void);
boolean S_MusicNotInFocus(void);
const char *S_MusicType(void);
const char *S_MusicName(void);
boolean S_MusicExists(const char *mname);
boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping);
//
// Music Effects
//
// Set Speed of Music
boolean S_SpeedMusic(float speed);
#define MAXDEFTRACKS 3
@ -213,23 +199,19 @@ extern struct cursongcredit
extern struct soundtest
{
const char *tune; // Tune used for music system
boolean playing; // Music is playing?
boolean paused; // System paused?
boolean justopened; // Menu visual assist
boolean privilegedrequest; // Overrides S_PlaysimMusicDisabled w/o changing every function signature
INT32 menutick; // Menu visual timer
musicdef_t *current; // Current selected music definition
SINT8 currenttrack; // Current selected music track for definition
UINT32 currenttime; // Current music playing time
soundtestsequence_t sequence; // Sequence head
boolean autosequence; // In auto sequence mode?
boolean dosequencefadeout; // Fade out when reaching the end?
UINT32 sequencemaxtime; // Maximum playing time for current music
UINT32 sequencefadeout; // auto sequence fadeout
} soundtest;
void S_PopulateSoundTestSequence(void);
@ -238,9 +220,6 @@ void S_SoundTestPlay(void);
void S_SoundTestStop(void);
void S_SoundTestTogglePause(void);
void S_TickSoundTest(void);
#define SOUNDTEST_FADEOUTSECONDS 5
boolean S_PlaysimMusicDisabled(void);
extern musicdef_t *musicdefstart;
@ -250,94 +229,10 @@ musicdef_t *S_FindMusicDef(const char *name, UINT8 *i);
void S_ShowMusicCredit(void);
void S_StopMusicCredit(void);
//
// Music Seeking
//
// Get Length of Music
UINT32 S_GetMusicLength(void);
// Set LoopPoint of Music
boolean S_SetMusicLoopPoint(UINT32 looppoint);
// Get LoopPoint of Music
UINT32 S_GetMusicLoopPoint(void);
// Set Position of Music
boolean S_SetMusicPosition(UINT32 position);
// Get Position of Music
UINT32 S_GetMusicPosition(void);
//
// Music Stacking (Jingles)
//
struct musicstack_t
{
char musname[7];
UINT16 musflags;
boolean looping;
UINT32 position;
tic_t tic;
UINT16 status;
lumpnum_t mlumpnum;
boolean noposition; // force music stack resuming from zero (like music_stack_noposition)
musicstack_t *prev;
musicstack_t *next;
};
extern char music_stack_nextmusname[7];
extern boolean music_stack_noposition;
extern UINT32 music_stack_fadeout;
extern UINT32 music_stack_fadein;
void S_SetStackAdjustmentStart(void);
void S_AdjustMusicStackTics(void);
void S_RetainMusic(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status);
boolean S_RecallMusic(UINT16 status, boolean fromfirst);
//
// Music Playback
//
/* this is for the sake of the hook */
struct MusicChange {
char * newname;
UINT16 * mflags;
boolean * looping;
UINT32 * position;
UINT32 * prefadems;
UINT32 * fadeinms;
};
enum
{
MUS_SPECIAL = 1,/* powerups--invincibility, grow */
};
// Start music track, arbitrary, given its name, and set whether looping
// note: music flags 12 bits for tracknum (gme, other formats with more than one track)
// 13-15 aren't used yet
// and the last bit we ignore (internal game flag for resetting music on reload)
void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms);
#define S_ChangeMusicInternal(a,b) S_ChangeMusicEx(a,0,b,0,0,0)
#define S_ChangeMusic(a,b,c) S_ChangeMusicEx(a,b,c,0,0,0)
void S_ChangeMusicSpecial (const char *mmusic);
void S_SetRestoreMusicFadeInCvar (consvar_t *cvar);
#define S_ClearRestoreMusicFadeInCvar() \
S_SetRestoreMusicFadeInCvar(0)
int S_GetRestoreMusicFadeIn (void);
void S_SetMusicUsage (int type);
int S_MusicUsage (void);
// Stops the music.
void S_StopMusic(void);
// Stop and resume music, during game PAUSE.
void S_PauseAudio(void);
void S_ResumeAudio(void);
@ -349,17 +244,6 @@ void S_DisableSound(void);
// Attempt to restore music based on gamestate.
void S_AttemptToRestoreMusic(void);
//
// Music Fading
//
void S_SetInternalMusicVolume(INT32 volume);
void S_StopFadingMusic(void);
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms);
#define S_FadeMusic(a, b) S_FadeMusicFromVolume(a, -1, b)
#define S_FadeInChangeMusic(a,b,c,d) S_ChangeMusicEx(a,b,c,0,0,d)
boolean S_FadeOutStopMusic(UINT32 ms);
//
// Updates music & sounds
//

View file

@ -50,6 +50,8 @@
#include "k_grandprix.h" // we need to know grandprix status for titlecards
#include "k_boss.h"
#include "k_zvote.h"
#include "music.h"
#include "i_sound.h"
UINT16 objectsdrawn = 0;
@ -381,38 +383,40 @@ static void ST_pushDebugTimeMS(INT32 *height, const char *label, UINT32 ms)
static void ST_drawMusicDebug(INT32 *height)
{
char mname[7];
UINT16 mflags; // unused
boolean looping;
const char *mname = Music_CurrentSong();
boolean looping = Music_CanLoop(Music_CurrentId());
UINT8 i = 0;
const musicdef_t *def;
const char *format;
if (!S_MusicInfo(mname, &mflags, &looping))
ST_pushDebugString(height, va(" Tune: %8s", Music_CurrentId()));
ST_pushRow(height);
if (!strcmp(mname, ""))
{
ST_pushDebugString(height, "Song: <NOTHING>");
return;
}
def = S_FindMusicDef(mname, &i);
format = S_MusicType();
format = I_SongType();
ST_pushDebugTimeMS(height, " Elapsed: ", S_GetMusicPosition());
ST_pushDebugTimeMS(height, " Elapsed: ", I_GetSongPosition());
ST_pushDebugTimeMS(height, looping
? " Loop B: "
: "Duration: ", S_GetMusicLength());
: "Duration: ", I_GetSongLength());
if (looping)
{
ST_pushDebugTimeMS(height, " Loop A: ", S_GetMusicLoopPoint());
ST_pushDebugTimeMS(height, " Loop A: ", I_GetSongLoopPoint());
}
ST_pushRow(height);
if (format)
{
ST_pushDebugString(height, va(" Format: %8s", S_MusicType()));
ST_pushDebugString(height, va(" Format: %8s", I_SongType()));
}
ST_pushDebugString(height, va(" Song: %8s", mname));

View file

@ -50,6 +50,7 @@
#include "k_grandprix.h"
#include "k_serverstats.h" // SV_BumpMatchStats
#include "m_easing.h"
#include "music.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -1823,7 +1824,7 @@ void Y_StartIntermission(void)
I_Error("Y_StartIntermission: Internal map ID %d not found (nummapheaders = %d)", prevmap, nummapheaders);
if (timer > 1 && musiccountdown == 0)
S_ChangeMusicInternal("racent", true); // loop it
Music_Play("intermission");
S_ShowMusicCredit(); // Always call