view src/xs_config.c @ 673:537240c47d18

It was the dawn of the third age of SID-kind, several years after the XMMS-BMP War. The Unified Audacious+XMMS-SID Project was a dream given form. Its goal: to prevent another war by creating a SID-plugin which would be functional for both worlds, where Audacious and XMMS -related code could work out their differences peacefully. It's a port of call, home away from home for coders, users, entrepreneurs, and wanderers. Humans and aliens wrapped in two million, five hundred thousand tons of spinning code, all alone in the night. It can be a dangerous place, but it's our last, best hope for peace. This is the story of the last of the XMMS-SID releases. The year is 2008. The name of the place is XMMS-SID 0.8.0rc2.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 21 Apr 2008 18:53:55 +0300
parents 50e036a32db8
children 4bf845090a25
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);

    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) {
        XS_WINDOW_PRESENT(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) {
        XS_WINDOW_PRESENT(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) {
        XS_WINDOW_PRESENT(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) {
        XS_WINDOW_PRESENT(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) {
        XS_WINDOW_PRESENT(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) {
        XS_WINDOW_PRESENT(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);
}