view src/sid/xs_config.c @ 906:16e51fb5908e trunk

[svn] - aosd: beta4, ghosd source was rewritten to support argb visual (x composite extension) as an option, this allows to have real transparency in the OSD
author giacomo
date Sat, 31 Mar 2007 17:44:23 -0700
parents 6c3c7b841382
children a9d7b36cc6af
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/configdb.h>
#define XS_CONFIG_FILE		ConfigDb
#define XS_CONFIG_OPEN		bmp_cfg_db_open
#define XS_CONFIG_FREE		bmp_cfg_db_close
#define XS_CONFIG_WRITE

#define XS_CFG_SET_STRING	bmp_cfg_db_set_string
#define XS_CFG_SET_FLOAT	bmp_cfg_db_set_float
#define XS_CFG_SET_INT		bmp_cfg_db_set_int
#define XS_CFG_SET_BOOL		bmp_cfg_db_set_bool
#define XS_CFG_GET_STRING	bmp_cfg_db_get_string
#define XS_CFG_GET_FLOAT	bmp_cfg_db_get_float
#define XS_CFG_GET_INT		bmp_cfg_db_get_int
#define XS_CFG_GET_BOOL		bmp_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_CONFIG_WRITE		xmms_cfg_write_default_file

#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 "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_pathselector = NULL;

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


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

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_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" },

{ CTYPE_INT,	&xs_cfg.subsongControl,		"subsongControl" },
{ CTYPE_BOOL,	&xs_cfg.detectMagic,		"detectMagic" },

{ 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));


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 },

{ 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 },

{ 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);

	/* 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;

	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;
#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");

#ifdef HAVE_SONG_POSITION
	xs_cfg.subsongControl = XS_SSC_PATCH;
#else
	xs_cfg.subsongControl = XS_SSC_POPUP;
#endif

	xs_cfg.detectMagic = FALSE;

#if defined(HAVE_XMMSEXTRA) || defined(AUDACIOUS_PLUGIN)
	xs_cfg.titleOverride = FALSE;
#else
	xs_cfg.titleOverride = TRUE;
#endif
	xs_pstrcpy(&xs_cfg.titleFormat, "%p - %t (%c) [%n/%N][%m/%C]");


	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;
	if (pResult->npoints > XS_SIDPLAY2_NFPOINTS)
		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 = 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) {
		sscanf(&tmpStr[j], "%4x%4x",
			&(pResult->points[i].x),
			&(pResult->points[i].y));
	}
	
	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;
}


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;
}


/* Filter exporting and importing. These functions export/import
 * filter settings to/from SIDPlay2 INI-type files.
 */
static gboolean xs_filters_import(gchar *pcFilename, t_xs_sid2_filter **pFilters, gint *nFilters)
{
	FILE *inFile;
	t_xs_sid2_filter *f;
	
	if ((inFile = fopen(pcFilename, "rb")) == NULL)
		return FALSE;
	
	
	
	fclose(inFile);
	return FALSE;
}


static gboolean xs_filters_export(gchar *pcFilename, t_xs_sid2_filter *pFilters, gint nFilters)
{
	FILE *outFile;
	t_xs_sid2_filter *f = pFilters;
	gint n;
	
	/* Open/create the file */
	if ((outFile = fopen(pcFilename, "wb")) == NULL)
		return FALSE;
	
	/* Write each filter spec in "INI"-style format */
	for (n = 0; n < nFilters; n++) {
		gint i;
		
		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;
		}
	}
	
	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();
#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;
		}
	}

	XS_CONFIG_WRITE(cfg);
	XS_CONFIG_FREE(cfg);

	XS_MUTEX_UNLOCK(xs_cfg);

	return 0;
}


/* Configuration panel was canceled
 */
void xs_cfg_cancel(void)
{
	gtk_widget_destroy(xs_configwin);
	xs_configwin = NULL;
}


/* Configuration was accepted, save the settings
 */
void xs_cfg_ok(void)
{
	gint i;
	gfloat tmpValue;
	gint tmpInt;
	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;
		}
	}

	/* 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();
}


/* Reset filter settings to defaults
 */
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_emu_filt_fs"))), XS_SIDPLAY1_FS);
	gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(LUW("cfg_emu_filt_fm"))), XS_SIDPLAY1_FM);
	gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(LUW("cfg_emu_filt_ft"))), XS_SIDPLAY1_FT);
}


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

	if (xs_sldb_fileselector != NULL) {
		gdk_window_raise(xs_sldb_fileselector->window);
		return;
	}

	xs_sldb_fileselector = create_xs_sldbfileselector();
	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_cfg_sldb_fs_ok(void)
{
	/* 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;
}


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


/* 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) {
		gdk_window_raise(xs_stil_fileselector->window);
		return;
	}

	xs_stil_fileselector = create_xs_stilfileselector();
	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_cfg_stil_fs_ok(void)
{
	/* 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;
}


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


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

	if (xs_hvsc_pathselector != NULL) {
		gdk_window_raise(xs_hvsc_pathselector->window);
		return;
	}

	xs_hvsc_pathselector = create_xs_hvscpathselector();
	XS_MUTEX_LOCK(xs_cfg);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(xs_hvsc_pathselector), xs_cfg.hvscPath);
	XS_MUTEX_UNLOCK(xs_cfg);
	gtk_widget_show(xs_hvsc_pathselector);
}


void xs_cfg_hvsc_fs_ok(void)
{
	/* Selection was accepted! */
	gtk_entry_set_text(GTK_ENTRY(LUW("cfg_hvsc_path")),
			   gtk_file_selection_get_filename(GTK_FILE_SELECTION(xs_hvsc_pathselector)));

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


void xs_cfg_hvsc_fs_cancel(void)
{
	/* Close file selector window */
	gtk_widget_destroy(xs_hvsc_pathselector);
	xs_hvsc_pathselector = NULL;
}


/* 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_sld_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);
}


/* Execute the configuration panel
 */
void xs_configure(void)
{
	gint i;
	gfloat tmpValue;
	gchar tmpStr[32];
	GtkWidget *c;

	/* Check if the window already exists */
	if (xs_configwin != NULL) {
		gdk_window_raise(xs_configwin->window);
		return;
	}

	/* Create the window */
	xs_configwin = create_xs_configwin();

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

	/* Create the custom filter curve widget for libSIDPlay2 */
	c = xs_curve_new();
	xs_curve_reset(XS_CURVE(c));
	xs_curve_set_range(XS_CURVE(c),
		0,0, XS_SIDPLAY2_NFPOINTS, XS_SIDPLAY2_FMAX);
	xs_curve_set_points(XS_CURVE(c),
		xs_cfg.sid2Filter.points, xs_cfg.sid2Filter.npoints);
	
	gtk_widget_set_name(c, "cfg_sp2_filter_curve");
	gtk_widget_ref(c);
	gtk_object_set_data_full(GTK_OBJECT(xs_configwin),
		"cfg_sp2_filter_curve", c, (GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show(c);
	gtk_container_add(GTK_CONTAINER(LUW("cfg_sp2_filter_frame")), c);


	/* 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_sidplay1"), FALSE);
#endif

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

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

#ifndef HAVE_SONG_POSITION
	gtk_widget_set_sensitive(LUW("cfg_subctrl_patch"), FALSE);
#endif

#ifdef AUDACIOUS_PLUGIN
	gtk_widget_set_sensitive(LUW("cfg_detectmagic"), FALSE);
#endif

	/* Update the widget sensitivities */
	gtk_widget_set_sensitive(LUW("cfg_resid_frame"), FALSE);
		
	xs_cfg_emu_filters_toggled((GtkToggleButton *) LUW("cfg_emu_filters"), NULL);
	xs_cfg_ftitle_override_toggled((GtkToggleButton *) LUW("cfg_ftitle_override"), NULL);
	xs_cfg_emu_sidplay1_toggled((GtkToggleButton *) LUW("cfg_emu_sidplay1"), NULL);
	xs_cfg_emu_sidplay2_toggled((GtkToggleButton *) LUW("cfg_emu_sidplay2"), NULL);
	xs_cfg_oversample_toggled((GtkToggleButton *) LUW("cfg_oversample"), NULL);
	xs_cfg_mintime_enable_toggled((GtkToggleButton *) LUW("cfg_mintime_enable"), NULL);
	xs_cfg_maxtime_enable_toggled((GtkToggleButton *) LUW("cfg_maxtime_enable"), NULL);
	xs_cfg_sld_enable_toggled((GtkToggleButton *) LUW("cfg_sld_enable"), NULL);
	xs_cfg_stil_enable_toggled((GtkToggleButton *) LUW("cfg_stil_enable"), NULL);
	xs_cfg_subauto_enable_toggled((GtkToggleButton *) LUW("cfg_subauto_enable"), NULL);
	xs_cfg_subauto_min_only_toggled((GtkToggleButton *) 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);
}