- 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 ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
extern float S_GetMusicVolume (const char *music); extern float S_GetMusicVolume (const char *music);
@ -86,11 +87,26 @@ static FPlayList PlayList;
float relative_volume = 1.f; float relative_volume = 1.f;
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function 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 ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
// CODE -------------------------------------------------------------------- // 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 // 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 (nomusic) return false; // skip the entire procedure if music is globally disabled.
if (!force && PlayList.GetNumSongs()) if (!force && PlayList.GetNumSongs())
{ // Don't change if a playlist is active { // Don't change if a playlist is active
return false; return false;
} }
// Do game specific lookup.
// allow specifying "*" as a placeholder to play the level's default music. FString musicname_;
if (musicname != nullptr && !strcmp(musicname, "*")) if (mus_cb.LookupFileName)
{ {
if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) musicname_ = mus_cb.LookupFileName(musicname, order);
{ musicname = musicname_.GetChars();
musicname = primaryLevel->Music;
order = primaryLevel->musicorder;
}
else
{
musicname = nullptr;
}
} }
if (musicname == nullptr || musicname[0] == 0) 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 = ""; mus_playing.LastSong = "";
return true; 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() && if (!mus_playing.name.IsEmpty() &&
mus_playing.handle != nullptr && mus_playing.handle != nullptr &&
stricmp (mus_playing.name, musicname) == 0 && stricmp(mus_playing.name, musicname) == 0 &&
ZMusic_IsLooping(mus_playing.handle) == zmusic_bool(looping)) ZMusic_IsLooping(mus_playing.handle) == zmusic_bool(looping))
{ {
if (order != mus_playing.baseorder) if (order != mus_playing.baseorder)
@ -380,79 +362,46 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
return true; return true;
} }
if (strnicmp (musicname, ",CD,", 4) == 0) int lumpnum = -1;
int length = 0;
ZMusic_MusicStream handle = nullptr;
MidiDeviceSetting* devp = MidiDevices.CheckKey(musicname);
// Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0)
{ {
static bool warned = false; musicname += 7;
if (!warned) }
Printf(TEXTCOLOR_RED "CD Audio no longer supported\n");
warned = true; // opening the music must be done by the game because it's different depending on the game's file system use.
return false; FileReader reader = mus_cb.OpenMusic(musicname);
if (!reader.isOpen()) return false;
// shutdown old music
S_StopMusic(true);
// Just record it if volume is 0 or music was disabled
if (snd_musicvolume <= 0)
{
mus_playing.loop = looping;
mus_playing.name = musicname;
mus_playing.baseorder = order;
mus_playing.LastSong = musicname;
return true;
}
// load & register it
if (handle != nullptr)
{
mus_playing.handle = handle;
} }
else else
{ {
int lumpnum = -1; auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper.
int length = 0; mus_playing.handle = ZMusic_OpenSong(mreader, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : "");
ZMusic_MusicStream handle = nullptr; if (mus_playing.handle == nullptr)
MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname);
// Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0)
{ {
musicname += 7; Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError());
}
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;
}
}
// shutdown old music
S_StopMusic (true);
// Just record it if volume is 0 or music was disabled
if (snd_musicvolume <= 0)
{
mus_playing.loop = looping;
mus_playing.name = musicname;
mus_playing.baseorder = order;
mus_playing.LastSong = musicname;
return true;
}
// load & register it
if (handle != nullptr)
{
mus_playing.handle = handle;
}
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() : "");
if (mus_playing.handle == nullptr)
{
Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError());
}
} }
} }
@ -475,6 +424,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
return false; return false;
} }
//========================================================================== //==========================================================================
// //
// S_RestartMusic // S_RestartMusic

View file

@ -7,6 +7,15 @@
#include "name.h" #include "name.h"
#include <zmusic.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_CreateStream();
void S_PauseStream(bool pause); void S_PauseStream(bool pause);
void S_StopStream(); void S_StopStream();
@ -22,6 +31,8 @@ void S_ResetMusic ();
bool S_StartMusic (const char *music_name); bool S_StartMusic (const char *music_name);
// Start music using <music_name>, and set whether looping // 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); bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false);
void S_RestartMusic (); void S_RestartMusic ();

View file

@ -97,6 +97,105 @@ public:
void PrintSoundList(); 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 // S_Init
@ -107,6 +206,10 @@ public:
void S_Init() 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. // Must be up before I_InitSound.
if (!soundEngine) if (!soundEngine)
{ {
@ -1438,3 +1541,5 @@ ADD_STAT (sound)
{ {
return GSnd->GatherStats (); return GSnd->GatherStats ();
} }