changeset 87:94497283affa

Various fixes and improvements
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 05 Oct 2003 10:38:03 +0000
parents 9533b78f1a7d
children 0cf08d137248
files src/xmms-sid.c src/xmms-sid.h src/xs_config.c src/xs_length.c src/xs_length.h src/xs_sidplay.h src/xs_sidplay1.cc src/xs_sidplay1.h src/xs_sidplay2.cc src/xs_sidplay2.h src/xs_support.c src/xs_support.h
diffstat 12 files changed, 310 insertions(+), 261 deletions(-) [+]
line wrap: on
line diff
--- a/src/xmms-sid.c	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xmms-sid.c	Sun Oct 05 10:38:03 2003 +0000
@@ -44,8 +44,14 @@
 #ifdef HAVE_SIDPLAY2
 #include "xs_sidplay2.h"
 #endif
+#ifdef HAVE_NANOSID
+#include "xs_nanosid.h"
+#endif
 
 
+/*
+ * Structure defining methods/functions of each player
+ */
 typedef struct {
 	gint		plrIdent;
 	gboolean	(*plrIsOurFile)(gchar *);
@@ -54,20 +60,22 @@
 	gboolean	(*plrInitSong)(t_xs_status *);
 	gboolean	(*plrFillBuffer)(t_xs_status *, gchar *, gint);
 	gboolean	(*plrLoadSID)(t_xs_status *, gchar *);
-	gint		(*plrGetTuneSpeed)(t_xs_status *);
 	void		(*plrDeleteSID)(t_xs_status *);
-	void		(*plrGetSIDInfo)(gchar *, gchar **, gint *);
+	t_xs_tune*	(*plrGetSIDInfo)(gchar *);
 } t_xs_player;
 
 
+/*
+ * List of players and links to their functions
+ */
 t_xs_player xs_playerlist[] = {
 #ifdef HAVE_SIDPLAY1
 	{ XS_ENG_SIDPLAY1,
 		xs_sidplay1_isourfile,
 		xs_sidplay1_init, xs_sidplay1_close,
 		xs_sidplay1_initsong, xs_sidplay1_fillbuffer,
-		xs_sidplay1_loadsid, xs_sidplay1_gettunespeed,
-		xs_sidplay1_deletesid, xs_sidplay1_getsidinfo
+		xs_sidplay1_loadsid, xs_sidplay1_deletesid,
+		xs_sidplay1_getsidinfo
 	},
 #endif
 #ifdef HAVE_SIDPLAY2
@@ -75,8 +83,8 @@
 		xs_sidplay2_isourfile,
 		xs_sidplay2_init, xs_sidplay2_close,
 		xs_sidplay2_initsong, xs_sidplay2_fillbuffer,
-		xs_sidplay2_loadsid, xs_sidplay2_gettunespeed,
-		xs_sidplay2_deletesid, xs_sidplay2_getsidinfo
+		xs_sidplay2_loadsid, xs_sidplay2_deletesid,
+		xs_sidplay2_getsidinfo
 	},
 #endif
 #ifdef HAVE_NANOSID
@@ -84,8 +92,8 @@
 		xs_nanosid_isourfile,
 		xs_nanosid_init, xs_nanosid_close,
 		xs_nanosid_initsong, xs_nanosid_fillbuffer,
-		xs_nanosid_loadsid, xs_nanosid_gettunespeed,
-		xs_nanosid_deletesid, xs_nanosid_getsidinfo
+		xs_nanosid_loadsid, xs_nanosid_deletesid,
+		xs_nanosid_getsidinfo
 	},
 #endif
 };
@@ -120,10 +128,9 @@
 
  /* Initialize status */
  memset(&xs_status, 0, sizeof(xs_status));
- xs_status.allowNext = TRUE;
 
  /* Try to initialize emulator engine */
- XSDEBUG("initializing emulator engine...\n");
+ XSDEBUG("initializing emulator engine #%i...\n", xs_cfg.playerEngine);
 
  iPlayer = 0;
  isInitialized = FALSE;
@@ -137,9 +144,10 @@
  			xs_player = (t_xs_player *) &xs_playerlist[iPlayer];
  			}
  		}
- 	iPlayer++;
+	iPlayer++;
  	}
 
+ XSDEBUG("init#1: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer);
 
  iPlayer = 0;
  while ((iPlayer < xs_nplayerlist) && !isInitialized)
@@ -148,10 +156,11 @@
 		{
 		isInitialized = TRUE;
 		xs_player = (t_xs_player *) &xs_playerlist[iPlayer];
- 		}
-	iPlayer++;
+ 		} else
+ 		iPlayer++;
  	}
  
+ XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer);
 
  /* Read song-length database */
  if (xs_cfg.songlenDBEnable && (xs_songlen_init() < 0))
@@ -174,9 +183,12 @@
 {
  XSDEBUG("xs_close(): shutting down...\n");
 
- /* Stop playing */
+ /* Stop playing, free structures */
  xs_stop();
 
+ xs_tune_free(xs_status.pTune);
+ xs_status.pTune = NULL;
+ 
  xs_player->plrDeleteSID(&xs_status);
  xs_player->plrClose(&xs_status);
 
@@ -184,6 +196,7 @@
  xs_songlen_close();
 
 // FIXME FIXME: STIL-entries
+
  XSDEBUG("shutdown finished.\n");
 }
 
@@ -191,21 +204,21 @@
 /*
  * Check whether the given file is handled by this plugin
  */
-gint xs_is_our_file(gchar *pcFileName)
+gint xs_is_our_file(gchar *pcFilename)
 {
  char *pcExt;
  assert(xs_player);
 
  /* Check the filename */
- if (pcFileName == NULL)
+ if (pcFilename == NULL)
 	return FALSE;
 
  /* Try to detect via detection routine, if required */
- if (xs_cfg.detectMagic && xs_player->plrIsOurFile(pcFileName))
+ if (xs_cfg.detectMagic && xs_player->plrIsOurFile(pcFilename))
  	return TRUE;
 
  /* Detect just by checking filename extension */
- pcExt = strrchr(pcFileName, '.');
+ pcExt = strrchr(pcFilename, '.');
  if (pcExt)
 	{
 	pcExt++;
@@ -235,15 +248,16 @@
 void *xs_play_loop(void *argPointer)
 {
  t_xs_status myStatus;
+ t_xs_tune *myTune;
  gboolean audioOpen, doPlay;
- gint audioFreq, audioChannels, songLength, audioFmt;
+ gint mySong, audioFreq, audioChannels, songLength, audioFmt;
  gchar audioBuffer[XS_BUFSIZE];
 
  /* Initialize */
  pthread_mutex_lock(&xs_mutex);
  XSDEBUG("entering play thread\n");
- xs_status.isPlaying = TRUE;
  memcpy(&myStatus, &xs_status, sizeof(t_xs_status));
+ myTune = xs_status.pTune;
  pthread_mutex_unlock(&xs_mutex);
 
  /* Copy and check audio options here (they might change in config while running) */
@@ -263,30 +277,27 @@
  while (xs_status.isPlaying && doPlay)
  {
  pthread_mutex_lock(&xs_mutex);
- myStatus.currSong = xs_status.currSong;
- myStatus.isPlaying = TRUE;
- xs_status.allowNext = TRUE;
+ mySong = xs_status.currSong;
+ songLength = myTune->subTunes[mySong - 1].tuneLength;
  pthread_mutex_unlock(&xs_mutex);
 
- XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong);
+ XSDEBUG("subtune #%i selected, initializing...\n", mySong);
 
 
  /* Initialize song */
  if (!xs_player->plrInitSong(&myStatus))
 	{
 	XSERR("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n",
-		myStatus.currFileName, myStatus.currSong);
+		myTune->tuneFilename, mySong);
 	goto err_exit;
 	}
 
 
  /* Get song information for current subtune */
- songLength = xs_songlen_get(myStatus.currFileName, myStatus.currSong);
-
  xs_plugin_ip.set_info(
- 	myStatus.currFileName,
+ 	myTune->subTunes[mySong - 1].tuneTitle,
  	(songLength > 0) ? (songLength * 1000) : -1,
- 	1000 * xs_player->plrGetTuneSpeed(&xs_status),
+ 	(myTune->subTunes[mySong - 1].tuneSpeed > 0) ? (myTune->subTunes[mySong - 1].tuneSpeed * 1000) : -1,
 	audioFreq,
 	audioChannels);
 
@@ -306,7 +317,7 @@
  /*
   * Play the subtune
   */
- while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong))
+ while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == mySong))
 	{
 	/* Render audio data */
 	xs_player->plrFillBuffer(&myStatus, audioBuffer, XS_BUFSIZE);
@@ -318,12 +329,12 @@
 
 	/* Wait a little */
 	while (xs_status.isPlaying &&
-		(xs_status.currSong == myStatus.currSong) &&
+		(xs_status.currSong == mySong) &&
 		(xs_plugin_ip.output->buffer_free() < XS_BUFSIZE))
 		xmms_usleep(10000);
 
 	/* Output audio */
-	if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong))
+	if (xs_status.isPlaying && (xs_status.currSong == mySong))
 		xs_plugin_ip.output->write_audio(audioBuffer, XS_BUFSIZE);
 
 	/* Check if we have played enough */
@@ -373,16 +384,7 @@
  XSDEBUG("exiting thread, bye.\n");
 
  pthread_mutex_lock(&xs_mutex);
- xs_player->plrDeleteSID(&myStatus);
-
- if (xs_status.currFileName)
- 	{
-	g_free(xs_status.currFileName);
-	xs_status.currFileName = NULL;
-	}
-                                 
  xs_status.isPlaying = FALSE;
- xs_status.allowNext = TRUE;
  pthread_mutex_unlock(&xs_mutex);
  pthread_exit(NULL);
 }
@@ -391,30 +393,37 @@
 /*
  * Start playing the given file
  */
-void xs_play_file(gchar *pcFileName)
+void xs_play_file(gchar *pcFilename)
 {
- while (!xs_status.allowNext) usleep(5000);
+ XSDEBUG("play '%s'\n", pcFilename);
  
- pthread_mutex_lock(&xs_mutex);
- xs_status.allowNext = FALSE;
- pthread_mutex_unlock(&xs_mutex);
-
- fprintf(stderr, "\n\n");
- XSDEBUG("play '%s'\n", pcFileName);
- 
- /* Initialize the tune */
- if (!xs_player->plrLoadSID(&xs_status, pcFileName))
+ /* Get tune information */
+ if ((xs_status.pTune = xs_player->plrGetSIDInfo(pcFilename)) == NULL)
  	return;
 
+ XSDEBUG("tuneinfo %p\n", xs_status.pTune);
+
+ /* Initialize the tune */
+ if (!xs_player->plrLoadSID(&xs_status, pcFilename))
+ 	{
+ 	xs_tune_free(xs_status.pTune);
+ 	xs_status.pTune = NULL;
+ 	return;
+ 	}
+
+ XSDEBUG("load ok\n");
+ 
  /* Set general status information */
- xs_status.isPlaying	= FALSE;
+ xs_status.isPlaying	= TRUE;
  xs_status.isError	= FALSE;
- xs_status.currFileName	= g_strdup(pcFileName);
+ xs_status.currSong	= xs_status.pTune->startTune;
 
  /* Start the playing thread! */
  if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, NULL) < 0)
 	{
 	XSERR("Couldn't start playing thread! Possible reason reported by system: %s\n", strerror(errno));
+ 	xs_tune_free(xs_status.pTune);
+	xs_status.pTune = NULL;
 	xs_player->plrDeleteSID(&xs_status);
 	}
 
@@ -427,11 +436,10 @@
  */
 void xs_stop(void)
 {
- /* If playing, stop. */
  XSDEBUG("STOP_REQ\n");
-
  if (xs_status.isPlaying)
 	{
+	/* Stop playing */
 	XSDEBUG("stopping...\n");
 	pthread_mutex_lock(&xs_mutex);
 	xs_status.isPlaying = FALSE;
@@ -439,11 +447,15 @@
 	pthread_join(xs_decode_thread, NULL);
 	}
 
+ /* Free tune information */
+ xs_player->plrDeleteSID(&xs_status);
+ xs_tune_free(xs_status.pTune);
+ xs_status.pTune = NULL;
 }
 
 
 /*
- * Pause the playing
+ * Pause/unpause the playing
  */
 void xs_pause(short pauseState)
 {
@@ -457,10 +469,12 @@
  */
 void xs_seek(gint iTime)
 {
+ if (!xs_status.pTune) return;
+
  if (xs_cfg.subsongControl == XS_SSC_POPUP)
- {
- /* User wants to use the pop-up */
- }
+	{
+	/* User wants to use the pop-up */
+	}
 
  /* If we have song-position patch, check settings */
 #ifdef HAVE_SONG_POSITION
@@ -468,9 +482,9 @@
  	{
 	pthread_mutex_lock(&xs_mutex);
 
-	if ((iTime > 0) && (iTime <= xs_status.nSongs) && xs_status.isPlaying)
+	if ((iTime > 0) && (iTime <= xs_status.pTune->nsubTunes) && xs_status.isPlaying)
 		xs_status.currSong = iTime;
-
+	
 	pthread_mutex_unlock(&xs_mutex);
 	}
 #endif
@@ -486,6 +500,10 @@
  if (xs_status.isError)
 	return -2;
 
+ /* If there is no tune, return -1 */
+ if (!xs_status.pTune)
+ 	return -1;
+ 
  /* If tune has ended, return -1 */
  if (!xs_status.isPlaying)
 	return -1;
@@ -495,7 +513,7 @@
  if (xs_cfg.subsongControl == XS_SSC_PATCH)
  	{
 	pthread_mutex_lock(&xs_mutex);
-	set_song_position(xs_status.currSong, 1, xs_status.nSongs);
+	set_song_position(xs_status.currSong, 1, xs_status.pTune->nsubTunes);
 	pthread_mutex_unlock(&xs_mutex);
 	}
 #endif
@@ -508,7 +526,77 @@
 /*
  * Return song information
  */
-void xs_get_song_info(gchar *songFileName, gchar **songTitle, gint *songLength)
+void xs_get_song_info(gchar *songFilename, gchar **songTitle, gint *songLength)
+{
+ t_xs_tune *pInfo;
+ gint tmpInt;
+ 
+ pInfo = xs_player->plrGetSIDInfo(songFilename);
+ if (!pInfo) return;
+
+ if ((pInfo->startTune >= 0) && (pInfo->startTune <= pInfo->nsubTunes))
+ 	{
+	(*songTitle) = g_strdup(pInfo->subTunes[pInfo->startTune - 1].tuneTitle);
+
+	tmpInt = pInfo->subTunes[pInfo->startTune - 1].tuneLength;
+	if (tmpInt < 0)
+		(*songLength) = -1;
+		else
+		(*songLength) = (tmpInt * 1000);
+	}
+	
+ xs_tune_free(pInfo);
+}
+
+
+/*
+ * Allocate a new tune structure
+ */
+t_xs_tune *xs_tune_new(gchar *pcFilename, gint nsubTunes, gint startTune)
 {
- xs_player->plrGetSIDInfo(songFileName, songTitle, songLength);
+ t_xs_tune *pResult;
+ 
+ pResult = (t_xs_tune *) g_malloc0(sizeof(t_xs_tune));
+ if (!pResult) return NULL;
+ 
+ pResult->tuneFilename = g_strdup(pcFilename);
+ if (!pResult->tuneFilename)
+ 	{
+ 	g_free(pResult);
+ 	return NULL;
+ 	}
+ 
+ pResult->nsubTunes = nsubTunes;
+ pResult->startTune = startTune;
+ 
+ return pResult;
 }
+
+
+/*
+ * Free tune information
+ */
+void xs_tune_free(t_xs_tune *pTune)
+{
+ gint i;
+ if (!pTune) return;
+
+ if (pTune->tuneFilename)
+ 	{
+ 	g_free(pTune->tuneFilename);
+ 	pTune->tuneFilename = NULL;
+ 	}
+ 
+ for (i = 0; i < pTune->nsubTunes; i++)
+ 	{
+ 	if (pTune->subTunes[i].tuneTitle)
+ 		{
+ 		g_free(pTune->subTunes[i].tuneTitle);
+ 		pTune->subTunes[i].tuneTitle = NULL;
+ 		}
+ 	}
+ 
+ g_free(pTune);
+}
+
+
--- a/src/xmms-sid.h	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xmms-sid.h	Sun Oct 05 10:38:03 2003 +0000
@@ -35,7 +35,7 @@
 /*
  * Some defines
  */
-#define DEBUG			/* ... */
+/*#define DEBUG	 */
 #undef HAVE_HARDSID_BUILDER	/* HardSID-support is not working and is untested */
 
 /*
@@ -57,18 +57,25 @@
 typedef struct {
 	gint		tuneSpeed;
 	gint		tuneLength;
-	gchar		*titleStr;
-} t_xs_tuneinfo;
+	gchar		*tuneTitle;
+} t_xs_subtune;
+
+
+typedef struct {
+	gchar		*tuneFilename;
+	gint		nsubTunes, startTune;
+	t_xs_subtune	subTunes[XS_STIL_MAXENTRY];
+} t_xs_tune;
 
 
 typedef struct {
 	void		*player;
-	gboolean	isError, isPlaying, allowNext;
-	gint		currSong, nSongs, startSong;
-	gchar		*currFileName;
-	t_xs_tuneinfo	subTunes[XS_STIL_MAXENTRY];
+	gboolean	isError, isPlaying;
+	gint		currSong;
+	t_xs_tune	*pTune;
 } t_xs_status;
 
+
 extern t_xs_status xs_status;
 
 
@@ -87,6 +94,9 @@
 //void	xs_file_info_box(gchar *);
 void	xs_about(void);
 
+t_xs_tune *xs_tune_new(gchar *, gint, gint);
+void	xs_tune_free(t_xs_tune *);
+
 
 /*
  * Debugging and error handling macros
--- a/src/xs_config.c	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_config.c	Sun Oct 05 10:38:03 2003 +0000
@@ -106,8 +106,9 @@
 { WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_clock_pal",	&xs_cfg.clockSpeed,		XS_CLOCK_PAL },
 { WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_clock_force",	&xs_cfg.forceSpeed,		0 },
 { WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_sidplay2_opt",	&xs_cfg.sid2OptLevel,		0 },
-{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_sidplay2_resid",&xs_cfg.sid2Builder,		XS_BLD_RESID },
-{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_sidplay2_hardsid",&xs_cfg.sid2Builder,		XS_BLD_HARDSID },
+
+{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_sidplay2_resid",&xs_cfg.sid2Builder,		XS_BLD_RESID },
+{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_sidplay2_hardsid",&xs_cfg.sid2Builder,		XS_BLD_HARDSID },
 
 { WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_filters",	&xs_cfg.emulateFilters,		0 },
 { WTYPE_SCALE,	CTYPE_FLOAT,	"cfg_emu_filt_fs",	&xs_cfg.filterFs,		0 },
--- a/src/xs_length.c	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_length.c	Sun Oct 05 10:38:03 2003 +0000
@@ -198,7 +198,7 @@
 	iResult = -1;
 
  /* Ignore and skip the possible attributes */
- while (!isspace(pcStr[*piPos])) (*piPos)++;
+ while (pcStr[*piPos] && !isspace(pcStr[*piPos])) (*piPos)++;
  
  return iResult;
 }
@@ -264,6 +264,8 @@
 	(guint *) &(tmpNode->md5Hash[14]), (guint *) &(tmpNode->md5Hash[15]));
 
 	/* Get playtimes */
+	if (inLine[linePos] != 0)
+	{
 	if (inLine[linePos] != '=')
 		{
 		XSERR("'=' expected in SongLengthDB file '%s' line #%d, column #%d\n",
@@ -295,6 +297,7 @@
 			xs_db_node_free(tmpNode);
 		}
 	}
+	}
  } else
  if ((inLine[0] != ';') && (inLine[0] != '['))
  	{
@@ -452,6 +455,7 @@
  return fread(s, sizeof(gchar), l, f);
 }
 
+#define MAX_MEMBUF (80*1024)
 
 gint xs_get_sid_hash(gchar *pcFilename, t_xs_md5hash hash)
 {
@@ -459,8 +463,9 @@
  t_xs_md5state inState;
  t_xs_psidv1_header psidH;
  t_xs_psidv2_header psidH2;
- guint8 *songData, ib8[2], i8;
- gint iIndex, iRes, songDataLen;
+ guint8 songData[MAX_MEMBUF+1], ib8[2], i8;
+ gint iIndex, iRes;
+
 
  /* Try to open the file */
  if ((inFile = fopen(pcFilename, "rb")) == NULL)
@@ -495,39 +500,18 @@
  	psidH2.reserved		= rd_be16(inFile);
  	}
 
- /* Get data length and seek to data offset */
- fseek(inFile, 0L, SEEK_END);
- songDataLen = ftell(inFile) - psidH.dataOffset;
- fseek(inFile, psidH.dataOffset, SEEK_SET);
-
- /* Allocate memory */ 
- songData = (guint8 *) g_malloc(sizeof(guint8) * songDataLen);
- if (songData == NULL)
- 	{
- 	fclose(inFile);
- 	return -7;
- 	}
-
  /* Read data to buffer */
- iRes = fread(songData, sizeof(guint8), songDataLen, inFile);
+ iRes = fread(songData, sizeof(guint8), MAX_MEMBUF, inFile);
  fclose(inFile);
 
- if (iRes != songDataLen)
- 	{
- 	g_free(songData);
- 	return -9;
- 	}
- 
  /* Initialize and start MD5-hash calculation */
  xs_md5_init(&inState);
  if (psidH.loadAddress == 0)
  	/* COULD SOMEONE EXPLAIN WHY DO WE NEED THIS +2 STRIP???? */
-	xs_md5_append(&inState, songData+2, iRes-2);
+	xs_md5_append(&inState, &songData[2], iRes-2);
 	else
-	xs_md5_append(&inState, songData, iRes);
-	
- g_free(songData);
- 
+	xs_md5_append(&inState, &songData, iRes);
+
  /* Append header data to hash */
 #define XSADDHASH(QDATAB) { ib8[0] = (QDATAB & 0xff); ib8[1] = (QDATAB >> 8); xs_md5_append(&inState, (guint8 *) &ib8, sizeof(ib8)); }
  
--- a/src/xs_length.h	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_length.h	Sun Oct 05 10:38:03 2003 +0000
@@ -17,7 +17,7 @@
 	gint32		sLengths[XS_STIL_MAXENTRY];	
 					/* Lengths in seconds */
 
-	struct _t_xs_sldb_node *pNext;
+	struct _t_xs_sldb_node *pPrev, *pNext;
 } t_xs_sldb_node;
 
 
@@ -26,7 +26,7 @@
  */
 gint	xs_songlen_init(void);		/* Initialize songlength subsystem */
 void	xs_songlen_close(void);		/* Close/shutdown */
-gint32	xs_songlen_get(gchar *, gint);	/* Get length in seconds */
+t_xs_sldb_node *xs_songlen_get(gchar *);
 
 
 #ifdef __cplusplus
--- a/src/xs_sidplay.h	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_sidplay.h	Sun Oct 05 10:38:03 2003 +0000
@@ -1,18 +1,23 @@
 /*
+ * Here comes the really ugly code...
+ *
  * Create the SID-tune description string from the tune's information
  * formatted by the user-specified format-string.
  */
-gchar *xs_make_filetitle(gchar *pcFileName, sidTuneInfo *pfInfo, gint iSubTune)
+#define VBUFSIZE	(1024)
+#define VPUTCH(MCH)	if (iIndex < VBUFSIZE) tmpBuf[iIndex++] = MCH;
+#define VPUTSTR(MSTR)	{if (MSTR) {if ((iIndex + strlen(MSTR) + 1) < VBUFSIZE){strcpy(&tmpBuf[iIndex], MSTR);iIndex += strlen(MSTR); } else iIndex = VBUFSIZE;}}
+
+gchar * TFUNCTION1(gchar *pcFilename, TTUNEINFO *pfInfo, gint iSubTune)
 {
- gint j, iLength;
- gchar *pcStr, *pcResult;
+ gchar *pcStr, *pcResult, tmpStr[VBUFSIZE], tmpBuf[VBUFSIZE];
+ gint iIndex;
 #ifdef HAVE_XMMSEXTRA
  TitleInput *ptInput;
 #endif
 
  /* FIXME FIXME: get STIL-information */
- 
-	
+
  /* Check the info strings */
  if (pfInfo->numberOfInfoStrings < 3)
 	{
@@ -61,54 +66,88 @@
 	else
 #endif
 	{
-	/* Estimate the length of the string */
+	/* Create the string */
 	pcStr = xs_cfg.titleFormat;
-	iLength = 0;
-	while (*pcStr)
+	iIndex = 0;
+	while (*pcStr && (iIndex < VBUFSIZE))
 	{
 	if (*pcStr == '%')
 		{
-		switch (*(++pcStr)) {
-		case '1': iLength += strlen(pfInfo->infoString[1]); break;
-		case '2': iLength += strlen(pfInfo->infoString[0]); break;
-		case '3': iLength += strlen(pfInfo->infoString[2]); break;
-		case '4': iLength += strlen(pfInfo->formatString); break;
-		case '%': iLength++;
+		pcStr++;
+		switch (*pcStr) {
+		case '%': VPUTCH('%'); break;
+		case '1': VPUTSTR(pfInfo->infoString[1]); break;
+		case '2': VPUTSTR(pfInfo->infoString[0]); break;
+		case '3': VPUTSTR(pfInfo->infoString[2]); break;
+		case '4': VPUTSTR(pfInfo->formatString); break;
+		case '5':
+			snprintf(tmpStr, VBUFSIZE, "%i", iSubTune);
+			VPUTSTR(tmpStr);
+			break;
 		}
-		} else
-		iLength++;
-
+		} else {
+		VPUTCH(*pcStr);
+		}
 	pcStr++;
 	}
-
-	/* Allocate memory */
-	pcResult = (gchar *) g_malloc(iLength + 2);
-	if (pcResult == NULL)
-		return g_strdup(pfInfo->infoString[0]);
-
-	/* Create the string */
-	pcStr = xs_cfg.titleFormat;
-	j = 0;
-	while (*pcStr)
-	{
-	if (*pcStr == '%')
-		{
-		switch (*(++pcStr)) {
-		case '1': xs_strpcat(pcResult, &j, pfInfo->infoString[1]); break;
-		case '2': xs_strpcat(pcResult, &j, pfInfo->infoString[0]); break;
-		case '3': xs_strpcat(pcResult, &j, pfInfo->infoString[2]); break;
-		case '4': xs_strpcat(pcResult, &j, pfInfo->formatString); break;
-		case '%': pcResult[j++] = '%'; break;
-		}
-		} else
-		pcResult[j++] = *pcStr;
-
-	pcStr++;
-	}
-
-	pcResult[j] = 0;
+	tmpBuf[iIndex] = 0;
+	pcResult = g_strdup(tmpBuf);
 	}
 
  return pcResult;
 }
 
+
+/*
+ * Get all SID-tune information (for all sub-tunes) including name, length, etc.
+ */
+t_xs_tune * TFUNCTION2(gchar *pcFilename)
+{
+ t_xs_sldb_node *tuneLen = NULL;
+ t_xs_tune *pResult;
+ TTUNEINFO tuneInfo;
+ TTUNE *testTune;
+ gint i;
+
+ /* Check if the tune exists and is readable */
+ if ((testTune = new TTUNE(pcFilename)) == NULL)
+	return NULL;
+
+ if (!testTune->getStatus())
+	{
+	delete testTune;
+	return NULL;
+	}
+
+ /* Get general tune information */
+ testTune->getInfo(tuneInfo);
+
+ /* Get length information (NOTE: Do not free this!) */
+ tuneLen = xs_songlen_get(pcFilename);
+
+ /* Allocate tuneinfo structure */
+ if ((pResult = xs_tune_new(pcFilename, tuneInfo.songs, tuneInfo.startSong)) == NULL)
+ 	{
+ 	delete testTune;
+	return NULL;
+	}
+
+ /* Get information for subtunes */
+ for (i = 0; i < pResult->nsubTunes; i++)
+	{
+	/* Make the title */
+	pResult->subTunes[i].tuneTitle = TFUNCTION1(pcFilename, &tuneInfo, i+1);
+
+	/* Get song length */
+	if (tuneLen && (i < tuneLen->nLengths))
+		pResult->subTunes[i].tuneLength = tuneLen->sLengths[i];
+		else
+		pResult->subTunes[i].tuneLength = -1;
+	}
+
+ delete testTune;
+
+ return pResult;
+}
+
+
--- a/src/xs_sidplay1.cc	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_sidplay1.cc	Sun Oct 05 10:38:03 2003 +0000
@@ -53,9 +53,9 @@
 /*
  * Check if we can play the given file
  */
-gboolean xs_sidplay1_isourfile(gchar *pcFileName)
+gboolean xs_sidplay1_isourfile(gchar *pcFilename)
 {
- sidTune *testTune = new sidTune(pcFileName);
+ sidTune *testTune = new sidTune(pcFilename);
 
  if (!testTune) return FALSE;
  if (!testTune->getStatus())
@@ -86,7 +86,7 @@
  if (!myPlayer->currEng)
 	{
 	XSERR("Could not initialize libSIDPlay1 emulation engine\n");
-	free(myPlayer);
+	g_free(myPlayer);
 	return FALSE;
 	}
 
@@ -94,7 +94,8 @@
  if (!myPlayer->currEng->verifyEndianess())
 	{
 	XSERR("Endianess verification failed\n");
-	free(myPlayer);
+	delete myPlayer->currEng;
+	g_free(myPlayer);
 	return FALSE;
 	}
 
@@ -112,13 +113,14 @@
  assert(myStatus);
 
  /* Free internals */
- xs_sidplay1_deletesid(myStatus);
-
  myPlayer = (t_xs_sidplay1 *) myStatus->player;
+ if (myPlayer->currEng)
+	{
+	delete myPlayer->currEng;
+	myPlayer->currEng = NULL;	
+	}
 
- if (myPlayer->currEng) delete myPlayer->currEng;
-
- free(myPlayer);
+ g_free(myPlayer);
  myStatus->player = NULL;
 }
 
@@ -164,16 +166,15 @@
 }
 
 
-gboolean xs_sidplay1_loadsid(t_xs_status *myStatus, gchar *pcFileName)
+gboolean xs_sidplay1_loadsid(t_xs_status *myStatus, gchar *pcFilename)
 {
  t_xs_sidplay1 *myPlayer = (t_xs_sidplay1 *) myStatus->player;
  sidTune *newTune;
- sidTuneInfo tuneInfo;
  assert(myStatus);
 
  /* Try to get the tune */
- if (!pcFileName) return FALSE;
- newTune = new sidTune(pcFileName);
+ if (!pcFilename) return FALSE;
+ newTune = new sidTune(pcFilename);
  if (!newTune) return FALSE;
 
  /* Get current configuration */
@@ -258,17 +259,14 @@
 	}
 
  /* Initialize status information */
- newTune->getInfo(tuneInfo);
- myPlayer->currTune	= newTune;
- myStatus->currSong	= tuneInfo.startSong;
- myStatus->nSongs	= tuneInfo.songs;
+ myPlayer->currTune = newTune;
 
  return TRUE;
 }
 
 
 /*
- * Delete tune
+ * Delete INTERNAL information
  */
 void xs_sidplay1_deletesid(t_xs_status *myStatus)
 {
@@ -286,52 +284,14 @@
 }
 
 
-gint xs_sidplay1_gettunespeed(t_xs_status *myStatus)
-{
- return 0;
-}
-
-
 /*
  * Return song information
  */
-#include "xs_sidplay.h"	// Include common function
-
-void xs_sidplay1_getsidinfo(gchar *songFileName, gchar **songTitle, gint *songLength, gint subSong)
-{
- sidTuneInfo tuneInfo;
- sidTune *testTune;
- gint tmpInt;
-
- /* Check if the tune exists and is readable */
- testTune = new sidTune(songFileName);
- if (!testTune) return;
- if (!testTune->getStatus())
-	{
-	delete testTune;
-	return;
-	}
-
- /* Get general tune information */
- testTune->getInfo(tuneInfo);
- delete testTune;
-
- /* Get titlestring */
- if (subSong < 0)
-	tmpInt = tuneInfo.startSong;
-	else
-	tmpInt = subSong;
-
- *songTitle = xs_make_filetitle(songFileName, &tuneInfo, tmpInt);
-
- /* Get song length (in milliseconds), negative if no known length */
- tmpInt = xs_songlen_get(songFileName, tuneInfo.startSong);
- if (tmpInt >= 0)
-	*songLength = (tmpInt * 1000);
-	else
-	*songLength = -1;
-}
-
+#define TFUNCTION1	xs_sidplay1_filetitle
+#define TFUNCTION2	xs_sidplay1_getsidinfo
+#define TTUNEINFO	sidTuneInfo
+#define TTUNE		sidTune
+#include "xs_sidplay.h"
 
 }	/* extern "C" */
 #endif	/* HAVE_SIDPLAY1 */
--- a/src/xs_sidplay1.h	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_sidplay1.h	Sun Oct 05 10:38:03 2003 +0000
@@ -10,7 +10,6 @@
 gboolean	xs_sidplay1_fillbuffer(t_xs_status *, gchar *, gint);
 gboolean	xs_sidplay1_loadsid(t_xs_status *, gchar *);
 void		xs_sidplay1_deletesid(t_xs_status *);
-gint		xs_sidplay1_gettunespeed(t_xs_status *);
-void		xs_sidplay1_getsidinfo(gchar *, gchar **, gint *, gint);
+t_xs_tune*	xs_sidplay1_getsidinfo(gchar *);
 
 #endif /* _XS_SIDPLAY1_H */
--- a/src/xs_sidplay2.cc	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_sidplay2.cc	Sun Oct 05 10:38:03 2003 +0000
@@ -58,9 +58,9 @@
 /*
  * Check if we can play the given file
  */
-gboolean xs_sidplay2_isourfile(gchar *pcFileName)
+gboolean xs_sidplay2_isourfile(gchar *pcFilename)
 {
- SidTune *testTune = new SidTune(pcFileName);
+ SidTune *testTune = new SidTune(pcFilename);
 
  if (!testTune) return FALSE;
  if (!testTune->getStatus())
@@ -96,9 +96,7 @@
 	}
 
  /* Initialize builder object */
- /*
-	FIXME! we need to select builder by configuration!
- */
+ XSDEBUG("init builder #%i\n", xs_cfg.sid2Builder);
 #ifdef HAVE_RESID_BUILDER
  if (xs_cfg.sid2Builder == XS_BLD_RESID)
 	{
@@ -205,15 +203,16 @@
 }
 
 
-gboolean xs_sidplay2_loadsid(t_xs_status *myStatus, gchar *pcFileName)
+gboolean xs_sidplay2_loadsid(t_xs_status *myStatus, gchar *pcFilename)
 {
  t_xs_sidplay2 *myPlayer = (t_xs_sidplay2 *) myStatus->player;
- SidTuneInfo tuneInfo;
  assert(myStatus);
 
  /* Try to get the tune */
- if (!pcFileName) return FALSE;
- if (!myPlayer->currTune->load(pcFileName)) return FALSE;
+ if (!pcFilename) return FALSE;
+XSDEBUG("paski #1\n");
+ if (!myPlayer->currTune->load(pcFilename)) return FALSE;
+XSDEBUG("paski #2\n");
 
  /* Get current configuration */
  myPlayer->currConfig = myPlayer->currEng->config();
@@ -293,6 +292,8 @@
 #endif
 #endif
 
+XSDEBUG("paski #3\n");
+
  /* Now set the emulator configuration */
  if (myPlayer->currEng->config(myPlayer->currConfig) < 0)
 	{
@@ -300,10 +301,7 @@
 	return FALSE;
 	}
 
- /* Initialize status information */
- myPlayer->currTune->getInfo(tuneInfo);
- myStatus->currSong	= tuneInfo.startSong;
- myStatus->nSongs	= tuneInfo.songs;
+XSDEBUG("paski #4\n");
 
  return TRUE;
 }
@@ -314,34 +312,20 @@
  */
 void xs_sidplay2_deletesid(t_xs_status *myStatus)
 {
- t_xs_sidplay2 *myPlayer;
  assert(myStatus);
 
-/*
- myPlayer = (t_xs_sidplay2 *) myStatus->player;
- if (!myPlayer) return;
-
- if (myPlayer->currTune)
-	{
-	delete myPlayer->currTune;
-	myPlayer->currTune = NULL;
-	}
-*/
+ /* With the current scheme of handling sidtune-loading, we don't do anything here. */
 }
 
 
-gint xs_sidplay2_gettunespeed(t_xs_status *myStatus)
-{
- return 0;
-}
-
 /*
  * Return song information
  */
-void xs_sidplay2_getsidinfo(gchar *songFileName, gchar **songTitle, gint *songLength)
-{
-}
-
+#define TFUNCTION1	xs_sidplay2_filetitle
+#define TFUNCTION2	xs_sidplay2_getsidinfo
+#define TTUNEINFO	SidTuneInfo
+#define TTUNE		SidTune
+#include "xs_sidplay.h"
 
 }	/* extern "C" */
 #endif	/* HAVE_SIDPLAY2 */
--- a/src/xs_sidplay2.h	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_sidplay2.h	Sun Oct 05 10:38:03 2003 +0000
@@ -10,7 +10,6 @@
 gboolean	xs_sidplay2_fillbuffer(t_xs_status *, gchar *, gint);
 gboolean	xs_sidplay2_loadsid(t_xs_status *, gchar *);
 void		xs_sidplay2_deletesid(t_xs_status *);
-gint		xs_sidplay2_gettunespeed(t_xs_status *);
-void		xs_sidplay2_getsidinfo(gchar *, gchar **, gint *);
+t_xs_tune*	xs_sidplay2_getsidinfo(gchar *);
 
 #endif /* _XS_SIDPLAY2_H */
--- a/src/xs_support.c	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_support.c	Sun Oct 05 10:38:03 2003 +0000
@@ -60,20 +60,6 @@
 }
 
 
-gint xs_strpcat(gchar *pcResult, gint *j, const gchar *pcStr)
-{
- assert(pcResult);
- assert(pcStr);
- assert(j);
- 
- /* Cat to the destination */
- strcpy((pcResult+(*j)), pcStr);
- (*j) += strlen(pcStr);
-
- return 0;
-}
-
-
 gchar *xs_strrchr(gchar *pcStr, gchar ch)
 {
  gchar *lastPos = NULL;
--- a/src/xs_support.h	Sat Oct 04 08:21:01 2003 +0000
+++ b/src/xs_support.h	Sun Oct 05 10:38:03 2003 +0000
@@ -12,7 +12,6 @@
  */
 gint	xs_strcalloc(gchar **, const gchar *);
 gint	xs_strcat(gchar **, const gchar *);
-gint	xs_strpcat(gchar *, gint *, const gchar *);
 gchar	*xs_strrchr(gchar *, gchar);
 inline 	void xs_findnext(gchar *, gint *);
 inline	void xs_findnum(gchar *, gint *);