mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Replace music handling
(This commit does not compile. Sound test and tunes command code needs to be ported after this.) This is a big one. Here's the rundown: The old music system was very direct, much of the time just a proxy to the real sound API in i_sound.h. You could change the music on command, but there wasn't a consistent way to prevent some music from playing over others. P_RestoreMusic is one example of needing to address this problem. The jingles system was intended as another solution. Furthermore, sound test (Stereo) has its own needs. I am removing all of that. Music handling in general is now a very deliberate system, kind of similar to jingles. In the new system, "tunes" are registered. The tune stores info such as whether it should loop or fade out. Most of the configuration is intended to be initialized only ONCE. Tunes can be mapped to an actual music lump. They can be remapped at any time too. Tunes are also configured with a priority number. This determines which tune is heard, if multiple are supposed to be playing at a time. You can even tell a tune how long it should play, so it's unnecessary to track this with bespoke timers.
This commit is contained in:
parent
646701c55c
commit
39f46a0f20
29 changed files with 1210 additions and 1187 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
13
src/g_game.c
13
src/g_game.c
|
|
@ -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)
|
||||
|
|
|
|||
29
src/k_kart.c
29
src/k_kart.c
|
|
@ -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)
|
||||
|
|
@ -3843,8 +3844,6 @@ void K_RemoveGrowShrink(player_t *player)
|
|||
}
|
||||
|
||||
player->growshrinktimer = 0;
|
||||
|
||||
P_RestoreMusic(player);
|
||||
}
|
||||
|
||||
boolean K_IsBigger(mobj_t *compare, mobj_t *other)
|
||||
|
|
@ -4380,7 +4379,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;
|
||||
|
|
@ -6197,18 +6196,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)
|
||||
|
|
@ -11281,25 +11274,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--;
|
||||
|
|
@ -11934,7 +11917,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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
10
src/k_vote.c
10
src/k_vote.c
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
322
src/music.cpp
Normal file
322
src/music.cpp
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
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
148
src/music.h
Normal 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
38
src/music_detail.hpp
Normal 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
204
src/music_manager.cpp
Normal 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
113
src/music_manager.hpp
Normal 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
194
src/music_tune.hpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
13
src/p_tick.c
13
src/p_tick.c
|
|
@ -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))
|
||||
|
|
|
|||
220
src/p_user.c
220
src/p_user.c
|
|
@ -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,90 +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
|
||||
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)
|
||||
|
|
@ -716,7 +619,7 @@ void P_StartPositionMusic(boolean exact)
|
|||
: (leveltime < 1))
|
||||
return;
|
||||
|
||||
S_ChangeMusicInternal("encore", true);
|
||||
Music_Remap("position", "encore");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -725,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);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -870,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);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1423,7 +1273,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
|
||||
if (P_IsLocalPlayer(player) && !specialout)
|
||||
{
|
||||
S_StopMusic();
|
||||
Music_StopAll();
|
||||
musiccountdown = MUSICCOUNTDOWNMAX;
|
||||
}
|
||||
|
||||
|
|
@ -1945,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -4036,7 +3884,7 @@ void P_DoTimeOver(player_t *player)
|
|||
|
||||
if (P_IsLocalPlayer(player))
|
||||
{
|
||||
S_StopMusic();
|
||||
Music_StopAll();
|
||||
musiccountdown = MUSICCOUNTDOWNMAX;
|
||||
}
|
||||
|
||||
|
|
|
|||
773
src/s_sound.c
773
src/s_sound.c
|
|
@ -35,6 +35,7 @@
|
|||
#include "m_random.h" // P_RandomKey
|
||||
#include "i_time.h"
|
||||
#include "v_video.h" // V_ThinStringWidth
|
||||
#include "music.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
// 3D Sound Interface
|
||||
|
|
@ -62,10 +63,6 @@ static void PlaySoundIfUnfocused_OnChange(void);
|
|||
static void ModFilter_OnChange(void);
|
||||
#endif
|
||||
|
||||
static lumpnum_t S_GetMusicLumpNum(const char *mname);
|
||||
|
||||
static boolean S_CheckQueue(void);
|
||||
|
||||
consvar_t cv_samplerate = CVAR_INIT ("samplerate", "22050", 0, CV_Unsigned, NULL); //Alam: For easy hacking?
|
||||
|
||||
// stereo reverse
|
||||
|
|
@ -1347,21 +1344,6 @@ void S_InitSfxChannels(INT32 sfxVolume)
|
|||
/// Music
|
||||
/// ------------------------
|
||||
|
||||
static char music_name[7]; // up to 6-character name
|
||||
static void *music_data;
|
||||
static UINT16 music_flags;
|
||||
static boolean music_looping;
|
||||
static consvar_t *music_refade_cv;
|
||||
static int music_usage;
|
||||
|
||||
static char queue_name[7];
|
||||
static UINT16 queue_flags;
|
||||
static boolean queue_looping;
|
||||
static UINT32 queue_position;
|
||||
static UINT32 queue_fadeinms;
|
||||
|
||||
static tic_t pause_starttic;
|
||||
|
||||
void S_AttemptToRestoreMusic(void)
|
||||
{
|
||||
switch (gamestate)
|
||||
|
|
@ -1369,18 +1351,20 @@ void S_AttemptToRestoreMusic(void)
|
|||
case GS_LEVEL:
|
||||
if (musiccountdown != 1)
|
||||
{
|
||||
P_RestoreMusic(&players[consoleplayer]);
|
||||
P_LoadLevelMusic();
|
||||
Music_Play("level");
|
||||
break;
|
||||
}
|
||||
// FALLTHRU
|
||||
case GS_INTERMISSION:
|
||||
S_ChangeMusicInternal("racent", true);
|
||||
Music_Play("intermission");
|
||||
break;
|
||||
case GS_CEREMONY:
|
||||
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
|
||||
Music_Play("level");
|
||||
break;
|
||||
case GS_TITLESCREEN:
|
||||
S_ChangeMusicInternal("_title", looptitle);
|
||||
Music_Loop("title", looptitle);
|
||||
Music_Play("title");
|
||||
break;
|
||||
case GS_MENU:
|
||||
M_PlayMenuJam();
|
||||
|
|
@ -1822,16 +1806,6 @@ handlenextsong:
|
|||
S_UpdateSoundTestDef(false, true, true);
|
||||
}
|
||||
|
||||
boolean S_PlaysimMusicDisabled(void)
|
||||
{
|
||||
if (soundtest.privilegedrequest)
|
||||
return false;
|
||||
|
||||
return (soundtest.playing // Ring Racers: Stereo Mode
|
||||
|| demo.rewinding // Don't mess with music while rewinding!
|
||||
|| demo.title); // SRB2Kart: Demos don't interrupt title screen music
|
||||
}
|
||||
|
||||
//
|
||||
// S_FindMusicDef
|
||||
//
|
||||
|
|
@ -2130,14 +2104,14 @@ void S_InitMusicDefs(void)
|
|||
void S_ShowMusicCredit(void)
|
||||
{
|
||||
UINT8 i = 0;
|
||||
musicdef_t *def = S_FindMusicDef(music_name, &i);
|
||||
musicdef_t *def = S_FindMusicDef(Music_CurrentSong(), &i);
|
||||
|
||||
char credittext[128] = "";
|
||||
char *work = NULL;
|
||||
size_t len = 128, worklen;
|
||||
INT32 widthused = BASEVIDWIDTH, workwidth;
|
||||
|
||||
if (!cv_songcredits.value || S_PlaysimMusicDisabled())
|
||||
if (!cv_songcredits.value)
|
||||
return;
|
||||
|
||||
if (!def) // No definitions
|
||||
|
|
@ -2206,9 +2180,6 @@ void S_ShowMusicCredit(void)
|
|||
|
||||
void S_StopMusicCredit(void)
|
||||
{
|
||||
if (S_PlaysimMusicDisabled())
|
||||
return;
|
||||
|
||||
cursongcredit.def = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2216,26 +2187,11 @@ void S_StopMusicCredit(void)
|
|||
/// Music Status
|
||||
/// ------------------------
|
||||
|
||||
boolean S_DigMusicDisabled(void)
|
||||
{
|
||||
return digital_disabled;
|
||||
}
|
||||
|
||||
boolean S_MusicDisabled(void)
|
||||
{
|
||||
return digital_disabled;
|
||||
}
|
||||
|
||||
boolean S_MusicPlaying(void)
|
||||
{
|
||||
return I_SongPlaying();
|
||||
}
|
||||
|
||||
boolean S_MusicPaused(void)
|
||||
{
|
||||
return I_SongPaused();
|
||||
}
|
||||
|
||||
boolean S_MusicNotInFocus(void)
|
||||
{
|
||||
return (
|
||||
|
|
@ -2243,616 +2199,16 @@ boolean S_MusicNotInFocus(void)
|
|||
);
|
||||
}
|
||||
|
||||
const char *S_MusicType(void)
|
||||
{
|
||||
return I_SongType();
|
||||
}
|
||||
|
||||
const char *S_MusicName(void)
|
||||
{
|
||||
return music_name;
|
||||
}
|
||||
|
||||
boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping)
|
||||
{
|
||||
if (!I_SongPlaying())
|
||||
return false;
|
||||
|
||||
strncpy(mname, music_name, 7);
|
||||
mname[6] = 0;
|
||||
*mflags = music_flags;
|
||||
*looping = music_looping;
|
||||
|
||||
return (boolean)mname[0];
|
||||
}
|
||||
|
||||
boolean S_MusicExists(const char *mname)
|
||||
{
|
||||
return W_CheckNumForName(va("O_%s", mname)) != LUMPERROR;
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
/// Music Effects
|
||||
/// ------------------------
|
||||
|
||||
boolean S_SpeedMusic(float speed)
|
||||
{
|
||||
return I_SetSongSpeed(speed);
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
/// Music Seeking
|
||||
/// ------------------------
|
||||
|
||||
UINT32 S_GetMusicLength(void)
|
||||
{
|
||||
return I_GetSongLength();
|
||||
}
|
||||
|
||||
boolean S_SetMusicLoopPoint(UINT32 looppoint)
|
||||
{
|
||||
return I_SetSongLoopPoint(looppoint);
|
||||
}
|
||||
|
||||
UINT32 S_GetMusicLoopPoint(void)
|
||||
{
|
||||
return I_GetSongLoopPoint();
|
||||
}
|
||||
|
||||
boolean S_SetMusicPosition(UINT32 position)
|
||||
{
|
||||
if (S_PlaysimMusicDisabled())
|
||||
return false;
|
||||
|
||||
return I_SetSongPosition(position);
|
||||
}
|
||||
|
||||
UINT32 S_GetMusicPosition(void)
|
||||
{
|
||||
return I_GetSongPosition();
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
/// Music Stacking (Jingles)
|
||||
/// In this section: mazmazz doesn't know how to do dynamic arrays or struct pointers!
|
||||
/// ------------------------
|
||||
|
||||
char music_stack_nextmusname[7];
|
||||
boolean music_stack_noposition = false;
|
||||
UINT32 music_stack_fadeout = 0;
|
||||
UINT32 music_stack_fadein = 0;
|
||||
static musicstack_t *music_stacks = NULL;
|
||||
static musicstack_t *last_music_stack = NULL;
|
||||
|
||||
void S_SetStackAdjustmentStart(void)
|
||||
{
|
||||
if (!pause_starttic)
|
||||
pause_starttic = gametic;
|
||||
}
|
||||
|
||||
void S_AdjustMusicStackTics(void)
|
||||
{
|
||||
if (pause_starttic)
|
||||
{
|
||||
musicstack_t *mst;
|
||||
for (mst = music_stacks; mst; mst = mst->next)
|
||||
mst->tic += gametic - pause_starttic;
|
||||
pause_starttic = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void S_ResetMusicStack(void)
|
||||
{
|
||||
musicstack_t *mst, *mst_next;
|
||||
for (mst = music_stacks; mst; mst = mst_next)
|
||||
{
|
||||
mst_next = mst->next;
|
||||
Z_Free(mst);
|
||||
}
|
||||
music_stacks = last_music_stack = NULL;
|
||||
}
|
||||
|
||||
static void S_RemoveMusicStackEntry(musicstack_t *entry)
|
||||
{
|
||||
musicstack_t *mst;
|
||||
for (mst = music_stacks; mst; mst = mst->next)
|
||||
{
|
||||
if (mst == entry)
|
||||
{
|
||||
// Remove ourselves from the chain and link
|
||||
// prev and next together
|
||||
|
||||
if (mst->prev)
|
||||
mst->prev->next = mst->next;
|
||||
else
|
||||
music_stacks = mst->next;
|
||||
|
||||
if (mst->next)
|
||||
mst->next->prev = mst->prev;
|
||||
else
|
||||
last_music_stack = mst->prev;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z_Free(entry);
|
||||
}
|
||||
|
||||
static void S_RemoveMusicStackEntryByStatus(UINT16 status)
|
||||
{
|
||||
musicstack_t *mst, *mst_next;
|
||||
|
||||
if (!status)
|
||||
return;
|
||||
|
||||
for (mst = music_stacks; mst; mst = mst_next)
|
||||
{
|
||||
mst_next = mst->next;
|
||||
if (mst->status == status)
|
||||
S_RemoveMusicStackEntry(mst);
|
||||
}
|
||||
}
|
||||
|
||||
static void S_AddMusicStackEntry(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status)
|
||||
{
|
||||
musicstack_t *mst, *new_mst;
|
||||
|
||||
// if the first entry is empty, force master onto it
|
||||
if (!music_stacks)
|
||||
{
|
||||
music_stacks = Z_Calloc(sizeof (*mst), PU_MUSIC, NULL);
|
||||
strncpy(music_stacks->musname, (status == JT_MASTER ? mname : (S_CheckQueue() ? queue_name : mapmusname)), 7);
|
||||
music_stacks->musflags = (status == JT_MASTER ? mflags : (S_CheckQueue() ? queue_flags : mapmusflags));
|
||||
music_stacks->looping = (status == JT_MASTER ? looping : (S_CheckQueue() ? queue_looping : true));
|
||||
music_stacks->position = (status == JT_MASTER ? position : (S_CheckQueue() ? queue_position : S_GetMusicPosition()));
|
||||
music_stacks->tic = gametic;
|
||||
music_stacks->status = JT_MASTER;
|
||||
music_stacks->mlumpnum = S_GetMusicLumpNum(music_stacks->musname);
|
||||
music_stacks->noposition = S_CheckQueue();
|
||||
|
||||
if (status == JT_MASTER)
|
||||
return; // we just added the user's entry here
|
||||
}
|
||||
|
||||
// look for an empty slot to park ourselves
|
||||
for (mst = music_stacks; mst->next; mst = mst->next);
|
||||
|
||||
// create our new entry
|
||||
new_mst = Z_Calloc(sizeof (*new_mst), PU_MUSIC, NULL);
|
||||
strncpy(new_mst->musname, mname, 7);
|
||||
new_mst->musname[6] = 0;
|
||||
new_mst->musflags = mflags;
|
||||
new_mst->looping = looping;
|
||||
new_mst->position = position;
|
||||
new_mst->tic = gametic;
|
||||
new_mst->status = status;
|
||||
new_mst->mlumpnum = S_GetMusicLumpNum(new_mst->musname);
|
||||
new_mst->noposition = false;
|
||||
|
||||
mst->next = new_mst;
|
||||
new_mst->prev = mst;
|
||||
new_mst->next = NULL;
|
||||
last_music_stack = new_mst;
|
||||
}
|
||||
|
||||
static musicstack_t *S_GetMusicStackEntry(UINT16 status, boolean fromfirst, INT16 startindex)
|
||||
{
|
||||
musicstack_t *mst, *start_mst = NULL, *mst_next;
|
||||
|
||||
// if the first entry is empty, force master onto it
|
||||
// fixes a memory corruption bug
|
||||
if (!music_stacks && status != JT_MASTER)
|
||||
S_AddMusicStackEntry(mapmusname, mapmusflags, true, S_GetMusicPosition(), JT_MASTER);
|
||||
|
||||
if (startindex >= 0)
|
||||
{
|
||||
INT16 i = 0;
|
||||
for (mst = music_stacks; mst && i <= startindex; mst = mst->next, i++)
|
||||
start_mst = mst;
|
||||
}
|
||||
else
|
||||
start_mst = (fromfirst ? music_stacks : last_music_stack);
|
||||
|
||||
for (mst = start_mst; mst; mst = mst_next)
|
||||
{
|
||||
mst_next = (fromfirst ? mst->next : mst->prev);
|
||||
|
||||
if (!status || mst->status == status)
|
||||
{
|
||||
if (P_EvaluateMusicStatus(mst->status, mst->musname))
|
||||
{
|
||||
if (!S_MusicExists(mst->musname)) // paranoia
|
||||
S_RemoveMusicStackEntry(mst); // then continue
|
||||
else
|
||||
return mst;
|
||||
}
|
||||
else
|
||||
S_RemoveMusicStackEntry(mst); // then continue
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void S_RetainMusic(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status)
|
||||
{
|
||||
musicstack_t *mst;
|
||||
|
||||
if (!status) // we use this as a null indicator, don't push
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Music stack entry must have a nonzero status.\n");
|
||||
return;
|
||||
}
|
||||
else if (status == JT_MASTER) // enforce only one JT_MASTER
|
||||
{
|
||||
for (mst = music_stacks; mst; mst = mst->next)
|
||||
{
|
||||
if (mst->status == JT_MASTER)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Music stack can only have one JT_MASTER entry.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // remove any existing status
|
||||
S_RemoveMusicStackEntryByStatus(status);
|
||||
|
||||
S_AddMusicStackEntry(mname, mflags, looping, position, status);
|
||||
}
|
||||
|
||||
boolean S_RecallMusic(UINT16 status, boolean fromfirst)
|
||||
{
|
||||
UINT32 newpos = 0;
|
||||
boolean mapmuschanged = false;
|
||||
musicstack_t *result;
|
||||
musicstack_t *entry;
|
||||
|
||||
if (S_PlaysimMusicDisabled())
|
||||
return false;
|
||||
|
||||
entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL);
|
||||
|
||||
if (status)
|
||||
result = S_GetMusicStackEntry(status, fromfirst, -1);
|
||||
else
|
||||
result = S_GetMusicStackEntry(JT_NONE, false, -1);
|
||||
|
||||
if (result && !S_MusicExists(result->musname))
|
||||
{
|
||||
Z_Free(entry);
|
||||
return false; // music doesn't exist, so don't do anything
|
||||
}
|
||||
|
||||
// make a copy of result, since we make modifications to our copy
|
||||
if (result)
|
||||
{
|
||||
*entry = *result;
|
||||
strncpy(entry->musname, result->musname, 7);
|
||||
}
|
||||
|
||||
// no result, just grab mapmusname
|
||||
if (!result || !entry->musname[0] || ((status == JT_MASTER || (music_stacks ? !music_stacks->status : false)) && !entry->status))
|
||||
{
|
||||
strncpy(entry->musname, mapmusname, 7);
|
||||
entry->musflags = mapmusflags;
|
||||
entry->looping = true;
|
||||
entry->position = mapmusposition;
|
||||
entry->tic = gametic;
|
||||
entry->status = JT_MASTER;
|
||||
entry->mlumpnum = S_GetMusicLumpNum(entry->musname);
|
||||
entry->noposition = false; // don't set this until we do the mapmuschanged check, below. Else, this breaks some resumes.
|
||||
}
|
||||
|
||||
if (entry->status == JT_MASTER)
|
||||
{
|
||||
mapmuschanged = strnicmp(entry->musname, mapmusname, 7);
|
||||
if (mapmuschanged)
|
||||
{
|
||||
strncpy(entry->musname, mapmusname, 7);
|
||||
entry->musflags = mapmusflags;
|
||||
entry->looping = true;
|
||||
entry->position = mapmusposition;
|
||||
entry->tic = gametic;
|
||||
entry->status = JT_MASTER;
|
||||
entry->mlumpnum = S_GetMusicLumpNum(entry->musname);
|
||||
entry->noposition = true;
|
||||
}
|
||||
S_ResetMusicStack();
|
||||
}
|
||||
else if (!entry->status)
|
||||
{
|
||||
Z_Free(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(entry->musname, S_MusicName(), 7)) // don't restart music if we're already playing it
|
||||
{
|
||||
if (music_stack_fadeout)
|
||||
S_ChangeMusicEx(entry->musname, entry->musflags, entry->looping, 0, music_stack_fadeout, 0);
|
||||
else
|
||||
{
|
||||
S_ChangeMusicEx(entry->musname, entry->musflags, entry->looping, 0, 0, music_stack_fadein);
|
||||
|
||||
if (!entry->noposition && !music_stack_noposition) // HACK: Global boolean to toggle position resuming, e.g., de-superize
|
||||
{
|
||||
UINT32 poslapse = 0;
|
||||
|
||||
// To prevent the game from jumping past the end of the music, we need
|
||||
// to check if we can get the song's length. Otherwise, if the lapsed resume time goes
|
||||
// over a LOOPPOINT, mixer_sound.c will be unable to calculate the new resume position.
|
||||
if (S_GetMusicLength())
|
||||
poslapse = (UINT32)((float)(gametic - entry->tic)/(float)TICRATE*(float)MUSICRATE);
|
||||
|
||||
newpos = entry->position + poslapse;
|
||||
}
|
||||
|
||||
// If the newly recalled music lumpnum does not match the lumpnum that we stored in stack,
|
||||
// then discard the new position. That way, we will not recall an invalid position
|
||||
// when the music is replaced or digital/MIDI is toggled.
|
||||
if (newpos > 0 && S_MusicPlaying() && S_GetMusicLumpNum(entry->musname) == entry->mlumpnum)
|
||||
S_SetMusicPosition(newpos);
|
||||
else
|
||||
{
|
||||
S_StopFadingMusic();
|
||||
S_SetInternalMusicVolume(100);
|
||||
}
|
||||
}
|
||||
music_stack_noposition = false;
|
||||
music_stack_fadeout = 0;
|
||||
music_stack_fadein = JINGLEPOSTFADE;
|
||||
}
|
||||
|
||||
Z_Free(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
/// Music Playback
|
||||
/// ------------------------
|
||||
|
||||
static lumpnum_t S_GetMusicLumpNum(const char *mname)
|
||||
{
|
||||
if (S_MusicExists(mname))
|
||||
return W_GetNumForName(va("o_%s", mname));
|
||||
else
|
||||
return LUMPERROR;
|
||||
}
|
||||
|
||||
static boolean S_LoadMusic(const char *mname)
|
||||
{
|
||||
lumpnum_t mlumpnum;
|
||||
void *mdata;
|
||||
|
||||
if (S_MusicDisabled())
|
||||
return false;
|
||||
|
||||
mlumpnum = S_GetMusicLumpNum(mname);
|
||||
|
||||
if (mlumpnum == LUMPERROR)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded: lump not found!\n", mname);
|
||||
return false;
|
||||
}
|
||||
|
||||
// load & register it
|
||||
mdata = W_CacheLumpNum(mlumpnum, PU_MUSIC);
|
||||
|
||||
if (I_LoadSong(mdata, W_LumpLength(mlumpnum)))
|
||||
{
|
||||
strncpy(music_name, mname, 7);
|
||||
music_name[6] = 0;
|
||||
music_data = mdata;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded: engine failure!\n", mname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void S_UnloadMusic(void)
|
||||
{
|
||||
I_UnloadSong();
|
||||
|
||||
#ifndef HAVE_SDL //SDL uses RWOPS
|
||||
Z_ChangeTag(music_data, PU_CACHE);
|
||||
#endif
|
||||
music_data = NULL;
|
||||
|
||||
music_name[0] = 0;
|
||||
music_flags = 0;
|
||||
music_looping = false;
|
||||
|
||||
music_refade_cv = 0;
|
||||
music_usage = 0;
|
||||
}
|
||||
|
||||
static boolean S_PlayMusic(boolean looping, UINT32 fadeinms)
|
||||
{
|
||||
//musicdef_t *def;
|
||||
|
||||
if (S_MusicDisabled())
|
||||
return false;
|
||||
|
||||
I_UpdateSongLagConditions();
|
||||
|
||||
if ((!fadeinms && !I_PlaySong(looping)) ||
|
||||
(fadeinms && !I_FadeInPlaySong(fadeinms, looping)))
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Music %.6s could not be played: engine failure!\n", music_name);
|
||||
S_UnloadMusic();
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* set loop point from MUSICDEF */
|
||||
for (def = musicdefstart; def; def = def->next)
|
||||
{
|
||||
if (strcasecmp(def->name, music_name) == 0)
|
||||
{
|
||||
if (def->loop_ms)
|
||||
S_SetMusicLoopPoint(def->loop_ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
S_InitMusicVolume(); // switch between digi and sequence volume
|
||||
|
||||
if (S_MusicNotInFocus())
|
||||
I_SetMusicVolume(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void S_QueueMusic(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 fadeinms)
|
||||
{
|
||||
strncpy(queue_name, mmusic, 7);
|
||||
queue_flags = mflags;
|
||||
queue_looping = looping;
|
||||
queue_position = position;
|
||||
queue_fadeinms = fadeinms;
|
||||
}
|
||||
|
||||
static boolean S_CheckQueue(void)
|
||||
{
|
||||
return queue_name[0];
|
||||
}
|
||||
|
||||
static void S_ClearQueue(void)
|
||||
{
|
||||
queue_name[0] = queue_flags = queue_looping = queue_position = queue_fadeinms = 0;
|
||||
}
|
||||
|
||||
static void S_ChangeMusicToQueue(void)
|
||||
{
|
||||
S_ChangeMusicEx(queue_name, queue_flags, queue_looping, queue_position, 0, queue_fadeinms);
|
||||
S_ClearQueue();
|
||||
}
|
||||
|
||||
void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms)
|
||||
{
|
||||
char newmusic[7];
|
||||
|
||||
if (S_MusicDisabled() || S_PlaysimMusicDisabled())
|
||||
return;
|
||||
|
||||
strncpy(newmusic, mmusic, 7);
|
||||
|
||||
newmusic[6] = 0;
|
||||
|
||||
// No Music (empty string)
|
||||
if (newmusic[0] == 0)
|
||||
{
|
||||
if (prefadems)
|
||||
I_FadeSong(0, prefadems, &S_StopMusic);
|
||||
else
|
||||
S_StopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefadems) // queue music change for after fade // allow even if the music is the same
|
||||
// && S_MusicPlaying() // Let the delay happen even if we're not playing music
|
||||
{
|
||||
CONS_Debug(DBG_DETAILED, "Now fading out song %s\n", music_name);
|
||||
S_QueueMusic(newmusic, mflags, looping, position, fadeinms);
|
||||
I_FadeSong(0, prefadems, S_ChangeMusicToQueue);
|
||||
return;
|
||||
}
|
||||
else if (strnicmp(music_name, newmusic, 6) || (mflags & MUSIC_FORCERESET))
|
||||
{
|
||||
CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic);
|
||||
|
||||
S_StopMusic();
|
||||
|
||||
if (!S_LoadMusic(newmusic))
|
||||
return;
|
||||
|
||||
music_flags = mflags;
|
||||
music_looping = looping;
|
||||
|
||||
{
|
||||
UINT8 i = 0;
|
||||
musicdef_t *def = S_FindMusicDef(music_name, &i);
|
||||
|
||||
if (def)
|
||||
{
|
||||
I_SetCurrentSongVolume(def->debug_volume != 0 ? def->debug_volume : def->volume);
|
||||
}
|
||||
}
|
||||
|
||||
if (!S_PlayMusic(looping, fadeinms))
|
||||
return;
|
||||
|
||||
if (position)
|
||||
I_SetSongPosition(position);
|
||||
|
||||
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
|
||||
|
||||
// Slow level music down a bit in Encore. (Values are vibe-based. WE GET IT YOU VAPE)
|
||||
S_SpeedMusic((encoremode && gamestate == GS_LEVEL) ? 0.86471f : 1.f);
|
||||
}
|
||||
else if (fadeinms) // let fades happen with same music
|
||||
{
|
||||
I_SetSongPosition(position);
|
||||
I_FadeSong(100, fadeinms, NULL);
|
||||
}
|
||||
else // reset volume to 100 with same music
|
||||
{
|
||||
I_StopFadingSong();
|
||||
I_FadeSong(100, 500, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void S_ChangeMusicSpecial (const char *mmusic)
|
||||
{
|
||||
if (cv_resetspecialmusic.value)
|
||||
S_ChangeMusic(mmusic, MUSIC_FORCERESET, true);
|
||||
else
|
||||
S_ChangeMusicInternal(mmusic, true);
|
||||
}
|
||||
|
||||
void S_StopMusic(void)
|
||||
{
|
||||
if (!I_SongPlaying() || S_PlaysimMusicDisabled())
|
||||
return;
|
||||
|
||||
if (strcasecmp(music_name, mapmusname) == 0)
|
||||
mapmusresume = I_GetSongPosition();
|
||||
|
||||
if (I_SongPaused())
|
||||
I_ResumeSong();
|
||||
|
||||
I_StopSong();
|
||||
S_UnloadMusic(); // for now, stopping also means you unload the song
|
||||
|
||||
if (cv_closedcaptioning.value)
|
||||
{
|
||||
if (closedcaptions[0].s-S_sfx == sfx_None)
|
||||
{
|
||||
if (gamestate != wipegamestate)
|
||||
{
|
||||
closedcaptions[0].c = NULL;
|
||||
closedcaptions[0].s = NULL;
|
||||
closedcaptions[0].t = 0;
|
||||
closedcaptions[0].b = 0;
|
||||
}
|
||||
else
|
||||
closedcaptions[0].t = CAPTIONFADETICS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Stop and resume music, during game PAUSE.
|
||||
//
|
||||
void S_PauseAudio(void)
|
||||
{
|
||||
if (I_SongPlaying() && !I_SongPaused())
|
||||
I_PauseSong();
|
||||
|
||||
S_SetStackAdjustmentStart();
|
||||
Music_PauseAll();
|
||||
}
|
||||
|
||||
void S_ResumeAudio(void)
|
||||
|
|
@ -2860,13 +2216,7 @@ void S_ResumeAudio(void)
|
|||
if (S_MusicNotInFocus())
|
||||
return;
|
||||
|
||||
if (soundtest.paused == true)
|
||||
return;
|
||||
|
||||
if (I_SongPlaying() && I_SongPaused())
|
||||
I_ResumeSong();
|
||||
|
||||
S_AdjustMusicStackTics();
|
||||
Music_UnPauseAll();
|
||||
}
|
||||
|
||||
void S_SetMusicVolume(INT32 digvolume)
|
||||
|
|
@ -2879,103 +2229,10 @@ void S_SetMusicVolume(INT32 digvolume)
|
|||
I_SetMusicVolume(digvolume);
|
||||
}
|
||||
|
||||
void
|
||||
S_SetRestoreMusicFadeInCvar (consvar_t *cv)
|
||||
{
|
||||
music_refade_cv = cv;
|
||||
}
|
||||
|
||||
int
|
||||
S_GetRestoreMusicFadeIn (void)
|
||||
{
|
||||
if (music_refade_cv)
|
||||
return music_refade_cv->value;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
S_SetMusicUsage (int type)
|
||||
{
|
||||
music_usage = type;
|
||||
I_UpdateSongLagConditions();
|
||||
}
|
||||
|
||||
int
|
||||
S_MusicUsage (void)
|
||||
{
|
||||
return music_usage;
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
/// Music Fading
|
||||
/// ------------------------
|
||||
|
||||
void S_SetInternalMusicVolume(INT32 volume)
|
||||
{
|
||||
I_SetInternalMusicVolume(min(max(volume, 0), 100));
|
||||
}
|
||||
|
||||
void S_StopFadingMusic(void)
|
||||
{
|
||||
I_StopFadingSong();
|
||||
}
|
||||
|
||||
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms)
|
||||
{
|
||||
if (S_PlaysimMusicDisabled())
|
||||
return false;
|
||||
|
||||
if (source_volume < 0)
|
||||
return I_FadeSong(target_volume, ms, NULL);
|
||||
else
|
||||
return I_FadeSongFromVolume(target_volume, source_volume, ms, NULL);
|
||||
}
|
||||
|
||||
boolean S_FadeOutStopMusic(UINT32 ms)
|
||||
{
|
||||
if (S_PlaysimMusicDisabled())
|
||||
return false;
|
||||
|
||||
return I_FadeSong(0, ms, &S_StopMusic);
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
/// Init & Others
|
||||
/// ------------------------
|
||||
|
||||
//
|
||||
// Per level startup code.
|
||||
// Kills playing sounds at start of level,
|
||||
// determines music if any, changes music.
|
||||
//
|
||||
void S_InitLevelMusic(boolean fromnetsave)
|
||||
{
|
||||
|
||||
if (mapmusflags & MUSIC_RELOADRESET)
|
||||
{
|
||||
if (!fromnetsave)
|
||||
{
|
||||
if (mapheaderinfo[gamemap-1]->musname_size > 1)
|
||||
mapmusrng = P_RandomKey(PR_MUSICSELECT, mapheaderinfo[gamemap-1]->musname_size);
|
||||
else
|
||||
mapmusrng = 0;
|
||||
}
|
||||
strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname[mapmusrng], 7);
|
||||
mapmusname[6] = 0;
|
||||
mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
|
||||
mapmusposition = mapheaderinfo[gamemap-1]->muspos;
|
||||
mapmusresume = 0;
|
||||
}
|
||||
|
||||
S_StopMusic();
|
||||
|
||||
S_ResetMusicStack();
|
||||
music_stack_noposition = false;
|
||||
music_stack_fadeout = 0;
|
||||
music_stack_fadein = JINGLEPOSTFADE;
|
||||
}
|
||||
|
||||
static inline void PrintMusicDefField(const char *label, const char *field)
|
||||
{
|
||||
if (field)
|
||||
|
|
@ -3095,7 +2352,7 @@ static void Command_RestartAudio_f(void)
|
|||
if (dedicated) // No point in doing anything if game is a dedicated server.
|
||||
return;
|
||||
|
||||
S_StopMusic();
|
||||
Music_StopAll();
|
||||
S_StopSounds();
|
||||
I_ShutdownMusic();
|
||||
I_ShutdownSound();
|
||||
|
|
@ -3223,7 +2480,7 @@ static void Command_MusicDef_f(void)
|
|||
{
|
||||
UINT8 i = 0;
|
||||
|
||||
def = S_FindMusicDef(music_name, &i);
|
||||
def = S_FindMusicDef(Music_CurrentSong(), &i);
|
||||
def->debug_volume = atoi(arg2);
|
||||
I_SetCurrentSongVolume(def->debug_volume);
|
||||
|
||||
|
|
@ -3298,13 +2555,11 @@ void GameDigiMusic_OnChange(void)
|
|||
digital_disabled = false;
|
||||
I_StartupSound(); // will return early if initialised
|
||||
I_InitMusic();
|
||||
|
||||
S_AttemptToRestoreMusic();
|
||||
}
|
||||
else
|
||||
{
|
||||
digital_disabled = true;
|
||||
S_StopMusic();
|
||||
I_UnloadSong();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
101
src/s_sound.h
101
src/s_sound.h
|
|
@ -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
|
||||
|
||||
|
|
@ -240,8 +226,6 @@ void S_SoundTestTogglePause(void);
|
|||
void S_TickSoundTest(void);
|
||||
#define SOUNDTEST_FADEOUTSECONDS 5
|
||||
|
||||
boolean S_PlaysimMusicDisabled(void);
|
||||
|
||||
extern musicdef_t *musicdefstart;
|
||||
|
||||
void S_LoadMusicDefs(UINT16 wadnum);
|
||||
|
|
@ -250,84 +234,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
|
||||
//
|
||||
|
||||
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);
|
||||
|
|
@ -339,17 +249,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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue