- separated the game-dependent music lookup parts from the core player.

This commit is contained in:
Christoph Oelckers 2020-04-11 18:24:00 +02:00
parent 4af96bab47
commit f0534afde6
3 changed files with 177 additions and 111 deletions

View file

@ -72,6 +72,7 @@
// MACROS ------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
extern float S_GetMusicVolume (const char *music);
@ -86,11 +87,26 @@ static FPlayList PlayList;
float relative_volume = 1.f;
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function
static FileReader DefaultOpenMusic(const char* fn)
{
// This is the minimum needed to make the music system functional.
FileReader fr;
fr.OpenFile(fn);
return fr;
}
static MusicCallbacks mus_cb = { nullptr, DefaultOpenMusic };
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// CODE --------------------------------------------------------------------
void S_SetMusicCallbacks(MusicCallbacks* cb)
{
mus_cb = *cb;
if (mus_cb.OpenMusic == nullptr) mus_cb.OpenMusic = DefaultOpenMusic; // without this we are dead in the water.
}
//==========================================================================
//
//
@ -293,33 +309,24 @@ bool S_StartMusic (const char *m_id)
//
// S_ChangeMusic
//
// Starts playing a music, possibly looping.
// initiates playback of a song
//
// [RH] If music is a MOD, starts it at position order. If name is of the
// format ",CD,<track>,[cd id]" song is a CD track, and if [cd id] is
// specified, it will only be played if the specified CD is in a drive.
//==========================================================================
bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force)
{
if (nomusic) return false; // skip the entire procedure if music is globally disabled.
if (!force && PlayList.GetNumSongs())
{ // Don't change if a playlist is active
return false;
}
// allow specifying "*" as a placeholder to play the level's default music.
if (musicname != nullptr && !strcmp(musicname, "*"))
// Do game specific lookup.
FString musicname_;
if (mus_cb.LookupFileName)
{
if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL)
{
musicname = primaryLevel->Music;
order = primaryLevel->musicorder;
}
else
{
musicname = nullptr;
}
musicname_ = mus_cb.LookupFileName(musicname, order);
musicname = musicname_.GetChars();
}
if (musicname == nullptr || musicname[0] == 0)
@ -330,35 +337,10 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
mus_playing.LastSong = "";
return true;
}
if (*musicname == '/') musicname++;
FString DEH_Music;
if (musicname[0] == '$')
{
// handle dehacked replacement.
// Any music name defined this way needs to be prefixed with 'D_' because
// Doom.exe does not contain the prefix so these strings don't either.
const char * mus_string = GStrings[musicname+1];
if (mus_string != nullptr)
{
DEH_Music << "D_" << mus_string;
musicname = DEH_Music;
}
}
FName *aliasp = MusicAliases.CheckKey(musicname);
if (aliasp != nullptr)
{
if (*aliasp == NAME_None)
{
return true; // flagged to be ignored
}
musicname = aliasp->GetChars();
}
if (!mus_playing.name.IsEmpty() &&
mus_playing.handle != nullptr &&
stricmp (mus_playing.name, musicname) == 0 &&
stricmp(mus_playing.name, musicname) == 0 &&
ZMusic_IsLooping(mus_playing.handle) == zmusic_bool(looping))
{
if (order != mus_playing.baseorder)
@ -380,20 +362,10 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
return true;
}
if (strnicmp (musicname, ",CD,", 4) == 0)
{
static bool warned = false;
if (!warned)
Printf(TEXTCOLOR_RED "CD Audio no longer supported\n");
warned = true;
return false;
}
else
{
int lumpnum = -1;
int length = 0;
ZMusic_MusicStream handle = nullptr;
MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname);
MidiDeviceSetting* devp = MidiDevices.CheckKey(musicname);
// Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0)
@ -401,34 +373,12 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
musicname += 7;
}
FileReader reader;
if (!FileExists (musicname))
{
if ((lumpnum = fileSystem.CheckNumForFullName (musicname, true, ns_music)) == -1)
{
Printf ("Music \"%s\" not found\n", musicname);
return false;
}
if (handle == nullptr)
{
if (fileSystem.FileLength (lumpnum) == 0)
{
return false;
}
reader = fileSystem.ReopenFileReader(lumpnum);
}
}
else
{
// Load an external file.
if (!reader.OpenFile(musicname))
{
return false;
}
}
// opening the music must be done by the game because it's different depending on the game's file system use.
FileReader reader = mus_cb.OpenMusic(musicname);
if (!reader.isOpen()) return false;
// shutdown old music
S_StopMusic (true);
S_StopMusic(true);
// Just record it if volume is 0 or music was disabled
if (snd_musicvolume <= 0)
@ -448,13 +398,12 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
else
{
auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper.
mus_playing.handle = ZMusic_OpenSong(mreader, devp? (EMidiDevice)devp->device : MDEV_DEFAULT, devp? devp->args.GetChars() : "");
mus_playing.handle = ZMusic_OpenSong(mreader, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : "");
if (mus_playing.handle == nullptr)
{
Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError());
}
}
}
mus_playing.loop = looping;
mus_playing.name = musicname;
@ -475,6 +424,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
return false;
}
//==========================================================================
//
// S_RestartMusic

View file

@ -7,6 +7,15 @@
#include "name.h"
#include <zmusic.h>
class FileReader;
struct MusicCallbacks
{
FString(*LookupFileName)(const char* fn, int &order);
FileReader(*OpenMusic)(const char* fn);
};
void S_SetMusicCallbacks(MusicCallbacks* cb);
void S_CreateStream();
void S_PauseStream(bool pause);
void S_StopStream();
@ -22,6 +31,8 @@ void S_ResetMusic ();
bool S_StartMusic (const char *music_name);
// Start music using <music_name>, and set whether looping
bool S_SetupMusic(const char* musicname, int order, bool looping, FileReader(*OpenMusic)(const char* filename));
bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false);
void S_RestartMusic ();

View file

@ -97,6 +97,105 @@ public:
void PrintSoundList();
};
//==========================================================================
//
// LookupMusic
//
// resolves aliases and special names
//
//==========================================================================
static FString LookupMusic(const char* musicname, int& order)
{
if (strnicmp(musicname, ",CD,", 4) == 0)
{
static bool warned = false;
if (!warned)
Printf(TEXTCOLOR_RED "CD Audio no longer supported\n");
warned = true;
return "";
}
// allow specifying "*" as a placeholder to play the level's default music.
if (musicname != nullptr && !strcmp(musicname, "*"))
{
if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL)
{
musicname = primaryLevel->Music.GetChars();
order = primaryLevel->musicorder;
}
else
{
musicname = nullptr;
}
}
if (musicname == nullptr || musicname[0] == 0)
{
// got nothing, return nothing.
return "";
}
if (*musicname == '/') musicname++;
FString DEH_Music;
if (musicname[0] == '$')
{
// handle dehacked replacement.
// Any music name defined this way needs to be prefixed with 'D_' because
// Doom.exe does not contain the prefix so these strings don't either.
const char* mus_string = GStrings[musicname + 1];
if (mus_string != nullptr)
{
DEH_Music << "D_" << mus_string;
musicname = DEH_Music;
}
}
FName* aliasp = MusicAliases.CheckKey(musicname);
if (aliasp != nullptr)
{
if (*aliasp == NAME_None)
{
order = -1;
return ""; // flagged to be ignored
}
musicname = aliasp->GetChars();
}
return musicname;
}
//==========================================================================
//
// OpenMusic
//
// opens a FileReader for the music - used as a callback to keep
// implementation details out of the core player.
//
//==========================================================================
static FileReader OpenMusic(const char* musicname)
{
FileReader reader;
if (!FileExists(musicname))
{
int lumpnum;
if ((lumpnum = fileSystem.CheckNumForFullName(musicname, true, ns_music)) == -1)
{
Printf("Music \"%s\" not found\n", musicname);
}
else if (fileSystem.FileLength(lumpnum) != 0)
{
reader = fileSystem.ReopenFileReader(lumpnum);
}
}
else
{
// Load an external file.
reader.OpenFile(musicname);
}
return reader;
}
//==========================================================================
//
// S_Init
@ -107,6 +206,10 @@ public:
void S_Init()
{
// Hook up the music player with the engine specific customizations.
static MusicCallbacks cb = { LookupMusic, OpenMusic };
S_SetMusicCallbacks(&cb);
// Must be up before I_InitSound.
if (!soundEngine)
{
@ -1438,3 +1541,5 @@ ADD_STAT (sound)
{
return GSnd->GatherStats ();
}