patch #1075: Simplify playlist code. Thanks to Giel for patch review.

The playlist file is no a simple list of files to play during the game.


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5281 4a71c877-e1ca-e34f-864e-861f7616d084
master
Per Inge Mathisen 2008-06-21 15:40:56 +00:00
parent 4f77bdc8e6
commit a1c47bccf8
15 changed files with 137 additions and 351 deletions

View File

@ -1,9 +1,2 @@
[game]
path=music
shuffle=yes
track1.ogg
track2.ogg
[menu]
path=music
menu.ogg

View File

@ -317,7 +317,9 @@ event setupEvent(CALL_GAMEINIT)
setStructureLimits(research,1,0);
// Fire off track one on the CD if it's there...
playIngameCDAudio();
// playIngameCDAudio();
// Actually, let's keep it quiet so that we can hear the tutorial instead - Per
stopCDAudio();
// Cam3daynight has set to cam 3 so reset to cam 1 - GJ
setCampaignNumber(1);

View File

@ -169,59 +169,26 @@ zone 2100 Resurrection Project (http://wiki.wz2100.net/command_line_options).
3.3 Music
---------
A playlist-system is used that can point to any *.ogg in your warzone-data-path.
A playlist-system is used that can point to any *.ogg in your warzone music path.
Warzone reads the following two playlists (in the order they are mentioned) and
the first playlist found will be used:
Warzone reads the playlist from the first location it is found, searching in this
order:
* Warzone-directory in your personal directory:
o for GNU/Linux: ~/.warzone2100/music/music.wpl
o for Windows: ~/My Documents/Warzone 2100/music/music.wpl
o for Mac OS X: ~/Library/Application Support/Warzone 2100/music/music.wpl
o for Mac OS X: ~/Library/Application Support/Warzone 2100/music/music.wpl
* Warzone-install-path:
o <whereverwarzoneisinstalled>/music/music.wpl
If no playlist is present, one is created that plays the original game music.
Using the playlist
******************
The playlist contains two sections, [game] and [menu]. For each section you can
define a list of songs you want to be played in-game. The only supported file-
format is Ogg/Vorbis as long as all necessary libraries are installed.
"shuffle=yes" specifies that you want the songs to played in random order. You
need to set this for each section individually.
"path=." specifies that the following files are found in the folder the playlist
was found. If you do not specify a path all file-names have to be given with
"absolute" path. This "absolute" path is still relative to your warzone-data-
dir. File-names have to match those in the file-system and you can not specify
files outside of the warzone-data-dir.
The playlist is just a list of songs you want to be played in-game, one song per
line. The only supported file format is Ogg Vorbis.
Note: Since we are using PhysFS we recommend you to use only Latin letters in
directory and file-names (more exactly this means: A to Z, a to z, 0 to 9, _-+
and space). You will receive the following error (running with --debug sound) if
"bad" characters are used: Failed opening [[PATH TO FILE]]: Insecure filename.
This example shows how a playlist-file could look like:
--------------------------------------------------------------------------------
[game]
path=.
shuffle=yes
neos_aurore.ogg
neos_chocolat.ogg
neos_down.ogg
neos_esperance.ogg
neos_indy.ogg
[menu]
path=.
neos_symphonie_du_vide.ogg
--------------------------------------------------------------------------------
Music replay may be choppy, so you may want to use an external player for your
music instead.
3.4 Multiplaying via internet
-----------------------------
There are two methods to start a multiplayer-game via internet: using the host's

View File

@ -25,6 +25,7 @@
#include "audio.h"
#include "track.h"
#include "tracklib.h"
#include "cdaudio.h"
#include "mixer.h"
#include "playlist.h"
@ -32,8 +33,8 @@
static const size_t bufferSize = 16 * 1024;
static const unsigned int buffer_count = 32;
static bool music_initialized;
static unsigned int music_track = 0;
static float music_volume = 0.5;
static bool stopping = true;
static AUDIO_STREAM* cdStream = NULL;
@ -47,26 +48,20 @@ BOOL cdAudio_Open(const char* user_musicdir)
return false;
}
debug(LOG_SOUND, "called(%s)", user_musicdir);
music_initialized = true;
stopping = true;
return true;
}
static void cdAudio_CloseTrack(void)
{
cdAudio_Stop();
if (music_track != 0)
{
music_track = 0;
}
}
void cdAudio_Close(void)
{
cdAudio_CloseTrack();
debug(LOG_SOUND, "called");
cdAudio_Stop();
PlayList_Quit();
music_initialized = false;
stopping = true;
}
static void cdAudio_TrackFinished(void*);
@ -78,7 +73,8 @@ static bool cdAudio_OpenTrack(const char* filename)
return false;
}
cdAudio_CloseTrack();
debug(LOG_SOUND, "called(%s)", filename);
cdAudio_Stop();
#ifndef WZ_NOSOUND
if (strncasecmp(filename+strlen(filename)-4, ".ogg", 4) == 0)
@ -87,7 +83,7 @@ static bool cdAudio_OpenTrack(const char* filename)
if (music_file == NULL)
{
debug(LOG_ERROR, "cdAudio_OpenTrack: Failed opening file %s, with error %s", filename, PHYSFS_getLastError());
debug(LOG_ERROR, "Failed opening file %s, with error %s", filename, PHYSFS_getLastError());
return false;
}
@ -99,6 +95,8 @@ static bool cdAudio_OpenTrack(const char* filename)
return false;
}
debug(LOG_SOUND, "successful(%s)", filename);
stopping = false;
return true;
}
#endif
@ -108,75 +106,57 @@ static bool cdAudio_OpenTrack(const char* filename)
static void cdAudio_TrackFinished(void* user_data)
{
const char* filename;
const char *filename = PlayList_NextSong();
// HACK: bail out when a song switch has taken place
if (user_data != PlayList_CurrentSong())
{
return;
}
filename = PlayList_NextSong();
// This pointer is now officially invalidated; so set it to NULL
cdStream = NULL;
if (filename == 0)
if (filename == NULL)
{
music_track = 0;
debug(LOG_ERROR, "Out of playlist?! was playing %s", (char *)user_data);
return;
}
if (cdAudio_OpenTrack(filename))
if (!stopping && cdAudio_OpenTrack(filename))
{
debug(LOG_SOUND, "Now playing %s", filename);
debug(LOG_SOUND, "Now playing %s (was playing %s)", filename, (char *)user_data);
}
}
BOOL cdAudio_PlayTrack(SDWORD iTrack)
BOOL cdAudio_PlayTrack(SONG_CONTEXT context)
{
cdAudio_CloseTrack();
PlayList_SetTrack(iTrack);
debug(LOG_SOUND, "called(%d)", (int)context);
if (context == SONG_FRONTEND)
{
const char* filename = PlayList_CurrentSong();
for (;;)
{
if (filename == NULL)
{
music_track = 0;
return false;
}
if (cdAudio_OpenTrack(filename))
{
music_track = iTrack;
break;
}
else
{
return false; // break out to avoid infinite loops
}
filename = PlayList_NextSong();
}
return cdAudio_OpenTrack("music/menu.ogg");
}
else if (context == SONG_INGAME)
{
const char *filename = PlayList_CurrentSong();
return true;
return cdAudio_OpenTrack(filename);
}
ASSERT(false, "Bad parameter value");
return false;
}
void cdAudio_Stop()
{
stopping = true;
debug(LOG_SOUND, "called, cdStream=%p", cdStream);
if (cdStream)
{
sound_StopStream(cdStream);
cdStream = NULL;
sound_Update();
}
}
void cdAudio_Pause()
{
debug(LOG_SOUND, "called");
if (cdStream)
{
sound_PauseStream(cdStream);
@ -185,6 +165,7 @@ void cdAudio_Pause()
void cdAudio_Resume()
{
debug(LOG_SOUND, "called");
if (cdStream)
{
sound_ResumeStream(cdStream);

View File

@ -26,19 +26,15 @@ extern "C"
{
#endif
enum
typedef enum
{
playlist_custom,
playlist_ingame,
playlist_frontend,
// Must be the last
playlist_last,
};
SONG_FRONTEND,
SONG_INGAME,
} SONG_CONTEXT;
BOOL cdAudio_Open(const char* user_musicdir);
void cdAudio_Close(void);
BOOL cdAudio_PlayTrack( SDWORD iTrack );
BOOL cdAudio_PlayTrack(SONG_CONTEXT context);
void cdAudio_Stop(void);
void cdAudio_Pause(void);
void cdAudio_Resume(void);

View File

@ -25,63 +25,51 @@
#define BUFFER_SIZE 2048
typedef struct {
char** songs;
unsigned int nb_songs;
unsigned int list_size;
bool shuffle;
typedef struct _wzTrack
{
char path[PATH_MAX];
struct _wzTrack *next;
} WZ_TRACK;
static unsigned int current_track = 0;
static unsigned int current_song = 0;
static WZ_TRACK playlist[playlist_last];
static WZ_TRACK *currentSong = NULL;
static int numSongs = 0;
static WZ_TRACK *songList = NULL;
void PlayList_Init()
{
unsigned int i;
for (i = 0; i < playlist_last; ++i)
{
playlist[i].songs = NULL;
playlist[i].list_size = 0;
playlist[i].nb_songs = 0;
}
songList = NULL;
currentSong = NULL;
numSongs = 0;
}
void PlayList_Quit()
{
unsigned int i, j;
WZ_TRACK *list = songList;
for(i = 0; i < playlist_last; ++i)
while (list)
{
for (j = 0; j < playlist[i].list_size; ++j )
{
free(playlist[i].songs[j]);
}
WZ_TRACK *next = list->next;
free(playlist[i].songs);
playlist[i].songs = NULL;
playlist[i].list_size = 0;
playlist[i].nb_songs = 0;
free(list);
list = next;
}
PlayList_Init();
}
bool PlayList_Read(const char* path)
{
PHYSFS_file* fileHandle;
char* path_to_music = NULL;
char fileName[PATH_MAX];
char listName[PATH_MAX];
// Construct file name
snprintf(fileName, sizeof(fileName), "%s/music.wpl", path);
ssprintf(listName, "%s/music.wpl", path);
// Attempt to open the playlist file
fileHandle = PHYSFS_openRead(fileName);
fileHandle = PHYSFS_openRead(listName);
if (fileHandle == NULL)
{
debug(LOG_NEVER, "sound_LoadTrackFromFile: PHYSFS_openRead(\"%s\") failed with error: %s\n", fileName, PHYSFS_getLastError());
debug(LOG_ERROR, "PHYSFS_openRead(\"%s\") failed with error: %s\n", listName, PHYSFS_getLastError());
return false;
}
@ -103,187 +91,79 @@ bool PlayList_Read(const char* path)
line_buf[buf_pos] = '\0';
buf_pos = 0;
if (strncmp(line_buf, "[game]", 6) == 0)
if (line_buf[0] != '\0'
&& (filename = strtok(line_buf, "\n")) != NULL
&& strlen(filename) != 0)
{
current_track = 1;
free(path_to_music);
path_to_music = NULL;
playlist[current_track].shuffle = false;
}
else if (strncmp(line_buf, "[menu]", 6) == 0)
{
current_track = 2;
free(path_to_music);
path_to_music = NULL;
playlist[current_track].shuffle = false;
}
else if (strncmp(line_buf, "path=", 5) == 0)
{
free(path_to_music);
path_to_music = strtok(line_buf+5, "\n");
if (strcmp(path_to_music, ".") == 0)
WZ_TRACK *song = malloc(sizeof(*songList));
WZ_TRACK *last = songList;
sstrcpy(song->path, path);
sstrcat(song->path, PHYSFS_getDirSeparator());
sstrcat(song->path, filename);
song->next = NULL;
// find last
for (; last && last->next; last = last->next);
if (last)
{
path_to_music = strdup(path);
last->next = song; // add last in list
}
else
{
path_to_music = strdup(path_to_music);
}
debug(LOG_SOUND, "playlist: path = %s", path_to_music );
}
else if (strncmp(line_buf, "shuffle=", 8) == 0)
{
if (strcmp(strtok(line_buf+8, "\n"), "yes") == 0)
{
playlist[current_track].shuffle = true;
}
debug( LOG_SOUND, "playlist: shuffle = yes" );
}
else if (line_buf[0] != '\0'
&& (filename = strtok(line_buf, "\n")) != NULL
&& strlen(filename) != 0)
{
char* filepath;
if (path_to_music == NULL)
{
filepath = strdup(filename);
if (filename == NULL)
{
debug(LOG_ERROR, "PlayList_Read: Out of memory!");
PHYSFS_close(fileHandle);
abort();
return false;
}
}
else
{
// Determine the length of the string we're about to construct
size_t path_length = strlen(path_to_music) + 1 + strlen(filename) + 2;
// Allocate memory for our string
filepath = (char*)malloc(path_length);
if (filepath == NULL)
{
debug(LOG_ERROR, "PlayList_Read: Out of memory!");
free(path_to_music);
PHYSFS_close(fileHandle);
abort();
return false;
}
snprintf(filepath, path_length, "%s/%s", path_to_music, filename);
}
debug(LOG_SOUND, "playlist: adding song %s", filepath );
if (playlist[current_track].nb_songs == playlist[current_track].list_size)
{
char** songs;
unsigned int new_list_size = playlist[current_track].list_size * 2;
unsigned int i;
// Make sure that we always allocate _some_ memory.
if (new_list_size == 0)
{
new_list_size = 1;
}
songs = (char**)realloc(playlist[current_track].songs,
new_list_size * sizeof(char*));
if (songs == NULL)
{
debug(LOG_ERROR, "PlayList_Read: Out of memory!");
free(path_to_music);
PHYSFS_close(fileHandle);
abort();
return false;
}
// Initialize the new set of pointers to NULL. Since they don't point to
// allocated memory yet.
for (i = playlist[current_track].list_size; i < new_list_size; ++i)
{
songs[i] = NULL;
}
playlist[current_track].songs = songs;
playlist[current_track].list_size = new_list_size;
songList = song; // create list
}
playlist[current_track].songs[playlist[current_track].nb_songs++] = filepath;
numSongs++;
debug(LOG_SOUND, "Added song %s to playlist", filename);
}
}
free(path_to_music);
PHYSFS_close(fileHandle);
currentSong = songList;
return true;
}
static void swap_charp(char** a, char** b)
const char* PlayList_CurrentSong()
{
char* tmp = *a;
*a = *b;
*b = tmp;
}
static void PlayList_Shuffle(void)
{
if (playlist[current_track].shuffle)
if (currentSong)
{
unsigned int i;
for (i = playlist[current_track].nb_songs-1; i > 0; --i)
{
unsigned int j = rand() % (i + 1);
swap_charp(&playlist[current_track].songs[i], &playlist[current_track].songs[j]);
}
}
}
void PlayList_SetTrack(unsigned int t)
{
if (t < playlist_last)
{
current_track = t;
return currentSong->path;
}
else
{
current_track = 0;
return NULL;
}
PlayList_Shuffle();
current_song = 0;
}
const char* PlayList_CurrentSong()
{
if (current_song < playlist[current_track].nb_songs)
{
return playlist[current_track].songs[current_song];
}
return NULL;
}
const char* PlayList_NextSong()
{
// If we're at the end of the playlist
if (++current_song >= playlist[current_track].nb_songs)
if (currentSong)
{
// Shuffle the playlist (again)
PlayList_Shuffle();
// Jump to the start of the playlist
current_song = 0;
currentSong = currentSong->next;
}
if (playlist[current_track].nb_songs == 0)
if (!currentSong)
{
return NULL;
currentSong = songList;
}
return PlayList_CurrentSong();
}
void playListTest()
{
int i;
for (i = 0; i < 10; i++)
{
PlayList_Quit();
PlayList_Init();
PlayList_Read("music");
if (numSongs != 2)
{
debug(LOG_ERROR, "Use the default playlist for selftest!");
}
assert(songList);
assert(numSongs == 2);
}
return playlist[current_track].songs[current_song];
}

View File

@ -34,6 +34,7 @@ bool PlayList_Read(const char* path);
void PlayList_SetTrack(unsigned int t);
const char* PlayList_CurrentSong(void);
const char* PlayList_NextSong(void);
void playListTest(void);
#if defined(__cplusplus)
}

View File

@ -180,7 +180,7 @@ void sound_CheckAllUnloaded( void )
for (currTrack = &g_apTrack[0]; currTrack != &g_apTrack[MAX_TRACKS]; ++currTrack)
{
ASSERT(*currTrack == NULL, "sound_CheckAllUnloaded: a track is not unloaded yet (%s); check audio.cfg for duplicate IDs", (*currTrack)->fileName);
ASSERT(*currTrack == NULL, "A track is not unloaded yet (%s); check audio.cfg for duplicate IDs", (*currTrack)->fileName);
}
}
@ -212,13 +212,13 @@ BOOL sound_CheckTrack( SDWORD iTrack )
{
if ( iTrack < 0 || iTrack > g_iCurTracks - 1 )
{
debug( LOG_SOUND, "sound_CheckTrack: track number %i outside max %i\n", iTrack, g_iCurTracks );
debug(LOG_SOUND, "Track number %i outside max %i\n", iTrack, g_iCurTracks);
return false;
}
if ( g_apTrack[iTrack] == NULL )
{
debug( LOG_SOUND, "sound_CheckTrack: track %i NULL\n", iTrack );
debug(LOG_SOUND, "Track %i NULL\n", iTrack);
return false;
}
@ -317,7 +317,7 @@ BOOL sound_Play3DTrack( AUDIO_SAMPLE *psSample )
//
void sound_StopTrack( AUDIO_SAMPLE *psSample )
{
ASSERT( psSample != NULL, "sound_StopTrack: sample pointer invalid\n" );
ASSERT(psSample != NULL, "Sample pointer invalid");
#ifndef WZ_NOSOUND
sound_StopSample(psSample);

View File

@ -129,10 +129,6 @@ BOOL loadConfig(void)
sound_SetMusicVolume((float)val / 100.0);
}
if (getWarzoneKeyNumeric("playaudiocds", &val)) {
war_SetPlayAudioCDs(val);
}
if (getWarzoneKeyNumeric("debugmode", &val))
{
bAllowDebugMode = val;
@ -613,7 +609,6 @@ BOOL saveConfig(void)
setWarzoneKeyNumeric("voicevol", (int)(sound_GetUIVolume() * 100.0));
setWarzoneKeyNumeric("fxvol", (int)(sound_GetEffectsVolume() * 100.0));
setWarzoneKeyNumeric("cdvol", (int)(sound_GetMusicVolume() * 100.0));
setWarzoneKeyNumeric("playaudiocds", war_GetPlayAudioCDs());
setWarzoneKeyNumeric("width", war_GetWidth());
setWarzoneKeyNumeric("height", war_GetHeight());

View File

@ -416,9 +416,7 @@ BOOL systemInitialise(void)
debug( LOG_SOUND, "Sound disabled!" );
}
if (war_GetPlayAudioCDs()) {
cdAudio_Open(UserMusicPath);
}
cdAudio_Open(UserMusicPath);
if (!dataInitLoadFuncs()) // Pass all the data loading functions to the framework library
{
@ -466,11 +464,9 @@ void systemShutdown(void)
debug(LOG_MAIN, "shutting down audio subsystems");
if (war_GetPlayAudioCDs()) {
debug(LOG_MAIN, "shutting down CD audio");
cdAudio_Stop();
cdAudio_Close();
}
debug(LOG_MAIN, "shutting down CD audio");
cdAudio_Stop();
cdAudio_Close();
if ( audio_Disabled() == false && !audio_Shutdown() )
{
@ -610,10 +606,7 @@ BOOL frontendInitialise(const char *ResourceFile)
gameTimeInit();
// hit me with some funky beats....
if (war_GetPlayAudioCDs())
{
cdAudio_PlayTrack(playlist_frontend); // frontend music
}
cdAudio_PlayTrack(SONG_FRONTEND);
return true;
}
@ -952,9 +945,7 @@ BOOL stageTwoShutDown(void)
{
debug(LOG_WZ, "== stageTwoShutDown ==");
if (war_GetPlayAudioCDs()) {
cdAudio_Stop();
}
cdAudio_Stop();
freeAllStructs();
freeAllDroids();
@ -1175,9 +1166,7 @@ BOOL saveGameReset(void)
{
debug(LOG_MAIN, "saveGameReset");
if (war_GetPlayAudioCDs()) {
cdAudio_Stop();
}
cdAudio_Stop();
freeAllStructs();
freeAllDroids();

View File

@ -41,6 +41,7 @@
#include "lib/framework/tagfile.h"
#include "lib/exceptionhandler/exceptionhandler.h"
#include "lib/sound/playlist.h"
#include "lib/gamelib/gtime.h"
#include "lib/ivis_common/piestate.h"
#include "lib/ivis_common/rendmode.h"
@ -937,6 +938,7 @@ int main(int argc, char *argv[])
{
memset(enabled_debug, 0, sizeof(*enabled_debug) * LOG_LAST);
fprintf(stdout, "Carrying out self-test:\n");
playListTest();
NETtest();
tagTest();
parseTest();

View File

@ -2695,7 +2695,7 @@ static BOOL _intAddMissionResult(BOOL result, BOOL bPlaySuccess)
memset(&sFormInit, 0, sizeof(W_FORMINIT));
// add some funky beats
cdAudio_PlayTrack(playlist_frontend); // frontend music.
cdAudio_PlayTrack(SONG_FRONTEND);
pie_LoadBackDrop(SCREEN_MISSIONEND);

View File

@ -3403,10 +3403,8 @@ BOOL scrPlayBackgroundAudio(void)
BOOL scrPlayIngameCDAudio(void)
{
if (war_GetPlayAudioCDs())
{
cdAudio_PlayTrack(playlist_ingame);
}
debug(LOG_SOUND, "Script wanted music to start");
cdAudio_PlayTrack(SONG_INGAME);
return true;
}
@ -3414,28 +3412,22 @@ BOOL scrPlayIngameCDAudio(void)
// -----------------------------------------------------------------------------------------
BOOL scrStopCDAudio(void)
{
if (war_GetPlayAudioCDs()) {
cdAudio_Stop();
}
debug(LOG_SOUND, "Script wanted music to stop");
cdAudio_Stop();
return true;
}
// -----------------------------------------------------------------------------------------
BOOL scrPauseCDAudio(void)
{
if (war_GetPlayAudioCDs()) {
cdAudio_Pause();
}
cdAudio_Pause();
return true;
}
// -----------------------------------------------------------------------------------------
BOOL scrResumeCDAudio(void)
{
if (war_GetPlayAudioCDs()) {
cdAudio_Resume();
}
cdAudio_Resume();
return true;
}

View File

@ -47,7 +47,6 @@ typedef struct _warzoneGlobals
BOOL bFog;
SWORD effectsLevel;
BOOL allowSubtitles;
BOOL playAudioCDs;
BOOL Fullscreen;
BOOL soundEnabled;
BOOL trapCursor;
@ -80,20 +79,11 @@ void war_SetDefaultStates(void)//Sets all states
{
//set those here and reset in clParse or loadConfig
war_SetFog(false);
war_SetPlayAudioCDs(true);
war_setSoundEnabled( true );
war_SetPauseOnFocusLoss(true);
war_SetColouredCursor(false);
}
void war_SetPlayAudioCDs(BOOL b) {
warGlobs.playAudioCDs = b;
}
BOOL war_GetPlayAudioCDs(void) {
return warGlobs.playAudioCDs;
}
void war_SetAllowSubtitles(BOOL b) {
warGlobs.allowSubtitles = b;
}

View File

@ -49,8 +49,6 @@ extern void war_SetFog(BOOL val);
extern BOOL war_GetFog(void);
extern void war_SetSeqMode(SEQ_MODE mode);
extern SEQ_MODE war_GetSeqMode(void);
extern void war_SetPlayAudioCDs(BOOL b);
extern BOOL war_GetPlayAudioCDs(void);
extern void war_SetAllowSubtitles(BOOL);
extern BOOL war_GetAllowSubtitles(void);
extern void war_setFullscreen(BOOL);