# HG changeset patch # User Matti Hamalainen # Date 1234228807 -7200 # Node ID 2b6a29eefffb9b715a6edbddd97a77c17a390ec9 # Parent 0feeaf698a543fcfd6d8e8f96bc1be5689a20a35 More work on implementing working filter saving, loading, importing and exporting. diff -r 0feeaf698a54 -r 2b6a29eefffb src/xs_config.c --- a/src/xs_config.c Tue Feb 10 03:11:39 2009 +0200 +++ b/src/xs_config.c Tue Feb 10 03:20:07 2009 +0200 @@ -302,37 +302,97 @@ /* Filter configuration handling */ +static void xs_filters_error(const gchar *fmt, ...) +{ + va_list ap; + gchar *msg; + + va_start(ap, fmt); + msg = g_strdup_vprintf(fmt, ap); + va_end(ap); + + xmms_show_message(_(PACKAGE_NAME " Error"), msg, _("OK"), TRUE, NULL, NULL); + g_free(msg); +} + + +static void xs_filter_free(xs_sid2_filter_t *filter) +{ + if (filter) { + g_free(filter->name); + filter->name = NULL; + g_free(filter); + } +} + + #define XS_FITEM (4 * 2) -static gboolean xs_filter_load_into(XS_CONFIG_FILE *cfg, gint nFilter, xs_sid2_filter_t *pResult) +static gboolean xs_filter_load_into(XS_CONFIG_FILE *cfg, gint nFilter, xs_sid2_filter_t *filter) { gchar tmpKey[64], *tmpStr; - gint i, j; /* Get fields from config */ - g_snprintf(tmpKey, sizeof(tmpKey), "filter%dNPoints", nFilter); - if (!XS_CFG_GET_INT(tmpKey, &(pResult->npoints))) + g_snprintf(tmpKey, sizeof(tmpKey), "filter%dType", nFilter); + if (!XS_CFG_GET_INT(tmpKey, &(filter->type))) return FALSE; g_snprintf(tmpKey, sizeof(tmpKey), "filter%dName", nFilter); if (!XS_CFG_GET_STRING(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(tmpKey, &tmpStr)) + filter->name = g_strdup(tmpStr); + if (filter->name == NULL) 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) + if (filter->type == 1) { + gint i, j; + + /* Types 1 has points */ + g_snprintf(tmpKey, sizeof(tmpKey), "filter%dNPoints", nFilter); + if (!XS_CFG_GET_INT(tmpKey, &(filter->npoints))) + return FALSE; + + g_snprintf(tmpKey, sizeof(tmpKey), "filter%dPoints", nFilter); + if (!XS_CFG_GET_STRING(tmpKey, &tmpStr)) + return FALSE; + + for (i = 0, j = 0; i < filter->npoints; i++, j += XS_FITEM) { + if (sscanf(&tmpStr[j], "%4x%4x", + &(filter->points[i].x), + &(filter->points[i].y)) != 2) + return FALSE; + } + } else if (filter->type == 3) { + /* Type 3 has tunables */ + g_snprintf(tmpKey, sizeof(tmpKey), "filter%dData", nFilter); + if (!XS_CFG_GET_STRING(tmpKey, &tmpStr)) return FALSE; + + if (sscanf(tmpStr, "%f,%f,%f,%f", &filter->rate, &filter->point, + &filter->voice_nonlinearity, &filter->cf_treshold) != 4) + return FALSE; + + g_snprintf(tmpKey, sizeof(tmpKey), "filter%dData3", nFilter); + if (!XS_CFG_GET_STRING(tmpKey, &tmpStr)) + return FALSE; + + if (sscanf(tmpStr, "%f,%f,%f,%f", &filter->baseresistance, + &filter->offset, &filter->steepness, + &filter->minimumfetresistance) != 4) + return FALSE; + + } else if (filter->type == 4) { + /* Type 4 has fewer tunables */ + g_snprintf(tmpKey, sizeof(tmpKey), "filter%dData4", nFilter); + if (!XS_CFG_GET_STRING(tmpKey, &tmpStr)) + return FALSE; + + if (sscanf(tmpStr, "%f,%f", &filter->k, &filter->b) != 2) + return FALSE; + } else { + xs_error("Unknown filter type %d for '%s' (#%d).\n", filter->type, filter->name, nFilter); + return FALSE; } return TRUE; @@ -341,19 +401,21 @@ static xs_sid2_filter_t * xs_filter_load(XS_CONFIG_FILE *cfg, gint nFilter) { - xs_sid2_filter_t *pResult; + xs_sid2_filter_t *filter; /* Allocate filter struct */ - if ((pResult = g_malloc0(sizeof(xs_sid2_filter_t))) == NULL) + if ((filter = g_malloc0(sizeof(xs_sid2_filter_t))) == NULL) return NULL; - if (!xs_filter_load_into(cfg, nFilter, pResult)) { - g_free(pResult); + if (!xs_filter_load_into(cfg, nFilter, filter)) { + xs_error("Error loading filter %d from configuration.\n", nFilter); + xs_filter_free(filter); return NULL; } else - return pResult; + return filter; } + #if 0 static gboolean xs_filter_save(XS_CONFIG_FILE *cfg, xs_sid2_filter_t *pFilter, gint nFilter) { @@ -387,67 +449,97 @@ } #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; + while (--i > 0 && isspace(tmpStr[i])) tmpStr[i] = 0; + xs_findnext(inLine, linePos); return (inLine[*linePos] == sep); } -static gboolean xs_filters_import(const gchar *pcFilename, xs_sid2_filter_t **pFilters, gint *nFilters) +static gboolean xs_chkf(xs_sid2_filter_t *filter, const gchar *str, const gchar *name, gint type) +{ + if (g_strncasecmp(str, name, strlen(name))) + return FALSE; + if (filter->type != type) { + if (filter->type == -1) { + filter->type = type; + return TRUE; + } else { + xs_error("Unexpected key '%s' for filter type %d.\n"); + return FALSE; + } + } else + return TRUE; +} + +static gboolean xs_filters_import(const gchar *filename, xs_sid2_filter_t **pFilters, gint *nFilters) { FILE *inFile; gchar inLine[XS_BUF_SIZE], tmpStr[XS_BUF_SIZE]; gchar *sectName = NULL; - gboolean sectBegin; + gboolean inSection, isError = FALSE; size_t lineNum, i; - xs_sid2_filter_t *tmpFilter; + xs_sid2_filter_t *filter = NULL; -fprintf(stderr, "xs_filters_import(%s)\n", pcFilename); +fprintf(stderr, "xs_filters_import(%s)\n", filename); - if ((inFile = fopen(pcFilename, "ra")) == NULL) + if ((inFile = fopen(filename, "ra")) == NULL) { + xs_filters_error(""); return FALSE; + } fprintf(stderr, "importing...\n"); - sectBegin = FALSE; + inSection = FALSE; lineNum = 0; - while (fgets(inLine, XS_BUF_SIZE, inFile) != NULL) { + while (fgets(inLine, XS_BUF_SIZE, inFile) != NULL && !isError) { size_t linePos = 0; lineNum++; xs_findnext(inLine, &linePos); - if (isalpha(inLine[linePos]) && sectBegin) { + if (isalpha(inLine[linePos])) { /* A new key/value pair */ if (!xs_fgetitem(inLine, &linePos, '=', tmpStr, XS_BUF_SIZE)) { - fprintf(stderr, "invalid line: %s [expect =']'", inLine); - } else { + xs_error("Invalid line '%s' :: expected =", inLine); + isError = TRUE; + } else if (inSection) { 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)) { + + if (xs_chkf(filter, tmpStr, "points", 1)) { + + } else if (xs_chkf(filter, tmpStr, "point", 1)) { + + } else if (!g_strncasecmp(tmpStr, "type", 4)) { + if (filter->type != -1) { + xs_error("Filter type %d already set for '%s'\n", + filter->type, sectName); + } + } else { - fprintf(stderr, "warning: ukn def: %s @ %s\n", + xs_error("Unsupported definition '%s' @ '%s'\n", tmpStr, sectName); } } } else if (inLine[linePos] == '[') { /* Check for existing section */ - if (sectBegin) { + if (inSection) { /* Submit definition */ fprintf(stderr, "filter ends: %s\n", sectName); - if ((tmpFilter = g_malloc0(sizeof(xs_sid2_filter_t))) == NULL) { + if ((filter = g_malloc0(sizeof(xs_sid2_filter_t))) == NULL) { fprintf(stderr, "could not allocate ..\n"); } else { @@ -464,13 +556,19 @@ if (inLine[linePos] != ']') { fprintf(stderr, "invalid! expected ']': %s\n", inLine); } else { - sectName = strdup(tmpStr); - fprintf(stderr, "filter: %s\n", sectName); - sectBegin = TRUE; + if (!g_strncasecmp(tmpStr, "filter", 6)) { + sectName = strdup(tmpStr + 6); + fprintf(stderr, "filter: %s\n", sectName); + inSection = TRUE; + } else { + fprintf(stderr, "ignoring section: %s\n", tmpStr); + inSection = FALSE; + } } - } else if ((inLine[linePos] != ';') && (inLine[linePos] != 0)) { + } else if (inLine[linePos] != '#' && inLine[linePos] != ';' && inLine[linePos] != 0) { /* Syntax error */ - fprintf(stderr, "syntax error: %s\n", inLine); + xs_error("Syntax error: '%s'\n", inLine); + isError = TRUE; } } @@ -479,15 +577,69 @@ } -static gboolean xs_filters_export(const gchar *pcFilename, xs_sid2_filter_t **pFilters, gint nFilters) +static gboolean xs_filter_export(FILE *outFile, xs_sid2_filter_t *filter) { + fprintf(outFile, + "[Filter%s]\n" + "type=%d\n", + filter->name, filter->type); + + if (filter->type == 1) { + gint i; + fprintf(outFile, "points=%d\n", filter->npoints); + + for (i = 0; i < filter->npoints; i++) { + fprintf(outFile, + "point%d=%d,%d\n", + i + 1, + filter->points[i].x, + filter->points[i].y); + } + } else if (filter->type == 3) { + fprintf(outFile, + "DistortionRate = %f\n" + "DistortionPoint = %f\n" + "VoiceNonlinearity = %f\n" + "DistortionCFThreshold = %f\n", + filter->rate, filter->point, + filter->voice_nonlinearity, + filter->cf_treshold); + + fprintf(outFile, + "Type3BaseResistance = %f\n" + "Type3Offset = %f\n" + "Type3Steepness = %f\n" + "Type3MinimumFETResistance = %f\n", + filter->baseresistance, filter->offset, + filter->steepness, filter->minimumfetresistance); + + } else if (filter->type == 4) { + fprintf(outFile, + "Type4K=%f\n" + "Type4B=%f\n", + filter->k, filter->b); + } else { + xs_error("Filter '%s' has type %d, which is unsupported by export.\n", + filter->name, filter->type); + return FALSE; + } + + fprintf(outFile, "\n"); + return TRUE; +} + + +static gboolean xs_filters_export(const gchar *filename, xs_sid2_filter_t **filters, gint nFilters) +{ + gboolean result = TRUE; FILE *outFile; - xs_sid2_filter_t *f; gint n; /* Open/create the file */ - if ((outFile = fopen(pcFilename, "wa")) == NULL) + if ((outFile = fopen(filename, "wa")) == NULL) { + xs_filters_error("Could not open '%s' for writing! Not exporting.", filename); return FALSE; + } /* Header */ fprintf(outFile, @@ -496,31 +648,21 @@ /* 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); + if (!xs_filter_export(outFile, filters[n])) { + result = FALSE; + break; } - - fprintf(outFile, "\n"); - f++; } fclose(outFile); - return TRUE; + + if (!result) + xs_filters_error("Some filters could not be exported!"); + + return result; } + /* Get the configuration (from file or default) */ void xs_read_configuration(void)