changeset 402:f997b79a7251

More work on merging of improved STIL/SLDB handling code with completely dynamic memory allocation.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 01 Jun 2006 02:18:02 +0000
parents 30da794755f7
children b2d233cd01ba
files src/xmms-sid.c src/xmms-sid.h src/xs_config.c src/xs_config.h src/xs_length.c src/xs_length.h src/xs_sidplay.h src/xs_sidplay1.cc src/xs_sidplay2.cc src/xs_stil.c src/xs_title.c src/xs_title.h
diffstat 12 files changed, 161 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/src/xmms-sid.c	Wed May 31 22:52:00 2006 +0000
+++ b/src/xmms-sid.c	Thu Jun 01 02:18:02 2006 +0000
@@ -38,6 +38,7 @@
 #include "xs_config.h"
 #include "xs_length.h"
 #include "xs_stil.h"
+#include "xs_title.h"
 #include "xs_filter.h"
 #include "xs_fileinfo.h"
 #include "xs_interface.h"
@@ -308,10 +309,10 @@
 	XS_MUTEX_LOCK(xs_status);
 	memcpy(&myStatus, &xs_status, sizeof(t_xs_status));
 	myTune = xs_status.tuneInfo;
+	for (i = 0; i <= myTune->nsubTunes; i++)
+		myTune->subTunes[i].tunePlayed = FALSE;
 	XS_MUTEX_UNLOCK(xs_status);
 
-	xs_memset(&playedTune, 0, sizeof(playedTune));
-
 	/* Allocate audio buffer */
 	audioBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE);
 	if (audioBuffer == NULL) {
@@ -336,13 +337,17 @@
 		/* Automatic sub-tune change logic */
 		XS_MUTEX_LOCK(xs_cfg);
 		XS_MUTEX_LOCK(xs_status);
-		assert(xs_status.currSong >= 1);
-		assert(xs_status.currSong <= XS_STIL_MAXENTRY);
 		myStatus.isPlaying = TRUE;
-
+		
+		if (xs_status.currSong < 1 || myStatus.currSong < 1) {
+			XS_MUTEX_UNLOCK(xs_status);
+			XS_MUTEX_UNLOCK(xs_cfg);
+			goto xs_err_exit;
+		}
+		
 		if (xs_cfg.subAutoEnable && (myStatus.currSong == xs_status.currSong)) {
 			/* Check if currently selected sub-tune has been played already */
-			if (playedTune[myStatus.currSong]) {
+			if (myTune->subTunes[myStatus.currSong-1].tunePlayed) {
 				/* Find a tune that has not been played */
 				XSDEBUG("tune #%i already played, finding next match ...\n", myStatus.currSong);
 				isFound = FALSE;
@@ -350,12 +355,12 @@
 				while (!isFound && (++i <= myTune->nsubTunes)) {
 					if (xs_cfg.subAutoMinOnly) {
 						/* A tune with minimum length must be found */
-						if (!playedTune[i]
-						    && myTune->subTunes[i].tuneLength >= xs_cfg.subAutoMinTime)
+						if (!myTune->subTunes[i-1].tunePlayed &&
+							myTune->subTunes[i-1].tuneLength >= xs_cfg.subAutoMinTime)
 							isFound = TRUE;
 					} else {
 						/* Any unplayed tune is okay */
-						if (!playedTune[i])
+						if (!myTune->subTunes[i-1].tunePlayed)
 							isFound = TRUE;
 					}
 				}
@@ -376,7 +381,7 @@
 
 		/* Tell that we are initializing, update sub-tune controls */
 		myStatus.currSong = xs_status.currSong;
-		playedTune[myStatus.currSong] = TRUE;
+		myTune->subTunes[myStatus.currSong-1].tunePlayed = TRUE;
 		XS_MUTEX_UNLOCK(xs_status);
 		XS_MUTEX_UNLOCK(xs_cfg);
 
@@ -387,7 +392,7 @@
 		GDK_THREADS_LEAVE();
 
 		/* Check minimum playtime */
-		songLength = myTune->subTunes[myStatus.currSong - 1].tuneLength;
+		songLength = myTune->subTunes[myStatus.currSong-1].tuneLength;
 		if (xs_cfg.playMinTimeEnable && (songLength >= 0)) {
 			if (songLength < xs_cfg.playMinTime)
 				songLength = xs_cfg.playMinTime;
@@ -416,11 +421,11 @@
 		audioOpen = TRUE;
 
 		/* Set song information for current subtune */
-		xs_plugin_ip.set_info(myTune->subTunes[myStatus.currSong - 1].tuneTitle,
-				      (songLength > 0) ? (songLength * 1000) : 0,
-				      (myTune->subTunes[myStatus.currSong - 1].tuneSpeed >
-				       0) ? (myTune->subTunes[myStatus.currSong - 1].tuneSpeed * 1000) : -1,
-				      myStatus.audioFrequency, myStatus.audioChannels);
+		xs_plugin_ip.set_info(myTune->subTunes[myStatus.currSong-1].tuneTitle,
+			(songLength > 0) ? (songLength * 1000) : 0,
+			(myTune->subTunes[myStatus.currSong-1].tuneSpeed > 0) ?
+			(myTune->subTunes[myStatus.currSong-1].tuneSpeed * 1000) : -1,
+			myStatus.audioFrequency, myStatus.audioChannels);
 
 
 		XSDEBUG("playing\n");
@@ -497,7 +502,7 @@
 			doPlay = FALSE;
 	}
 
-      xs_err_exit:
+xs_err_exit:
 	/* Close audio output plugin */
 	if (audioOpen) {
 		XSDEBUG("close audio #2\n");
@@ -736,7 +741,8 @@
 	GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next;
 
 	XS_MUTEX_LOCK(xs_subctrl);
-	if (!xs_status.tuneInfo || !xs_status.isPlaying || xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) {
+	if (!xs_status.tuneInfo || !xs_status.isPlaying ||
+		xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) {
 		XS_MUTEX_UNLOCK(xs_subctrl);
 		return;
 	}
@@ -902,7 +908,6 @@
 void xs_get_song_info(gchar * songFilename, gchar ** songTitle, gint * songLength)
 {
 	t_xs_tuneinfo *pInfo;
-	gint tmpInt;
 
 	/* Get tune information from emulation engine */
 	pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename);
@@ -911,9 +916,11 @@
 
 	/* Get sub-tune information, if available */
 	if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) {
-		(*songTitle) = g_strdup(pInfo->subTunes[pInfo->startTune - 1].tuneTitle);
+		gint tmpInt;
+		
+		(*songTitle) = g_strdup(pInfo->subTunes[pInfo->startTune-1].tuneTitle);
 
-		tmpInt = pInfo->subTunes[pInfo->startTune - 1].tuneLength;
+		tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength;
 		if (tmpInt < 0)
 			(*songLength) = -1;
 		else
@@ -927,11 +934,15 @@
 
 /* Allocate a new tune information structure
  */
-t_xs_tuneinfo *xs_tuneinfo_new(gchar * pcFilename, gint nsubTunes, gint startTune,
-			       gchar * sidName, gchar * sidComposer, gchar * sidCopyright,
-			       gint loadAddr, gint initAddr, gint playAddr, gint dataFileLen)
+t_xs_tuneinfo *xs_tuneinfo_new(const gchar * pcFilename,
+		gint nsubTunes, gint startTune, const gchar * sidName,
+		const gchar * sidComposer, const gchar * sidCopyright,
+		gint loadAddr, gint initAddr, gint playAddr,
+		gint dataFileLen, const gchar *sidFormat)
 {
 	t_xs_tuneinfo *pResult;
+	t_xs_sldb_node *tmpLength;
+	gint i;
 
 	/* Allocate structure */
 	pResult = (t_xs_tuneinfo *) g_malloc0(sizeof(t_xs_tuneinfo));
@@ -948,15 +959,14 @@
 	}
 
 	/* Allocate space for subtune information */
-	if (nsubTunes > 0) {
-		pResult->subTunes = g_malloc0(sizeof(t_xs_subtuneinfo) * nsubTunes);
-		if (!pResult->subTunes) {
-			xs_error("Could not allocate memory for t_xs_subtuneinfo ('%s', %i)\n", pcFilename, nsubTunes);
+	pResult->subTunes = g_malloc0(sizeof(t_xs_subtuneinfo) * (nsubTunes + 1));
+	if (!pResult->subTunes) {
+		xs_error("Could not allocate memory for t_xs_subtuneinfo ('%s', %i)\n",
+			pcFilename, nsubTunes);
 
-			g_free(pResult->sidFilename);
-			g_free(pResult);
-			return NULL;
-		}
+		g_free(pResult->sidFilename);
+		g_free(pResult);
+		return NULL;
 	}
 
 	/* The following allocations don't matter if they fail */
@@ -971,7 +981,21 @@
 	pResult->initAddr = initAddr;
 	pResult->playAddr = playAddr;
 	pResult->dataFileLen = dataFileLen;
+	pResult->sidFormat = g_strdup(sidFormat);
 
+	/* Get length information (NOTE: Do not free this!) */
+	tmpLength = xs_songlen_get(pcFilename);
+	
+	/* Fill in sub-tune information */
+	for (i = 0; i < pResult->nsubTunes; i++) {
+		if (tmpLength && (i < tmpLength->nLengths))
+			pResult->subTunes[i].tuneLength = tmpLength->sLengths[i];
+		else
+			pResult->subTunes[i].tuneLength = -1;
+		
+		pResult->subTunes[i].tuneTitle = xs_make_titlestring(pResult, i);
+	}
+	
 	return pResult;
 }
 
@@ -981,23 +1005,19 @@
 void xs_tuneinfo_free(t_xs_tuneinfo * pTune)
 {
 	gint i;
-	if (!pTune)
-		return;
 
-	for (i = 0; i < pTune->nsubTunes; i++) {
+	if (!pTune) return;
+
+	for (i = 1; i < pTune->nsubTunes; i++) {
 		g_free(pTune->subTunes[i].tuneTitle);
 		pTune->subTunes[i].tuneTitle = NULL;
 	}
 
 	g_free(pTune->subTunes);
-	pTune->nsubTunes = 0;
 	g_free(pTune->sidFilename);
-	pTune->sidFilename = NULL;
 	g_free(pTune->sidName);
-	pTune->sidName = NULL;
 	g_free(pTune->sidComposer);
-	pTune->sidComposer = NULL;
 	g_free(pTune->sidCopyright);
-	pTune->sidCopyright = NULL;
+	g_free(pTune->sidFormat);
 	g_free(pTune);
 }
--- a/src/xmms-sid.h	Wed May 31 22:52:00 2006 +0000
+++ b/src/xmms-sid.h	Thu Jun 01 02:18:02 2006 +0000
@@ -140,11 +140,13 @@
 	gchar		*sidFilename,
 			*sidName,
 			*sidComposer,
-			*sidCopyright;
+			*sidCopyright,
+			*sidFormat;
 	gint		loadAddr,
 			initAddr,
 			playAddr,
-			dataFileLen;
+			dataFileLen,
+			sidModel;
 	gint		nsubTunes, startTune;
 	t_xs_subtuneinfo	*subTunes;
 } t_xs_tuneinfo;
@@ -207,7 +209,10 @@
 void	xs_get_song_info(gchar *, gchar **, gint *);
 void	xs_about(void);
 
-t_xs_tuneinfo *xs_tuneinfo_new(gchar *, gint, gint, gchar *, gchar *, gchar *, gint, gint, gint, gint);
+t_xs_tuneinfo *xs_tuneinfo_new(const gchar *, gint, gint,
+	const gchar *, const gchar *, const gchar *,
+	gint, gint, gint, gint, const gchar *);
+
 void	xs_tuneinfo_free(t_xs_tuneinfo *);
 
 void	xs_error(const char *, ...);
--- a/src/xs_config.c	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_config.c	Thu Jun 01 02:18:02 2006 +0000
@@ -193,7 +193,7 @@
 	xs_cfg.clockSpeed = XS_CLOCK_PAL;
 	xs_cfg.forceSpeed = FALSE;
 
-	xs_cfg.sid2OptLevel = FALSE;
+	xs_cfg.sid2OptLevel = 0;
 #ifdef HAVE_RESID_BUILDER
 	xs_cfg.sid2Builder = XS_BLD_RESID;
 #else
--- a/src/xs_config.h	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_config.h	Thu Jun 01 02:18:02 2006 +0000
@@ -81,7 +81,7 @@
 
 	gint		playerEngine;		/* Selected player engine */
 
-	gboolean	sid2OptLevel;		/* SIDPlay2 emulation optimization */
+	gint		sid2OptLevel;		/* SIDPlay2 emulation optimization */
 	gint		sid2Builder;		/* SIDPlay2 "builder" aka SID-emu */
 
 	gboolean	oversampleEnable;
--- a/src/xs_length.c	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_length.c	Thu Jun 01 02:18:02 2006 +0000
@@ -103,7 +103,7 @@
  */
 t_xs_sldb_node * xs_sldb_read_entry(gchar *inLine)
 {
-	gint linePos, savePos, i, tmpLen;
+	gint linePos, savePos, i, tmpLen, l;
 	gboolean iOK;
 	t_xs_sldb_node *tmpNode;
 
@@ -136,18 +136,13 @@
 			iOK = TRUE;
 			while ((linePos < tmpLen) && iOK) {
 				xs_findnext(inLine, &linePos);
+
 				if (xs_sldb_gettime(inLine, &linePos) >= 0)
 					tmpNode->nLengths++;
 				else
 					iOK = FALSE;
 			}
 			
-			if (!iOK) {
-				xs_error("Invalid sub-tune length.\n");
-				xs_sldb_node_free(tmpNode);
-				return NULL;
-			}
-						
 			/* Allocate memory for lengths */
 			tmpNode->sLengths = (gint *) g_malloc0(tmpNode->nLengths * sizeof(gint));
 			if (!tmpNode->sLengths) {
@@ -160,14 +155,16 @@
 			i = 0;
 			linePos = savePos;
 			iOK = TRUE;
-			while ((linePos < tmpLen) && iOK) {
+			while ((linePos < tmpLen) && (i < tmpNode->nLengths) && iOK) {
 				xs_findnext(inLine, &linePos);
 
-				if (i < tmpNode->nLengths) {
-					tmpNode->sLengths[i] = xs_sldb_gettime(inLine, &linePos);
-					i++;
-				} else
+				l = xs_sldb_gettime(inLine, &linePos);
+				if (l >= 0)
+					tmpNode->sLengths[i] = l;
+				else
 					iOK = FALSE;
+
+				i++;
 			}
 
 			if (!iOK) {
@@ -184,7 +181,7 @@
 
 /* Read database to memory
  */
-gint xs_sldb_read(t_xs_sldb *db, gchar *dbFilename)
+gint xs_sldb_read(t_xs_sldb *db, const gchar *dbFilename)
 {
 	FILE *inFile;
 	gchar inLine[XS_BUF_SIZE];
@@ -429,7 +426,7 @@
 } t_xs_psidv2_header;
 
 
-static gint xs_get_sid_hash(gchar * pcFilename, t_xs_md5hash hash)
+static gint xs_get_sid_hash(const gchar *pcFilename, t_xs_md5hash hash)
 {
 	FILE *inFile;
 	t_xs_md5state inState;
@@ -535,7 +532,7 @@
 
 /* Get song lengths
  */
-t_xs_sldb_node *xs_sldb_get(t_xs_sldb *db, gchar *pcFilename)
+t_xs_sldb_node *xs_sldb_get(t_xs_sldb *db, const gchar *pcFilename)
 {
 	t_xs_sldb_node *pResult;
 	t_xs_md5hash dbHash;
@@ -612,7 +609,7 @@
 }
 
 
-t_xs_sldb_node *xs_songlen_get(gchar * pcFilename)
+t_xs_sldb_node *xs_songlen_get(const gchar * pcFilename)
 {
 	t_xs_sldb_node *pResult;
 
--- a/src/xs_length.h	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_length.h	Thu Jun 01 02:18:02 2006 +0000
@@ -29,15 +29,15 @@
 /*
  * Functions
  */
-gint			xs_sldb_read(t_xs_sldb *, gchar *);
+gint			xs_sldb_read(t_xs_sldb *, const gchar *);
 gint			xs_sldb_index(t_xs_sldb *);
 void			xs_sldb_free(t_xs_sldb *);
-t_xs_sldb_node *	xs_sldb_get(t_xs_sldb *, gchar *);
+t_xs_sldb_node *	xs_sldb_get(t_xs_sldb *, const gchar *);
 
 
 gint			xs_songlen_init(void);
 void			xs_songlen_close(void);
-t_xs_sldb_node *	xs_songlen_get(gchar *);
+t_xs_sldb_node *	xs_songlen_get(const gchar *);
 
 #ifdef __cplusplus
 }
--- a/src/xs_sidplay.h	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_sidplay.h	Thu Jun 01 02:18:02 2006 +0000
@@ -1,16 +1,12 @@
-/*
- * Here comes the really ugly code...
- * Get all SID-tune information (for all sub-tunes)
- * including name, length, etc.
+/* Here comes the really ugly code... Get all SID-tune information
+ * for all sub-tunes, including name, length, etc.
  */
 t_xs_tuneinfo *TFUNCTION(gchar * pcFilename)
 {
-	t_xs_sldb_node *tuneLength = NULL;
 	t_xs_tuneinfo *pResult;
 	TTUNEINFO tuneInfo;
 	TTUNE *testTune;
 	gboolean haveInfo = TRUE;
-	gint i;
 
 	/* Check if the tune exists and is readable */
 	if ((testTune = new TTUNE(pcFilename)) == NULL)
@@ -30,37 +26,12 @@
 	haveInfo = TRUE;
 #endif
 
-	/* Get length information (NOTE: Do not free this!) */
-	tuneLength = xs_songlen_get(pcFilename);
-
 	/* Allocate tuneinfo structure */
 	pResult = xs_tuneinfo_new(pcFilename,
-				  tuneInfo.songs, tuneInfo.startSong,
-				  tuneInfo.infoString[0], tuneInfo.infoString[1], tuneInfo.infoString[2],
-				  tuneInfo.loadAddr, tuneInfo.initAddr, tuneInfo.playAddr, tuneInfo.dataFileLen);
-
-	if (!pResult) {
-		delete testTune;
-		return NULL;
-	}
-
-	/* Get information for subtunes */
-	for (i = 0; i < pResult->nsubTunes; i++) {
-		/* Make the title */
-		if (haveInfo) {
-			pResult->subTunes[i].tuneTitle =
-			    xs_make_titlestring(pcFilename, i + 1, pResult->nsubTunes, tuneInfo.sidModel,
-						tuneInfo.formatString, tuneInfo.infoString[0],
-						tuneInfo.infoString[1], tuneInfo.infoString[2]);
-		} else
-			pResult->subTunes[i].tuneTitle = g_strdup(pcFilename);
-
-		/* Get song length */
-		if (tuneLength && (i < tuneLength->nLengths))
-			pResult->subTunes[i].tuneLength = tuneLength->sLengths[i];
-		else
-			pResult->subTunes[i].tuneLength = -1;
-	}
+		tuneInfo.songs, tuneInfo.startSong,
+		tuneInfo.infoString[0], tuneInfo.infoString[1], tuneInfo.infoString[2],
+		tuneInfo.loadAddr, tuneInfo.initAddr, tuneInfo.playAddr,
+		tuneInfo.dataFileLen, tuneInfo.formatString);
 
 	delete testTune;
 
--- a/src/xs_sidplay1.cc	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_sidplay1.cc	Thu Jun 01 02:18:02 2006 +0000
@@ -27,8 +27,6 @@
 #include "xs_sidplay1.h"
 #include <stdio.h>
 #include "xs_config.h"
-#include "xs_length.h"
-#include "xs_title.h"
 
 #include <sidplay/player.h>
 #include <sidplay/myendian.h>
--- a/src/xs_sidplay2.cc	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_sidplay2.cc	Thu Jun 01 02:18:02 2006 +0000
@@ -28,8 +28,7 @@
 #include <stdio.h>
 #include "xs_config.h"
 #include "xs_support.h"
-#include "xs_length.h"
-#include "xs_title.h"
+
 
 #include <sidplay/sidplay2.h>
 #ifdef HAVE_RESID_BUILDER
@@ -200,7 +199,7 @@
 			/* Builder object created, initialize it */
 			rs->create((myEngine->currEng->info()).maxsids);
 			if (!*rs) {
-				xs_error("rs->create() failed. SIDPlay2 suxx again.\n");
+				xs_error("rs->create() failed.\n");
 				return FALSE;
 			}
 
@@ -210,12 +209,15 @@
 				return FALSE;
 			}
 
+			// FIXME FIX ME: support other configurable parameters ...
+			// ... WHEN/IF resid-builder+libsidplay2 gets fixed
 			rs->sampling(tmpFreq);
 			if (!*rs) {
 				xs_error("rs->sampling(%d) failed.\n", tmpFreq);
 				return FALSE;
 			}
 
+			// FIXME FIX ME: load filter spec
 			rs->filter((sid_filter_t *) NULL);
 			if (!*rs) {
 				xs_error("rs->filter(NULL) failed.\n");
@@ -232,7 +234,7 @@
 			/* Builder object created, initialize it */
 			hs->create((myEngine->currEng->info()).maxsids);
 			if (!*hs) {
-				xs_error("hs->create() failed. SIDPlay2 suxx again.\n");
+				xs_error("hs->create() failed.\n");
 				return FALSE;
 			}
 
@@ -259,8 +261,10 @@
 		myEngine->currConfig.clockDefault = SID2_CLOCK_NTSC;
 		break;
 
+	default:
+		xs_error("Invalid clockSpeed=%d, falling back to PAL.\n", xs_cfg.clockSpeed);
+
 	case XS_CLOCK_PAL:
-	default:
 		myEngine->currConfig.clockDefault = SID2_CLOCK_PAL;
 		xs_cfg.clockSpeed = XS_CLOCK_PAL;
 		break;
@@ -278,10 +282,15 @@
 		myEngine->currConfig.clockSpeed = SID2_CLOCK_CORRECT;
 	}
 	
-	if (xs_cfg.sid2OptLevel)
-		myEngine->currConfig.optimisation = 1;
-	else
-		myEngine->currConfig.optimisation = 0;
+	if ((xs_cfg.sid2OptLevel >= 0) && (xs_cfg.sid2OptLevel <= SID2_MAX_OPTIMISATION))
+		myEngine->currConfig.optimisation = xs_cfg.sid2OptLevel;
+	else {
+		xs_error("Invalid sid2OptLevel=%d, falling back to %d.\n",
+			xs_cfg.sid2OptLevel, SID2_DEFAULT_OPTIMISATION);
+		
+		xs_cfg.sid2OptLevel =
+		myEngine->currConfig.optimisation = SID2_DEFAULT_OPTIMISATION;
+	}
 
 	if (xs_cfg.mos8580)
 		myEngine->currConfig.sidDefault = SID2_MOS8580;
@@ -293,7 +302,8 @@
 	else
 		myEngine->currConfig.sidModel = SID2_MODEL_CORRECT;
 
-	myEngine->currConfig.sidSamples = TRUE;	// FIXME FIX ME, make configurable!
+	/* XXX: Should this be configurable? libSIDPlay1 does not support it, though */
+	myEngine->currConfig.sidSamples = TRUE;
 
 
 	/* Now set the emulator configuration */
--- a/src/xs_stil.c	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_stil.c	Thu Jun 01 02:18:02 2006 +0000
@@ -41,22 +41,28 @@
 			(t_xs_stil_subnode **) g_realloc(pNode->subTunes,
 			(nsubTunes + 1) * sizeof(t_xs_stil_subnode **));
 
-		if (!pNode->subTunes)
+		if (!pNode->subTunes) {
+			xs_error("SubTune pointer structure realloc failed.\n");
 			return FALSE;
+		}
 		
 		/* Clear the newly allocated memory */
 		xs_memset(&(pNode->subTunes[pNode->nsubTunes]), 0,
 			(nsubTunes + 1 - pNode->nsubTunes) *
 			sizeof(t_xs_stil_subnode **));
+		
+		pNode->nsubTunes = nsubTunes + 1;
 	}
-			
+
 	/* Allocate memory for subTune */
 	if (!pNode->subTunes[nsubTunes]) {
 		pNode->subTunes[nsubTunes] = (t_xs_stil_subnode *)
 			g_malloc0(sizeof(t_xs_stil_subnode));
 		
-		if (!pNode->subTunes[nsubTunes])
+		if (!pNode->subTunes[nsubTunes]) {
+			xs_error("SubTune structure malloc failed!\n");
 			return FALSE;
+		}
 	}
 
 	return TRUE;
@@ -247,7 +253,7 @@
 				break;
 			}
 
-			if (xs_stildb_node_realloc(tmpNode, subEntry)) {
+			if (!xs_stildb_node_realloc(tmpNode, subEntry)) {
 				XS_STILDB_ERR(lineNum, inLine,
 					"Could not (re)allocate memory for subEntries!\n");
 				isError = TRUE;
@@ -265,13 +271,11 @@
 				tmpNode->subTunes[subEntry]->pAuthor = g_strdup(&inLine[9]);
 			} else if (strncmp(inLine, "  TITLE:", 8) == 0) {
 				XS_STILDB_MULTI;
-				inLine[eolPos++] = '\n';
-				inLine[eolPos++] = 0;
+				isMulti = TRUE;
 				xs_pstrcat(&(tmpNode->subTunes[subEntry]->pInfo), &inLine[2]);
 			} else if (strncmp(inLine, " ARTIST:", 8) == 0) {
 				XS_STILDB_MULTI;
-				inLine[eolPos++] = '\n';
-				inLine[eolPos++] = 0;
+				isMulti = TRUE;
 				xs_pstrcat(&(tmpNode->subTunes[subEntry]->pInfo), &inLine[1]);
 			} else if (strncmp(inLine, "COMMENT:", 8) == 0) {
 				XS_STILDB_MULTI;
--- a/src/xs_title.c	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_title.c	Thu Jun 01 02:18:02 2006 +0000
@@ -43,36 +43,41 @@
 }
 
 
-gchar *xs_make_titlestring(gchar * pcFilename, gint iSubTune, gint nSubTunes, gint iSidModel,
-			   const gchar * formatString, const gchar * infoString0,
-			   const gchar * infoString1, const gchar * infoString2)
+gchar *xs_make_titlestring(t_xs_tuneinfo *p, gint subTune)
 {
-	gchar *tmpFilename, *tmpFilePath, *tmpFileExt, *pcStr,
-		*pcResult, tmpStr[XS_BUF_SIZE], tmpBuf[XS_BUF_SIZE];
+	gchar *tmpFilename, *tmpFilePath, *tmpFileExt, *pcStr, *pcResult,
+		tmpStr[XS_BUF_SIZE], tmpBuf[XS_BUF_SIZE];
+	t_xs_subtuneinfo *subInfo;
 	gint iIndex;
 #ifdef HAVE_XMMSEXTRA
 	TitleInput *ptInput;
 #endif
 
 	/* Split the filename into path */
-	tmpFilePath = g_strdup(pcFilename);
+	tmpFilePath = g_strdup(p->sidFilename);
 	tmpFilename = xs_strrchr(tmpFilePath, '/');
 	if (tmpFilename)
 		tmpFilename[1] = 0;
 
 	/* Filename */
-	tmpFilename = xs_strrchr(pcFilename, '/');
+	tmpFilename = xs_strrchr(p->sidFilename, '/');
 	if (tmpFilename)
 		tmpFilename = g_strdup(tmpFilename + 1);
 	else
-		tmpFilename = g_strdup(pcFilename);
+		tmpFilename = g_strdup(p->sidFilename);
 
 	tmpFileExt = xs_strrchr(tmpFilename, '.');
 	tmpFileExt[0] = 0;
 
 	/* Extension */
-	tmpFileExt = xs_strrchr(pcFilename, '.');
+	tmpFileExt = xs_strrchr(p->sidFilename, '.');
+
 
+	/* Get sub-tune information */
+	if ((subTune >= 0) && (subTune < p->nsubTunes)) {
+		subInfo = &(p->subTunes[subTune]);
+	} else
+		subInfo = NULL;
 
 #ifdef HAVE_XMMSEXTRA
 	/* Check if the titles are overridden or not */
@@ -90,25 +95,20 @@
 		ptInput->file_ext = tmpFileExt;
 		ptInput->file_path = tmpFilePath;
 
-		ptInput->track_name = g_strdup(infoString0);
-		ptInput->track_number = iSubTune;
+		ptInput->track_name = p->sidName;
+		ptInput->track_number = subTune + 1;
 		ptInput->album_name = NULL;
-		ptInput->performer = g_strdup(infoString1);
-		ptInput->date = g_strdup((iSidModel == XS_SIDMODEL_6581) ? "SID6581" : "SID8580");
+		ptInput->performer = p->sidComposer;
+		ptInput->date = (p->sidModel == XS_SIDMODEL_6581) ? "SID6581" : "SID8580";
 
 		ptInput->year = 0;
-		ptInput->genre = g_strdup("SID-tune");
-		ptInput->comment = g_strdup(infoString2);
+		ptInput->genre = "SID-tune";
+		ptInput->comment = p->sidCopyright;
 
 		/* Create the string */
 		pcResult = xmms_get_titlestring(xmms_get_gentitle_format(), ptInput);
 
 		/* Dispose all allocated memory */
-		g_free(ptInput->track_name);
-		g_free(ptInput->performer);
-		g_free(ptInput->comment);
-		g_free(ptInput->date);
-		g_free(ptInput->genre);
 		g_free(ptInput);
 	} else
 #endif
@@ -133,19 +133,19 @@
 					VPUTSTR(tmpFileExt);
 					break;
 				case 'p':
-					VPUTSTR(infoString1);
+					VPUTSTR(p->sidComposer);
 					break;
 				case 't':
-					VPUTSTR(infoString0);
+					VPUTSTR(p->sidName);
 					break;
 				case 'c':
-					VPUTSTR(infoString2);
+					VPUTSTR(p->sidCopyright);
 					break;
 				case 's':
-					VPUTSTR(formatString);
+					VPUTSTR(p->sidFormat);
 					break;
 				case 'm':
-					switch (iSidModel) {
+					switch (p->sidModel) {
 					case XS_SIDMODEL_6581:
 						VPUTSTR("6581");
 						break;
@@ -153,16 +153,24 @@
 						VPUTSTR("8580");
 						break;
 					default:
-						VPUTSTR("Unknown");
+						VPUTSTR("?");
 						break;
 					}
 					break;
+				case 'S':
+					if (subInfo && (subInfo->tuneSpeed > 0)) {
+						g_snprintf(tmpStr, XS_BUF_SIZE,
+							"%i", subInfo->tuneSpeed);
+						VPUTSTR(tmpStr);
+					} else
+						VPUTSTR("?");
+					break;
 				case 'n':
-					snprintf(tmpStr, XS_BUF_SIZE, "%i", iSubTune);
+					g_snprintf(tmpStr, XS_BUF_SIZE, "%i", subTune + 1);
 					VPUTSTR(tmpStr);
 					break;
 				case 'N':
-					snprintf(tmpStr, XS_BUF_SIZE, "%i", nSubTunes);
+					g_snprintf(tmpStr, XS_BUF_SIZE, "%i", p->nsubTunes);
 					VPUTSTR(tmpStr);
 					break;
 				}
--- a/src/xs_title.h	Wed May 31 22:52:00 2006 +0000
+++ b/src/xs_title.h	Thu Jun 01 02:18:02 2006 +0000
@@ -10,7 +10,7 @@
 /*
  * Functions
  */
-gchar *xs_make_titlestring(gchar *, gint, gint, gint, const gchar *, const gchar *, const gchar *, const gchar *);
+gchar *xs_make_titlestring(t_xs_tuneinfo *, gint);
 
 #ifdef __cplusplus
 }