changeset 721:2b6a29eefffb

More work on implementing working filter saving, loading, importing and exporting.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 10 Feb 2009 03:20:07 +0200
parents 0feeaf698a54
children 5923dfff1fac
files src/xs_config.c
diffstat 1 files changed, 208 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- 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)