view src/sid/xs_config.c @ 2284:d19b53359b24

cleaned up the sndfile wav plugin, currently limiting it ONLY TO WAV PLAYBACK. if somebody is more experienced with it and wants to restore the other formats, go ahead (maybe change the name of the plugin too?).
author mf0102 <0102@gmx.at>
date Wed, 09 Jan 2008 15:41:22 +0100
parents e5401b6c4665
children 59e8f118ad34
line wrap: on
line source

/*  
   XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS)

   Configuration dialog
   
   Programmed and designed by Matti 'ccr' Hamalainen <ccr@tnsp.org>
   (C) Copyright 1999-2007 Tecnic Software productions (TNSP)
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "xs_config.h"

#ifdef AUDACIOUS_PLUGIN
#include <audacious/plugin.h>
#define XS_CONFIG_FILE		ConfigDb
#define XS_CONFIG_OPEN		aud_cfg_db_open
#define XS_CONFIG_FREE		aud_cfg_db_close

#define XS_CFG_SET_STRING	aud_cfg_db_set_string
#define XS_CFG_SET_FLOAT	aud_cfg_db_set_float
#define XS_CFG_SET_INT		aud_cfg_db_set_int
#define XS_CFG_SET_BOOL		aud_cfg_db_set_bool
#define XS_CFG_GET_STRING	aud_cfg_db_get_string
#define XS_CFG_GET_FLOAT	aud_cfg_db_get_float
#define XS_CFG_GET_INT		aud_cfg_db_get_int
#define XS_CFG_GET_BOOL		aud_cfg_db_get_bool
#else
#include <xmms/configfile.h>
#define XS_CONFIG_FILE		ConfigFile
#define XS_CONFIG_OPEN		xmms_cfg_open_default_file
#define XS_CONFIG_FREE		xmms_cfg_free

#define XS_CFG_SET_STRING	xmms_cfg_write_string
#define XS_CFG_SET_FLOAT	xmms_cfg_write_float
#define XS_CFG_SET_INT		xmms_cfg_write_int
#define XS_CFG_SET_BOOL		xmms_cfg_write_boolean
#define XS_CFG_GET_STRING	xmms_cfg_read_string
#define XS_CFG_GET_FLOAT	xmms_cfg_read_float
#define XS_CFG_GET_INT		xmms_cfg_read_int
#define XS_CFG_GET_BOOL		xmms_cfg_read_boolean
#endif
#include <stdio.h>
#include <ctype.h>
#include "xs_glade.h"
#include "xs_interface.h"
#include "xs_support.h"


/*
 * Global widgets
 */
static GtkWidget *xs_configwin = NULL,
	*xs_sldb_fileselector = NULL,
	*xs_stil_fileselector = NULL,
	*xs_hvsc_selector = NULL,
	*xs_filt_importselector = NULL,
	*xs_filt_exportselector = NULL;

#define LUW(x)	lookup_widget(xs_configwin, x)

/* Samplerates
 */
static const gchar *xs_samplerates_table[] = {
	"8000", "11025", "22050", 
	"44100", "48000", "64000",
	"96000"
};

static const gint xs_nsamplerates_table = (sizeof(xs_samplerates_table) / sizeof(xs_samplerates_table[0]));

/*
 * Configuration specific stuff
 */
XS_MUTEX(xs_cfg);
struct t_xs_cfg xs_cfg;

static t_xs_cfg_item xs_cfgtable[] = {
{ CTYPE_INT,	&xs_cfg.audioBitsPerSample,	"audioBitsPerSample" },
{ CTYPE_INT,	&xs_cfg.audioChannels,		"audioChannels" },
{ CTYPE_INT,	&xs_cfg.audioFrequency,		"audioFrequency" },

{ CTYPE_BOOL,	&xs_cfg.mos8580,		"mos8580" },
{ CTYPE_BOOL,	&xs_cfg.forceModel,		"forceModel" },
{ CTYPE_BOOL,	&xs_cfg.emulateFilters,		"emulateFilters" },
{ CTYPE_FLOAT,	&xs_cfg.sid1FilterFs,		"filterFs" },
{ CTYPE_FLOAT,	&xs_cfg.sid1FilterFm,		"filterFm" },
{ CTYPE_FLOAT,	&xs_cfg.sid1FilterFt,		"filterFt" },
{ CTYPE_INT,	&xs_cfg.memoryMode,		"memoryMode" },
{ CTYPE_INT,	&xs_cfg.clockSpeed,		"clockSpeed" },
{ CTYPE_BOOL,	&xs_cfg.forceSpeed,		"forceSpeed" },

{ CTYPE_INT,	&xs_cfg.playerEngine,		"playerEngine" },

{ CTYPE_INT,	&xs_cfg.sid2Builder,		"sid2Builder" },
{ CTYPE_INT,	&xs_cfg.sid2OptLevel,		"sid2OptLevel" },
{ CTYPE_INT,	&xs_cfg.sid2NFilterPresets,	"sid2NFilterPresets" },

{ CTYPE_BOOL,	&xs_cfg.oversampleEnable,	"oversampleEnable" },
{ CTYPE_INT,	&xs_cfg.oversampleFactor,	"oversampleFactor" },

{ CTYPE_BOOL,	&xs_cfg.playMaxTimeEnable,	"playMaxTimeEnable" },
{ CTYPE_BOOL,	&xs_cfg.playMaxTimeUnknown,	"playMaxTimeUnknown" },
{ CTYPE_INT,	&xs_cfg.playMaxTime,		"playMaxTime" },
{ CTYPE_BOOL,	&xs_cfg.playMinTimeEnable,	"playMinTimeEnable" },
{ CTYPE_INT,	&xs_cfg.playMinTime,		"playMinTime" },
{ CTYPE_BOOL,	&xs_cfg.songlenDBEnable,	"songlenDBEnable" },
{ CTYPE_STR,	&xs_cfg.songlenDBPath,		"songlenDBPath" },

{ CTYPE_BOOL,	&xs_cfg.stilDBEnable,		"stilDBEnable" },
{ CTYPE_STR,	&xs_cfg.stilDBPath,		"stilDBPath" },
{ CTYPE_STR,	&xs_cfg.hvscPath,		"hvscPath" },

#ifndef AUDACIOUS_PLUGIN
{ CTYPE_INT,	&xs_cfg.subsongControl,		"subsongControl" },
{ CTYPE_BOOL,	&xs_cfg.detectMagic,		"detectMagic" },
#endif

{ CTYPE_BOOL,	&xs_cfg.titleOverride,		"titleOverride" },
{ CTYPE_STR,	&xs_cfg.titleFormat,		"titleFormat" },

{ CTYPE_BOOL,	&xs_cfg.subAutoEnable,		"subAutoEnable" },
{ CTYPE_BOOL,	&xs_cfg.subAutoMinOnly,		"subAutoMinOnly" },
{ CTYPE_INT,	&xs_cfg.subAutoMinTime,		"subAutoMinTime" },
};

static const gint xs_cfgtable_max = (sizeof(xs_cfgtable) / sizeof(t_xs_cfg_item));


static t_xs_wid_item xs_widtable[] = {
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_res_16bit",	&xs_cfg.audioBitsPerSample,	XS_RES_16BIT },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_res_8bit",		&xs_cfg.audioBitsPerSample,	XS_RES_8BIT },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_chn_mono",		&xs_cfg.audioChannels,		XS_CHN_MONO },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_chn_stereo",	&xs_cfg.audioChannels,		XS_CHN_STEREO },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_chn_autopan",	&xs_cfg.audioChannels,		XS_CHN_AUTOPAN },
{ WTYPE_COMBO,	CTYPE_INT,	"cfg_samplerate",	&xs_cfg.audioFrequency,		XS_AUDIO_FREQ },
{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_oversample",	&xs_cfg.oversampleEnable,	0 },
{ WTYPE_SPIN,	CTYPE_INT,	"cfg_oversample_factor",&xs_cfg.oversampleFactor,	0 },

{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_sidplay1",	&xs_cfg.playerEngine,		XS_ENG_SIDPLAY1 },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_sidplay2",	&xs_cfg.playerEngine,		XS_ENG_SIDPLAY2 },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_mem_real",	&xs_cfg.memoryMode,		XS_MPU_REAL },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_mem_banksw",	&xs_cfg.memoryMode,		XS_MPU_BANK_SWITCHING },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_mem_transrom",	&xs_cfg.memoryMode,		XS_MPU_TRANSPARENT_ROM },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_mem_playsid",	&xs_cfg.memoryMode,		XS_MPU_PLAYSID_ENVIRONMENT },

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_mos8580",	&xs_cfg.mos8580,		0 },
{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_sid_force",	&xs_cfg.forceModel,		0 },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_clock_ntsc",	&xs_cfg.clockSpeed,		XS_CLOCK_NTSC },
{ 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_sp2_opt",	&xs_cfg.sid2OptLevel,		0 },

{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_sp2_resid",	&xs_cfg.sid2Builder,		XS_BLD_RESID },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_emu_sp2_hardsid",	&xs_cfg.sid2Builder,		XS_BLD_HARDSID },

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_emu_filters",	&xs_cfg.emulateFilters,		0 },
{ WTYPE_SCALE,	CTYPE_FLOAT,	"cfg_sp1_filter_fs",	&xs_cfg.sid1FilterFs,		0 },
{ WTYPE_SCALE,	CTYPE_FLOAT,	"cfg_sp1_filter_fm",	&xs_cfg.sid1FilterFm,		0 },
{ WTYPE_SCALE,	CTYPE_FLOAT,	"cfg_sp1_filter_ft",	&xs_cfg.sid1FilterFt,		0 },

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_maxtime_enable",	&xs_cfg.playMaxTimeEnable,	0 },
{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_maxtime_unknown",	&xs_cfg.playMaxTimeUnknown,	0 },
{ WTYPE_SPIN,	CTYPE_INT,	"cfg_maxtime",		&xs_cfg.playMaxTime,		0 },
{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_mintime_enable",	&xs_cfg.playMinTimeEnable,	0 },
{ WTYPE_SPIN,	CTYPE_INT,	"cfg_mintime",		&xs_cfg.playMinTime,		0 },
{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_sld_enable",	&xs_cfg.songlenDBEnable,	0 },
{ WTYPE_TEXT,	CTYPE_STR,	"cfg_sld_dbpath",	&xs_cfg.songlenDBPath,		0 },

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_stil_enable",	&xs_cfg.stilDBEnable,		0 },
{ WTYPE_TEXT,	CTYPE_STR,	"cfg_stil_dbpath",	&xs_cfg.stilDBPath,		0 },
{ WTYPE_TEXT,	CTYPE_STR,	"cfg_hvsc_path",	&xs_cfg.hvscPath,		0 },

#ifndef AUDACIOUS_PLUGIN
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_subctrl_none",	&xs_cfg.subsongControl,		XS_SSC_NONE },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_subctrl_seek",	&xs_cfg.subsongControl,		XS_SSC_SEEK },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_subctrl_popup",	&xs_cfg.subsongControl,		XS_SSC_POPUP },
{ WTYPE_BGROUP,	CTYPE_INT,	"cfg_subctrl_patch",	&xs_cfg.subsongControl,		XS_SSC_PATCH },

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_detectmagic",	&xs_cfg.detectMagic,		0 },
#endif

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_ftitle_override",	&xs_cfg.titleOverride,		0 },
{ WTYPE_TEXT,	CTYPE_STR,	"cfg_ftitle_format",	&xs_cfg.titleFormat,		0 },

{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_subauto_enable",	&xs_cfg.subAutoEnable,		0 },
{ WTYPE_BUTTON,	CTYPE_BOOL,	"cfg_subauto_min_only",	&xs_cfg.subAutoMinOnly,		0 },
{ WTYPE_SPIN,	CTYPE_INT,	"cfg_subauto_mintime",	&xs_cfg.subAutoMinTime,		0 },
};

static const gint xs_widtable_max = (sizeof(xs_widtable) / sizeof(t_xs_wid_item));


/* Reset/initialize the configuration
 */
void xs_init_configuration(void)
{
	/* Lock configuration mutex */
	XSDEBUG("initializing configuration ...\n");
	XS_MUTEX_LOCK(xs_cfg);

	xs_memset(&xs_cfg, 0, sizeof(xs_cfg));
	
	/* Initialize values with sensible defaults */
	xs_cfg.audioBitsPerSample = XS_RES_16BIT;
	xs_cfg.audioChannels = XS_CHN_MONO;
	xs_cfg.audioFrequency = XS_AUDIO_FREQ;

	xs_cfg.mos8580 = FALSE;
	xs_cfg.forceModel = FALSE;

	/* Filter values */
	xs_cfg.emulateFilters = TRUE;
	xs_cfg.sid1FilterFs = XS_SIDPLAY1_FS;
	xs_cfg.sid1FilterFm = XS_SIDPLAY1_FM;
	xs_cfg.sid1FilterFt = XS_SIDPLAY1_FT;

#ifdef HAVE_SIDPLAY2
	xs_cfg.playerEngine = XS_ENG_SIDPLAY2;
	xs_cfg.memoryMode = XS_MPU_REAL;
#else
#ifdef HAVE_SIDPLAY1
	xs_cfg.playerEngine = XS_ENG_SIDPLAY1;
	xs_cfg.memoryMode = XS_MPU_BANK_SWITCHING;
#else
#error This should not happen! No emulator engines configured in!
#endif
#endif

	xs_cfg.clockSpeed = XS_CLOCK_PAL;
	xs_cfg.forceSpeed = FALSE;

	xs_cfg.sid2OptLevel = 0;
	xs_cfg.sid2NFilterPresets = 0;

#ifdef HAVE_RESID_BUILDER
	xs_cfg.sid2Builder = XS_BLD_RESID;
#else
#ifdef HAVE_HARDSID_BUILDER
	xs_cfg.sid2Builder = XS_BLD_HARDSID;
#else
#ifdef HAVE_SIDPLAY2
#error This should not happen! No supported SIDPlay2 builders configured in!
#endif
#endif
#endif

	xs_cfg.oversampleEnable = FALSE;
	xs_cfg.oversampleFactor = XS_MIN_OVERSAMPLE;

	xs_cfg.playMaxTimeEnable = FALSE;
	xs_cfg.playMaxTimeUnknown = FALSE;
	xs_cfg.playMaxTime = 150;

	xs_cfg.playMinTimeEnable = FALSE;
	xs_cfg.playMinTime = 15;

	xs_cfg.songlenDBEnable = FALSE;
	xs_pstrcpy(&xs_cfg.songlenDBPath, "~/C64Music/Songlengths.txt");

	xs_cfg.stilDBEnable = FALSE;
	xs_pstrcpy(&xs_cfg.stilDBPath, "~/C64Music/DOCUMENTS/STIL.txt");
	xs_pstrcpy(&xs_cfg.hvscPath, "~/C64Music");

#if defined(HAVE_SONG_POSITION) && !defined(AUDACIOUS_PLUGIN)
	xs_cfg.subsongControl = XS_SSC_PATCH;
#else
	xs_cfg.subsongControl = XS_SSC_POPUP;
#endif
	xs_cfg.detectMagic = FALSE;

#ifndef HAVE_XMMSEXTRA
	xs_cfg.titleOverride = TRUE;
#endif

#ifdef AUDACIOUS_PLUGIN
	xs_pstrcpy(&xs_cfg.titleFormat, "${artist} - ${title} (${copyright}) <${subsong-id}/${subsong-num}> [${sid-model}/${sid-speed}]");
#else
	xs_pstrcpy(&xs_cfg.titleFormat, "%p - %t (%c) <%n/%N> [%m/%C]");
#endif

	xs_cfg.subAutoEnable = FALSE;
	xs_cfg.subAutoMinOnly = TRUE;
	xs_cfg.subAutoMinTime = 15;


	/* Unlock the configuration */
	XS_MUTEX_UNLOCK(xs_cfg);
}


/* Filter configuration handling
 */
#define XS_FITEM (4 * 2)

static gboolean xs_filter_load_into(XS_CONFIG_FILE *cfg, gint nFilter, t_xs_sid2_filter *pResult)
{
	gchar tmpKey[64], *tmpStr;
	gint i, j;

	/* Get fields from config */
	g_snprintf(tmpKey, sizeof(tmpKey), "filter%dNPoints", nFilter);
	if (!XS_CFG_GET_INT(cfg, XS_CONFIG_IDENT, tmpKey, &(pResult->npoints)))
		return FALSE;
	
	g_snprintf(tmpKey, sizeof(tmpKey), "filter%dName", nFilter);
	if (!XS_CFG_GET_STRING(cfg, XS_CONFIG_IDENT, tmpKey, &tmpStr))
		return FALSE;
	
	pResult->name = g_strdup(tmpStr);
	if (pResult->name == NULL) {
		g_free(pResult);
		return FALSE;
	}
	
	g_snprintf(tmpKey, sizeof(tmpKey), "filter%dPoints", nFilter);
	if (!XS_CFG_GET_STRING(cfg, XS_CONFIG_IDENT, tmpKey, &tmpStr))
		return FALSE;
	
	for (i = 0, j = 0; i < pResult->npoints; i++, j += XS_FITEM) {
		if (sscanf(&tmpStr[j], "%4x%4x",
			&(pResult->points[i].x),
			&(pResult->points[i].y)) != 2)
			return FALSE;
	}
	
	return TRUE;
}


static t_xs_sid2_filter * xs_filter_load(XS_CONFIG_FILE *cfg, gint nFilter)
{
	t_xs_sid2_filter *pResult;
	
	/* Allocate filter struct */
	if ((pResult = g_malloc0(sizeof(t_xs_sid2_filter))) == NULL)
		return NULL;
	
	if (!xs_filter_load_into(cfg, nFilter, pResult)) {
		g_free(pResult);
		return NULL;
	} else
		return pResult;
}

#if 0
static gboolean xs_filter_save(XS_CONFIG_FILE *cfg, t_xs_sid2_filter *pFilter, gint nFilter)
{
	gchar *tmpValue, tmpKey[64];
	gint i, j;
	
	/* Allocate memory for value string */
	tmpValue = g_malloc(sizeof(gchar) * XS_FITEM * (pFilter->npoints + 1));
	if (tmpValue == NULL)
		return FALSE;
	
	/* Make value string */
	for (i = 0, j = 0; i < pFilter->npoints; i++, j += XS_FITEM) {
		g_snprintf(&tmpValue[j], XS_FITEM+1, "%04x%04x",
			pFilter->points[i].x,
			pFilter->points[i].y);
	}
	
	/* Write into the configuration */
	g_snprintf(tmpKey, sizeof(tmpKey), "filter%dName", nFilter);
	XS_CFG_SET_STRING(cfg, XS_CONFIG_IDENT, tmpKey, pFilter->name);
	
	g_snprintf(tmpKey, sizeof(tmpKey), "filter%dNPoints", nFilter);
	XS_CFG_SET_INT(cfg, XS_CONFIG_IDENT, tmpKey, pFilter->npoints);

	g_snprintf(tmpKey, sizeof(tmpKey), "filter%dPoints", nFilter);
	XS_CFG_SET_STRING(cfg, XS_CONFIG_IDENT, tmpKey, tmpValue);
	
	g_free(tmpValue);
	return TRUE;
}
#endif

/* Filter exporting and importing. These functions export/import
 * filter settings to/from SIDPlay2 INI-type files.
 */
static gboolean xs_fgetitem(gchar *inLine, size_t *linePos, gchar sep, gchar *tmpStr, size_t tmpMax)
{
	size_t i;
	for (i = 0; i < tmpMax && inLine[*linePos] &&
		!isspace(inLine[*linePos]) &&
		inLine[*linePos] != sep; i++, (*linePos)++)
		tmpStr[i] = inLine[*linePos];
	tmpStr[i] = 0;
	xs_findnext(inLine, linePos);
	return (inLine[*linePos] == sep);
}

static gboolean xs_filters_import(const gchar *pcFilename, t_xs_sid2_filter **pFilters, gint *nFilters)
{
	FILE *inFile;
	gchar inLine[XS_BUF_SIZE], tmpStr[XS_BUF_SIZE];
	gchar *sectName = NULL;
	gboolean sectBegin;
	size_t lineNum, i;
	t_xs_sid2_filter *tmpFilter;

fprintf(stderr, "xs_filters_import(%s)\n", pcFilename);

	if ((inFile = fopen(pcFilename, "ra")) == NULL)
		return FALSE;

fprintf(stderr, "importing...\n");
	
	sectBegin = FALSE;
	lineNum = 0;
	while (fgets(inLine, XS_BUF_SIZE, inFile) != NULL) {
		size_t linePos = 0;
		lineNum++;
		
		xs_findnext(inLine, &linePos);
		if (isalpha(inLine[linePos]) && sectBegin) {
			/* A new key/value pair */
			if (!xs_fgetitem(inLine, &linePos, '=', tmpStr, XS_BUF_SIZE)) {
				fprintf(stderr, "invalid line: %s [expect =']'", inLine);
			} else {
				linePos++;
				xs_findnext(inLine, &linePos);
				if (!strncmp(tmpStr, "points", 6)) {
					fprintf(stderr, "points=%s\n", &inLine[linePos]);
				} else if (!strncmp(tmpStr, "point", 5)) {
				} else if (!strncmp(tmpStr, "type", 4)) {
				} else {
					fprintf(stderr, "warning: ukn def: %s @ %s\n",
						tmpStr, sectName);
				}
			}
		} else if (inLine[linePos] == '[') {
			/* Check for existing section */
			if (sectBegin) {
				/* Submit definition */
				fprintf(stderr, "filter ends: %s\n", sectName);
				if ((tmpFilter = g_malloc0(sizeof(t_xs_sid2_filter))) == NULL) {
					fprintf(stderr, "could not allocate ..\n");
				} else {
					
				}
				g_free(sectName);
			}
			
			/* New filter(?) section starts */
			linePos++;
			for (i = 0; i < XS_BUF_SIZE && inLine[linePos] && inLine[linePos] != ']'; i++, linePos++)
				tmpStr[i] = inLine[linePos];
			tmpStr[i] = 0;
			
			if (inLine[linePos] != ']') {
				fprintf(stderr, "invalid! expected ']': %s\n", inLine);
			} else {
				sectName = strdup(tmpStr);
				fprintf(stderr, "filter: %s\n", sectName);
				sectBegin = TRUE;
			}
		} else if ((inLine[linePos] != ';') && (inLine[linePos] != 0)) {
			/* Syntax error */
			fprintf(stderr, "syntax error: %s\n", inLine);
		}
	}
	
	fclose(inFile);
	return TRUE;
}


static gboolean xs_filters_export(const gchar *pcFilename, t_xs_sid2_filter **pFilters, gint nFilters)
{
	FILE *outFile;
	t_xs_sid2_filter *f;
	gint n;
	
	/* Open/create the file */
	if ((outFile = fopen(pcFilename, "wa")) == NULL)
		return FALSE;
	
	/* Header */
	fprintf(outFile,
		"; SIDPlay2 compatible filter definition file\n"
		"; Exported by " PACKAGE_STRING "\n\n");
	
	/* Write each filter spec in "INI"-style format */
	for (n = 0; n < nFilters; n++) {
		gint i;
		f = pFilters[n];
		
		fprintf(outFile,
		"[%s]\n"
		"type=1\n"
		"points=%d\n",
		f->name, f->npoints);
	
		for (i = 0; i < f->npoints; i++) {
			fprintf(outFile,
			"point%d=%d,%d\n",
			i + 1,
			f->points[i].x,
			f->points[i].y);
		}
	
		fprintf(outFile, "\n");
		f++;
	}
	
	fclose(outFile);
	return TRUE;
}

/* Get the configuration (from file or default)
 */
void xs_read_configuration(void)
{
	XS_CONFIG_FILE *cfg;
	gint i;
	gchar *tmpStr;

	/* Try to open the XMMS configuration file  */
	XS_MUTEX_LOCK(xs_cfg);
	XSDEBUG("loading from config-file ...\n");

	cfg = XS_CONFIG_OPEN();

	if (cfg == NULL) {
		XSDEBUG("Could not open configuration, trying to write defaults...\n");
		xs_write_configuration();
		return;
	}

	/* Read the new settings from XMMS configuration file */
	for (i = 0; i < xs_cfgtable_max; i++) {
		switch (xs_cfgtable[i].itemType) {
		case CTYPE_INT:
			XS_CFG_GET_INT(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				(gint *) xs_cfgtable[i].itemData);
			break;

		case CTYPE_BOOL:
			XS_CFG_GET_BOOL(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				(gboolean *) xs_cfgtable[i].itemData);
			break;

		case CTYPE_FLOAT:
			XS_CFG_GET_FLOAT(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				(gfloat *) xs_cfgtable[i].itemData);
			break;
		
		case CTYPE_STR:
			if (XS_CFG_GET_STRING(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName, (gchar **) &tmpStr)) {
				xs_pstrcpy((gchar **) xs_cfgtable[i].itemData, tmpStr);
				g_free(tmpStr);
			}
			break;
		}
	}
	
	/* Filters and presets are a special case */
	xs_filter_load_into(cfg, 0, &xs_cfg.sid2Filter);
	
	if (xs_cfg.sid2NFilterPresets > 0) {
		xs_cfg.sid2FilterPresets = g_malloc0(xs_cfg.sid2NFilterPresets * sizeof(t_xs_sid2_filter *));
		if (!xs_cfg.sid2FilterPresets) {
			xs_error(_("Allocation of sid2FilterPresets structure failed!\n"));
		} else {
			for (i = 0; i < xs_cfg.sid2NFilterPresets; i++) {
				xs_cfg.sid2FilterPresets[i] = xs_filter_load(cfg, i);
			}
		}
	}

	XS_CONFIG_FREE(cfg);

	XS_MUTEX_UNLOCK(xs_cfg);
	XSDEBUG("OK\n");
}


/* Write the current configuration
 */
gint xs_write_configuration(void)
{
	XS_CONFIG_FILE *cfg;
	gint i;

	XSDEBUG("writing configuration ...\n");
	XS_MUTEX_LOCK(xs_cfg);

	/* Try to open the XMMS configuration file  */
	cfg = XS_CONFIG_OPEN();

#ifndef AUDACIOUS_PLUGIN
	if (!cfg) cfg = xmms_cfg_new();
	if (!cfg) return -1;
#endif

	/* Write the new settings to XMMS configuration file */
	for (i = 0; i < xs_cfgtable_max; i++) {
		switch (xs_cfgtable[i].itemType) {
		case CTYPE_INT:
			XS_CFG_SET_INT(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				*(gint *) xs_cfgtable[i].itemData);
			break;

		case CTYPE_BOOL:
			XS_CFG_SET_BOOL(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				*(gboolean *) xs_cfgtable[i].itemData);
			break;

		case CTYPE_FLOAT:
			XS_CFG_SET_FLOAT(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				*(gfloat *) xs_cfgtable[i].itemData);
			break;

		case CTYPE_STR:
			XS_CFG_SET_STRING(cfg, XS_CONFIG_IDENT,
				xs_cfgtable[i].itemName,
				*(gchar **) xs_cfgtable[i].itemData);
			break;
		}
	}


#ifndef AUDACIOUS_PLUGIN
	xmms_cfg_write_default_file(cfg);
#endif
	XS_CONFIG_FREE(cfg);

	XS_MUTEX_UNLOCK(xs_cfg);

	return 0;
}


/* Configuration panel was canceled
 */
XS_DEF_WINDOW_CLOSE(cfg_cancel, configwin)


/* Configuration was accepted, save the settings
 */
void xs_cfg_ok(void)
{
	gint i;
	gfloat tmpValue;
	gint tmpInt;
	const gchar *tmpStr;

	/* Get lock on configuration */
	XS_MUTEX_LOCK(xs_cfg);

	XSDEBUG("get data from widgets to config...\n");

	for (i = 0; i < xs_widtable_max; i++) {
		switch (xs_widtable[i].widType) {
		case WTYPE_BGROUP:
			/* Check if toggle-button is active */
			if (GTK_TOGGLE_BUTTON(LUW(xs_widtable[i].widName))->active) {
				/* Yes, set the constant value */
				*((gint *) xs_widtable[i].itemData) = xs_widtable[i].itemSet;
			}
			break;

		case WTYPE_COMBO:
			/* Get text from text-widget */
			tmpStr = gtk_entry_get_text(GTK_ENTRY(LUW(xs_widtable[i].widName)));
			if (sscanf(tmpStr, "%d", &tmpInt) != 1)
				tmpInt = xs_widtable[i].itemSet;

			*((gint *) xs_widtable[i].itemData) = tmpInt;
			break;
			
		case WTYPE_SPIN:
		case WTYPE_SCALE:
			/* Get the value */
			switch (xs_widtable[i].widType) {
			case WTYPE_SPIN:
				tmpValue = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(LUW(xs_widtable[i].widName)))->value;
				break;

			case WTYPE_SCALE:
				tmpValue = gtk_range_get_adjustment(GTK_RANGE(LUW(xs_widtable[i].widName)))->value;
				break;
			
			default:
				tmpValue = -1;
				break;
			}

			/* Set the value */
			switch (xs_widtable[i].itemType) {
			case CTYPE_INT:
				*((gint *) xs_widtable[i].itemData) = (gint) tmpValue;
				break;

			case CTYPE_FLOAT:
				*((gfloat *) xs_widtable[i].itemData) = tmpValue;
				break;
			}
			break;

		case WTYPE_BUTTON:
			/* Check if toggle-button is active */
			*((gboolean *) xs_widtable[i].itemData) =
				(GTK_TOGGLE_BUTTON(LUW(xs_widtable[i].widName))->active);
			break;

		case WTYPE_TEXT:
			/* Get text from text-widget */
			xs_pstrcpy((gchar **) xs_widtable[i].itemData,
				gtk_entry_get_text(GTK_ENTRY(LUW(xs_widtable[i].widName))));
			break;
		}
	}
	
	/* Get filter settings */
	/*
	if (!xs_curve_get_points(XS_CURVE(LUW("")), &xs_cfg.sid2Filter.points, &xs_cfg.sid2Filter.npoints)) {
		xs_error(_("Warning: Could not get filter curve widget points!\n"));
	}
	*/

	/* Release lock */
	XS_MUTEX_UNLOCK(xs_cfg);
	
	/* Close window */
	gtk_widget_destroy(xs_configwin);
	xs_configwin = NULL;

	/* Write settings */
	xs_write_configuration();

	/* Re-initialize */
	xs_reinit();
}


/* Confirmation window
 */
gboolean xs_confirmwin_delete(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	(void) widget;
	(void) event;
	(void) user_data;
	
	return FALSE;
}



/* HVSC songlength-database file selector response-functions
 */
void xs_cfg_sldb_browse(GtkButton * button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	if (xs_sldb_fileselector != NULL) {
                gtk_window_present(GTK_WINDOW(xs_sldb_fileselector));
		return;
	}

	xs_sldb_fileselector = create_xs_sldb_fs();
	XS_MUTEX_LOCK(xs_cfg);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(xs_sldb_fileselector), xs_cfg.songlenDBPath);
	XS_MUTEX_UNLOCK(xs_cfg);
	gtk_widget_show(xs_sldb_fileselector);
}


void xs_sldb_fs_ok(GtkButton *button, gpointer user_data)
{
	(void) button;
	(void) user_data;
	
	/* Selection was accepted! */
	gtk_entry_set_text(GTK_ENTRY(LUW("cfg_sld_dbpath")),
			   gtk_file_selection_get_filename(GTK_FILE_SELECTION(xs_sldb_fileselector)));

	/* Close file selector window */
	gtk_widget_destroy(xs_sldb_fileselector);
	xs_sldb_fileselector = NULL;
}

XS_DEF_WINDOW_CLOSE(sldb_fs_cancel, sldb_fileselector)
XS_DEF_WINDOW_DELETE(sldb_fs, sldb_fileselector)


/* STIL-database file selector response-functions
 */
void xs_cfg_stil_browse(GtkButton * button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	if (xs_stil_fileselector != NULL) {
                gtk_window_present(GTK_WINDOW(xs_stil_fileselector));
		return;
	}

	xs_stil_fileselector = create_xs_stil_fs();
	XS_MUTEX_LOCK(xs_cfg);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(xs_stil_fileselector), xs_cfg.stilDBPath);
	XS_MUTEX_UNLOCK(xs_cfg);
	gtk_widget_show(xs_stil_fileselector);
}


void xs_stil_fs_ok(GtkButton *button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	/* Selection was accepted! */
	gtk_entry_set_text(GTK_ENTRY(LUW("cfg_stil_dbpath")),
		gtk_file_selection_get_filename(GTK_FILE_SELECTION(xs_stil_fileselector)));

	/* Close file selector window */
	gtk_widget_destroy(xs_stil_fileselector);
	xs_stil_fileselector = NULL;
}


XS_DEF_WINDOW_CLOSE(stil_fs_cancel, stil_fileselector)
XS_DEF_WINDOW_DELETE(stil_fs, stil_fileselector)


/* HVSC location selector response-functions
 */
void xs_cfg_hvsc_browse(GtkButton * button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	if (xs_hvsc_selector != NULL) {
                gtk_window_present(GTK_WINDOW(xs_hvsc_selector));
		return;
	}

	xs_hvsc_selector = create_xs_hvsc_fs();
	XS_MUTEX_LOCK(xs_cfg);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(xs_hvsc_selector), xs_cfg.hvscPath);
	XS_MUTEX_UNLOCK(xs_cfg);
	gtk_widget_show(xs_hvsc_selector);
}


void xs_hvsc_fs_ok(GtkButton *button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	/* Selection was accepted! */
	gtk_entry_set_text(GTK_ENTRY(LUW("cfg_hvsc_path")),
		gtk_file_selection_get_filename(GTK_FILE_SELECTION(xs_hvsc_selector)));

	/* Close file selector window */
	gtk_widget_destroy(xs_hvsc_selector);
	xs_hvsc_selector = NULL;
}


XS_DEF_WINDOW_CLOSE(hvsc_fs_cancel, hvsc_selector)
XS_DEF_WINDOW_DELETE(hvsc_fs, hvsc_selector)


/* Filter handling
 */
void xs_cfg_sp1_filter_reset(GtkButton * button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(LUW("cfg_sp1_filter_fs"))), XS_SIDPLAY1_FS);
	gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(LUW("cfg_sp1_filter_fm"))), XS_SIDPLAY1_FM);
	gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(LUW("cfg_sp1_filter_ft"))), XS_SIDPLAY1_FT);
}


void xs_cfg_sp2_filter_update(XSCurve *curve, t_xs_sid2_filter *f)
{
	assert(curve);
	assert(f);
	
	xs_curve_reset(curve);
	xs_curve_set_range(curve, 0,0, XS_SIDPLAY2_NFPOINTS, XS_SIDPLAY2_FMAX);
	if (!xs_curve_set_points(curve, f->points, f->npoints)) {
		// FIXME
		xs_error(_("Warning: Could not set filter curve widget points!\n"));
	}
}


void xs_cfg_sp2_presets_update(void)
{
	GList *tmpList = NULL;
	gint i;
	
	for (i = 0; i < xs_cfg.sid2NFilterPresets; i++) {
		tmpList = g_list_append(tmpList,
			(gpointer) xs_cfg.sid2FilterPresets[i]->name);
	}
	
	gtk_combo_set_popdown_strings(GTK_COMBO(LUW("cfg_sp2_filter_combo")), tmpList);
	g_list_free(tmpList);
}


void xs_cfg_sp2_filter_load(GtkButton *button, gpointer user_data)
{
	const gchar *tmpStr;
	gint i, j;
	
	(void) button;
	(void) user_data;
	
	XS_MUTEX_LOCK(xs_cfg);
	
	tmpStr = gtk_entry_get_text(GTK_ENTRY(LUW("cfg_sp2_filter_combo_entry")));
	for (i = 0, j = -1; i < xs_cfg.sid2NFilterPresets; i++) {
		if (!strcmp(tmpStr, xs_cfg.sid2FilterPresets[i]->name)) {
			j = i;
			break;
		}
	}
	
	if (j != -1) {
		fprintf(stderr, "Updating from '%s'\n", tmpStr);
		xs_cfg_sp2_filter_update(
			XS_CURVE(LUW("cfg_sp2_filter_curve")),
			xs_cfg.sid2FilterPresets[i]);
	} else {
		/* error/warning: no such filter preset */
		fprintf(stderr, "No such filter preset '%s'!\n", tmpStr);
	}
	
	XS_MUTEX_UNLOCK(xs_cfg);
}


void xs_cfg_sp2_filter_save(GtkButton *button, gpointer user_data)
{
	/*
	1) check if textentry matches any current filter name
		yes) ask if saving over ok?
		no) ...
		
	2) save current filter to the name		
	*/
	const gchar *tmpStr;
	gint i, j;
	
	(void) button;
	(void) user_data;
	
	XS_MUTEX_LOCK(xs_cfg);
	
	tmpStr = gtk_entry_get_text(GTK_ENTRY(LUW("cfg_sp2_filter_combo_entry")));
	for (i = 0, j = -1; i < xs_cfg.sid2NFilterPresets; i++) {
		if (!strcmp(tmpStr, xs_cfg.sid2FilterPresets[i]->name)) {
			j = i;
			break;
		}
	}
	
	if (j != -1) {
		fprintf(stderr, "Found, confirm overwrite?\n");
	}
	
	fprintf(stderr, "saving!\n");
	
	xs_cfg_sp2_presets_update();
	
	XS_MUTEX_UNLOCK(xs_cfg);
}


void xs_cfg_sp2_filter_delete(GtkButton *button, gpointer user_data)
{
	(void) button;
	(void) user_data;
	/*
	1) confirm
	2) delete
	*/
}


void xs_cfg_sp2_filter_import(GtkButton *button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	if (xs_filt_importselector != NULL) {
                gtk_window_present(GTK_WINDOW(xs_filt_importselector));
		return;
	}

	xs_filt_importselector = create_xs_filter_import_fs();
	gtk_widget_show(xs_filt_importselector);
}


void xs_filter_import_fs_ok(GtkButton *button, gpointer user_data)
{
	const gchar *tmpStr;
	(void) button;
	(void) user_data;
	
	XS_MUTEX_LOCK(xs_cfg);

	/* Selection was accepted! */
	tmpStr = gtk_file_selection_get_filename(GTK_FILE_SELECTION(xs_filt_importselector));
	xs_filters_import(tmpStr, xs_cfg.sid2FilterPresets, &xs_cfg.sid2NFilterPresets);
	xs_cfg_sp2_presets_update();

	/* Close file selector window */
	gtk_widget_destroy(xs_filt_importselector);
	xs_filt_importselector = NULL;
	XS_MUTEX_UNLOCK(xs_cfg);
}


XS_DEF_WINDOW_CLOSE(filter_import_fs_cancel, filt_importselector)
XS_DEF_WINDOW_DELETE(filter_import_fs, filt_importselector)


void xs_cfg_sp2_filter_export(GtkButton *button, gpointer user_data)
{
	(void) button;
	(void) user_data;

	if (xs_filt_exportselector != NULL) {
                gtk_window_present(GTK_WINDOW(xs_filt_exportselector));
		return;
	}

	xs_filt_exportselector = create_xs_filter_export_fs();
	gtk_widget_show(xs_filt_exportselector);
}


void xs_filter_export_fs_ok(GtkButton *button, gpointer user_data)
{
	const gchar *tmpStr;
	(void) button;
	(void) user_data;

	XS_MUTEX_LOCK(xs_cfg);

	/* Selection was accepted! */
	tmpStr = gtk_file_selection_get_filename(GTK_FILE_SELECTION(xs_filt_exportselector));
	xs_filters_export(tmpStr, xs_cfg.sid2FilterPresets, xs_cfg.sid2NFilterPresets);

	/* Close file selector window */
	gtk_widget_destroy(xs_filt_exportselector);
	xs_filt_exportselector = NULL;
	XS_MUTEX_UNLOCK(xs_cfg);
}


XS_DEF_WINDOW_CLOSE(filter_export_fs_cancel, filt_exportselector)
XS_DEF_WINDOW_DELETE(filter_export_fs, filt_exportselector)


/* Selection toggle handlers
 */
void xs_cfg_emu_filters_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_filters_notebook"), isActive);
}


void xs_cfg_ftitle_override_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_ftitle_box"), isActive);
}


void xs_cfg_emu_sidplay1_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	(void) togglebutton;
	(void) user_data;
}


void xs_cfg_emu_sidplay2_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_emu_mem_real"), isActive);

	gtk_widget_set_sensitive(LUW("cfg_sidplay2_frame"), isActive);
	gtk_widget_set_sensitive(LUW("cfg_emu_sp2_opt"), isActive);

	gtk_widget_set_sensitive(LUW("cfg_chn_autopan"), !isActive);

#ifdef HAVE_RESID_BUILDER
	gtk_widget_set_sensitive(LUW("cfg_emu_sp2_resid"), isActive);
#else
	gtk_widget_set_sensitive(LUW("cfg_emu_sp2_resid"), FALSE);
#endif

#ifdef HAVE_HARDSID_BUILDER
	gtk_widget_set_sensitive(LUW("cfg_emu_sp2_hardsid"), isActive);
#else
	gtk_widget_set_sensitive(LUW("cfg_emu_sp2_hardsid"), FALSE);
#endif
}


void xs_cfg_oversample_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_oversample_box"), isActive);
}


void xs_cfg_mintime_enable_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_mintime_box"), isActive);
}


void xs_cfg_maxtime_enable_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(LUW("cfg_maxtime_enable"))->active;

	(void) togglebutton;
	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_maxtime_unknown"), isActive);
	gtk_widget_set_sensitive(LUW("cfg_maxtime_box"), isActive);
}


void xs_cfg_sldb_enable_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_sld_box"), isActive);
}


void xs_cfg_stil_enable_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_stil_box1"), isActive);
	gtk_widget_set_sensitive(LUW("cfg_stil_box2"), isActive);
}


void xs_cfg_subauto_enable_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_subauto_min_only"), isActive);
	gtk_widget_set_sensitive(LUW("cfg_subauto_box"), isActive);
}


void xs_cfg_subauto_min_only_toggled(GtkToggleButton * togglebutton, gpointer user_data)
{
	gboolean isActive = GTK_TOGGLE_BUTTON(togglebutton)->active &&
		GTK_TOGGLE_BUTTON(LUW("cfg_subauto_enable"))->active;

	(void) user_data;

	gtk_widget_set_sensitive(LUW("cfg_subauto_box"), isActive);
}


void xs_cfg_mintime_changed(GtkEditable * editable, gpointer user_data)
{
	gint tmpValue;
	GtkAdjustment *tmpAdj;

	(void) user_data;

	tmpAdj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(LUW("cfg_maxtime")));

	tmpValue = (gint) gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(editable))->value;

	if (tmpValue > tmpAdj->value)
		gtk_adjustment_set_value(tmpAdj, tmpValue);
}


void xs_cfg_maxtime_changed(GtkEditable * editable, gpointer user_data)
{
	gint tmpValue;
	GtkAdjustment *tmpAdj;

	(void) user_data;

	tmpAdj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(LUW("cfg_mintime")));

	tmpValue = (gint) gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(editable))->value;

	if (tmpValue < tmpAdj->value)
		gtk_adjustment_set_value(tmpAdj, tmpValue);
}


XS_DEF_WINDOW_DELETE(configwin, configwin)


/* Execute the configuration panel
 */
void xs_configure(void)
{
	gint i;
	gfloat tmpValue;
	gchar tmpStr[64];
	GList *tmpList = NULL;
	GtkWidget *tmpCurve;

	/* Check if the window already exists */
	if (xs_configwin) {
                gtk_window_present(GTK_WINDOW(xs_configwin));
		return;
	}

	/* Create the window */
	xs_configwin = create_xs_configwin();
	
	/* Get lock on configuration */
	XS_MUTEX_LOCK(xs_cfg);

	/* Add samplerates */
	for (i = 0; i < xs_nsamplerates_table; i++) {
		tmpList = g_list_append (tmpList,
			(gpointer) xs_samplerates_table[i]);
	}
	gtk_combo_set_popdown_strings(GTK_COMBO(LUW("cfg_samplerate_combo")), tmpList);
	g_list_free(tmpList);
	
	/* Create the custom filter curve widget for libSIDPlay2 */
	xs_cfg_sp2_presets_update();
	tmpCurve = xs_curve_new();
	xs_cfg_sp2_filter_update(XS_CURVE(tmpCurve), &xs_cfg.sid2Filter);
	gtk_widget_set_name(tmpCurve, "cfg_sp2_filter_curve");
	gtk_widget_ref(tmpCurve);
	gtk_object_set_data_full(GTK_OBJECT(xs_configwin),
		"cfg_sp2_filter_curve", tmpCurve, (GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show(tmpCurve);
	gtk_container_add(GTK_CONTAINER(LUW("cfg_sp2_filter_frame")), tmpCurve);


	/* Based on available optional parts, gray out options */
#ifndef HAVE_SIDPLAY1
	gtk_widget_set_sensitive(LUW("cfg_emu_sidplay1"), FALSE);
	gtk_widget_set_sensitive(LUW("cfg_box_filter_sidplay1"), FALSE);
#endif

#ifndef HAVE_SIDPLAY2
	gtk_widget_set_sensitive(LUW("cfg_emu_sidplay2"), FALSE);
	gtk_widget_set_sensitive(LUW("cfg_box_filter_sidplay2"), FALSE);
#endif

	gtk_widget_set_sensitive(LUW("cfg_resid_frame"), FALSE);

#if !defined(HAVE_XMMSEXTRA) && !defined(AUDACIOUS_PLUGIN)
	gtk_widget_set_sensitive(LUW("cfg_ftitle_override"), FALSE);
	xs_cfg.titleOverride = TRUE;
#endif

#if !defined(HAVE_SONG_POSITION) && !defined(AUDACIOUS_PLUGIN)
	gtk_widget_set_sensitive(LUW("cfg_subctrl_patch"), FALSE);
#endif

	xs_cfg_ftitle_override_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_ftitle_override")), NULL);
	xs_cfg_emu_filters_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_emu_filters")), NULL);
	xs_cfg_emu_sidplay1_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_emu_sidplay1")), NULL);
	xs_cfg_emu_sidplay2_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_emu_sidplay2")), NULL);
	xs_cfg_oversample_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_oversample")), NULL);
	xs_cfg_mintime_enable_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_mintime_enable")), NULL);
	xs_cfg_maxtime_enable_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_maxtime_enable")), NULL);
	xs_cfg_sldb_enable_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_sld_enable")), NULL);
	xs_cfg_stil_enable_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_stil_enable")), NULL);
	xs_cfg_subauto_enable_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_subauto_enable")), NULL);
	xs_cfg_subauto_min_only_toggled(GTK_TOGGLE_BUTTON(LUW("cfg_subauto_min_only")), NULL);


	/* Set current data to widgets */
	for (i = 0; i < xs_widtable_max; i++) {
		switch (xs_widtable[i].widType) {
		case WTYPE_BGROUP:
			assert(xs_widtable[i].itemType == CTYPE_INT);
			/* Check if current value matches the given one */
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(LUW(xs_widtable[i].widName)),
				(*((gint *) xs_widtable[i].itemData) == xs_widtable[i].itemSet));
			break;

		case WTYPE_COMBO:
			assert(xs_widtable[i].itemType == CTYPE_INT);
			g_snprintf(tmpStr, sizeof(tmpStr), "%d", *(gint *) xs_widtable[i].itemData);
			gtk_entry_set_text(GTK_ENTRY(LUW(xs_widtable[i].widName)), tmpStr);
			break;
			
		case WTYPE_SPIN:
		case WTYPE_SCALE:
			/* Get the value */
			switch (xs_widtable[i].itemType) {
			case CTYPE_INT:
				tmpValue = (gfloat) * ((gint *) xs_widtable[i].itemData);
				break;

			case CTYPE_FLOAT:
				tmpValue = *((gfloat *) xs_widtable[i].itemData);
				break;

			default:
				tmpValue = -1;
				assert(0);
				break;
			}

			/* Set the value */
			switch (xs_widtable[i].widType) {
			case WTYPE_SPIN:
				gtk_adjustment_set_value(gtk_spin_button_get_adjustment
					(GTK_SPIN_BUTTON(LUW(xs_widtable[i].widName))), tmpValue);
				break;

			case WTYPE_SCALE:
				gtk_adjustment_set_value(gtk_range_get_adjustment
					(GTK_RANGE(LUW(xs_widtable[i].widName))), tmpValue);
				break;
			}
			break;

		case WTYPE_BUTTON:
			assert(xs_widtable[i].itemType == CTYPE_BOOL);
			/* Set toggle-button */
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(LUW(xs_widtable[i].widName)),
				*((gboolean *) xs_widtable[i].itemData));
			break;

		case WTYPE_TEXT:
			assert(xs_widtable[i].itemType == CTYPE_STR);
			/* Set text to text-widget */
			if (*(gchar **) xs_widtable[i].itemData != NULL) {
				gtk_entry_set_text(GTK_ENTRY(LUW(xs_widtable[i].widName)),
				*(gchar **) xs_widtable[i].itemData);
			}
			break;
		}
	}

	/* Release the configuration */
	XS_MUTEX_UNLOCK(xs_cfg);

	/* Show the widget */
	gtk_widget_show(xs_configwin);
}