vbank.c
来自「A GTK sound font editor. Sound font file」· C语言 代码 · 共 879 行 · 第 1/2 页
C
879 行
if (pset1 < pset2) return (-1); if (pset1 > pset2) return (1); return (0);}/* searches for unloaded sound fonts required by a virtual bank and returns a list of "found" file paths and "notfound" sound font names, both lists (and list items) should be freed */voidvbank_find_unloaded_sfonts (VBnkData *vbnk, GList **found, GList **notfound){ GHashTable *sfnames; GList *nlists[2] = { NULL, NULL}; /* 2 GLists for found and notfound */ VBnkItem *item; GSList *p; sfnames = g_hash_table_new (g_str_hash, g_str_equal); if (vbnk->defname) g_hash_table_insert (sfnames, vbnk->defname, GINT_TO_POINTER (TRUE)); /* loop over virtual bank items, and insert unloaded sound font names into hash (gets rid of duplicates) */ p = vbnk->items; while (p) { item = (VBnkItem *)(p->data); if (item->sfname) g_hash_table_insert (sfnames, item->sfname, GINT_TO_POINTER (TRUE)); p = g_slist_next (p); } g_hash_table_foreach (sfnames, vbank_GHFunc_find_sfont, nlists); if (!found) { g_list_foreach (nlists[0], (GFunc)g_free, NULL); g_list_free (nlists[0]); } else *found = nlists[0]; if (!notfound) { g_list_foreach (nlists[1], (GFunc)g_free, NULL); g_list_free (nlists[1]); } else *notfound = nlists[1];}/* GHFunc used by vbank_find_unloaded_sfonts to fill found and not found lists with found sfont paths and not found sfont names */static voidvbank_GHFunc_find_sfont (gpointer key, gpointer value, gpointer data){ GList **nlists = (GList **)data; gchar *sfname = (gchar *)key; gchar *path; /* can we locate the sound font? (full file path) */ if (!(path = vbank_locate_sfont_by_name (sfname))) nlists[0] = g_list_append (nlists[0], path); /* ?: YES, add path to found */ else nlists[1] = g_list_append (nlists[1], g_strdup (sfname)); /* ?: Nope */}/* looks up a sound font by name (without extension) in the sfont file hash and returns a full path to the found file, or NULL if not found. ** Return string should be freed ** */gchar *vbank_locate_sfont_by_name (gchar *sfname){ gchar *origkey, *dir; gchar *filepath; if (!vbank_sffile_hash) vbank_update_sffile_hash (); /* lookup the sfont name and get original key string */ if (!g_hash_table_lookup_extended (vbank_sffile_hash, sfname, (gpointer *)(&origkey),(gpointer *)(&dir))) return (NULL); /* construct full path to file (original hash key contains 2 adjacent strings, first is the sfont name (without extension) second is the 3 letter extension) */ filepath = g_strconcat (dir, origkey, ".", origkey + strlen (origkey) + 1, NULL); return (filepath);}/* turns a full path into just the base file name without ".sf2" extension ** returned string should be freed ** */gchar *vbank_base_fname (gchar *path){ gchar *s; s = g_basename (path); if (strlen (s) > 4 && g_strcasecmp (s + strlen (s) - 4, ".sf2") == 0) return (g_strndup (s, strlen (s) - 4)); else return (g_strdup (s));}/* indexes all sound font files in directories of vbank search path */voidvbank_update_sffile_hash (void){ gchar *path; gchar *s, *s2; gboolean recurse; /* free old hashes if any */ if (vbank_sffile_hash) { /* free keys only (value strings are in vbank_sfdir_hash) */ g_hash_table_foreach (vbank_sffile_hash, (GHFunc)g_free, NULL); g_hash_table_destroy (vbank_sffile_hash); } if (vbank_sfdir_hash) { /* free keys only (value is just TRUE) */ g_hash_table_foreach (vbank_sfdir_hash, (GHFunc)g_free, NULL); g_hash_table_destroy (vbank_sfdir_hash); } vbank_sffile_hash = g_hash_table_new (g_str_hash, g_str_equal); vbank_sfdir_hash = g_hash_table_new (g_str_hash, g_str_equal); path = g_strdup (smurfcfg_get_val (SMURFCFG_VBNK_SEARCH_PATH)->v_string); /* no search path? */ if (!path || !*path) return; s = path; while (s && *s) /* loop over directory names in search path */ { if ((s2 = strchr (s, ':'))) { *s2 = '\0'; s2++; } /* check for "slash*" (start of C comment :) at end of directory name, signifying recursive search */ if (strlen (s) >= 2 && strcmp (s + strlen (s) - 2, G_DIR_SEPARATOR_S "*") == 0) { s[strlen (s) - 1] = '\0'; /* truncate string at the '*' */ recurse = TRUE; } else recurse = FALSE; /* no recurse into sub directories */ vbank_hash_sffiles (s, recurse); /* hash sfont names */ s = s2; } g_free (path);}/* adds all sound font file names in "dirname" to vbank_sffile_hash, called by vbank_update_sffile_hash and itself (recursively) */static gintvbank_hash_sffiles (gchar *dirname, gboolean recurse){ gchar *dname; /* dup of dirname but with / at end if needed */ DIR *dh; struct dirent *ent; gchar *fname, *fullpath; struct stat statnfo; gboolean found = FALSE; /* new sound font file found? */ gchar *s; if (!dirname || !*dirname) return (logit (LogWarn, _("Empty directory name in virtual bank" " search path"))); /* if directory doesn't end with a slash, then add one */ if (dirname [strlen (dirname) - 1] != G_DIR_SEPARATOR) dname = g_strconcat (dirname, G_DIR_SEPARATOR_S, NULL); else dname = g_strdup (dirname); /* duplicate to keep g_free consistent */ /* directory already searched? */ if (g_hash_table_lookup (vbank_sfdir_hash, dname)) { g_free (dname); return (OK); } if (!(dh = opendir (dname))) /* attempt to open the directory */ return (logit (LogWarn | LogErrno, _("Failed to open directory '%s' in" " virtual bank search path"), s)); /* loop over contents of directory */ while ((ent = readdir (dh))) { fname = ent->d_name; /* skip self and parent directory */ if (strcmp (fname, ".") == 0 || strcmp (fname, "..") == 0) continue; if (recurse) /* recurse into sub dirs? */ { fullpath = g_strconcat (dname, fname, NULL); /* full path to file */ if (stat (fullpath, &statnfo) == -1) /* stat the file */ { logit (LogWarn | LogErrno, _("Failed to get stats on file '%s'"), fullpath); g_free (fullpath); continue; } if (S_ISDIR (statnfo.st_mode)) /* if directory, then recurse it */ { vbank_hash_sffiles (fullpath, TRUE); /* call us recursively */ g_free (fullpath); continue; } g_free (fullpath); } /* is it a sound font file? (.sf2 extension) */ if (strlen (fname) <= 4 || g_strcasecmp (fname + strlen (fname) - 4, ".sf2") != 0) continue; /* make file name string dynamically allocated so we can mess with it */ fname = g_strdup (fname); /* make file name 2 strings, first is sound font name without extension, second string (immediately following the first) is the extension, therefore file name (without extension) gets used as hash key */ fname [strlen (fname) - 4] = '\0'; /* check if file by this name already found */ if ((s = g_hash_table_lookup (vbank_sffile_hash, fname))) { logit (LogWarn, _("Sound font file '%s' conflicts with '%s' in" " virtual sound font search path"), fname, s); g_free (fname); continue; } /* insert into file hash table: sfont name as a key, file's directory as the value */ g_hash_table_insert (vbank_sffile_hash, fname, dname); found = TRUE; } /* if any sfonts were found, insert directory name into directory hash as key and value (hash used to check for duplicates), keep dname */ if (found) g_hash_table_insert (vbank_sfdir_hash, dname, GINT_TO_POINTER (TRUE)); else g_free (dname); /* no sfonts found, free dname */ return (OK);}/* parse a virtual bank file into a virtual bank structure */static gintvbank_parse (FILE *fp, VBnkData *vbnk){ char line[256], *p, *p2, *name; VBnkItem *item; int len; gint linenum = 0; while (fgets(line, sizeof(line) - 1, fp)) { linenum++; /* discard the linefeed */ len = strlen(line); if (len > 0 && line[len-1] == '\n') line[len-1] = 0; /* skip spaces & comments */ for (p = line; isspace(*p); p++) ; if (!*p || *p == '#' || *p == '!' || *p == '%') continue; if (isalpha(*p)) { char *arg; arg = strschr(p, " \t\r\n"); if (arg) { char *tmp = strschr(arg, " \t\r\n"); if (tmp) *tmp = 0; arg++; } switch (*p) { case 'i': case 'I': /* include other bank file */ break; case 'd': case 'D': /* set default font file */ if (vbnk->defname) g_free(vbnk->defname); vbnk->defname = g_strdup(arg); break; default: return (logit (LogFubar, _("Illegal command on line %d"), linenum)); break; } continue; } else if (*p == '*' || *p == '-' || isdigit(*p)) { item = vbank_item_alloc (); if (! vbank_parse_item (p, item, &name)) { vbank_item_free (item); logit (LogWarn, _("Ignoring invalid item on line %d"), linenum); continue; } if (item->src.bank == -1 || item->src.psetnum == -1) { vbank_item_free (item); logit (LogWarn, "Virtual bank wildcard maps not supported yet"); continue; } } else continue; if (name && *name) /* if there is a sound font name string */ { /* convert "\ " to spaces and "\\" to back slashes, to support file names with spaces (original AWE .bnk format doesn't) */ p = p2 = name; while (*p2) { if (p2[0] == '\\' && p2[1] == ' ') { *p = ' '; p2++; } else if (p2[0] == '\\' && p2[1] == '\\') { *p = '\\'; p2++; } else if (strchr (" \t\n", *p2)) { *p = '\0'; break; } else *p = *p2; p++; p2++; } *p = '\0'; /* terminate sound font name */ } if (name == NULL || !*name) /* without font name -- its a preset link */ item->sfname = NULL; else item->sfname = g_strdup (name); vbnk->items = g_slist_append (vbnk->items, item); } return (OK);}/* parse source and mapping presets */static gintvbank_parse_item(gchar *arg, VBnkItem *item, gchar **strp){ char *next; if ((next = strschr(arg, ":=")) != NULL) *next++ = 0; vbank_parse_preset(&item->src, arg); if (next == NULL) { item->map = item->src; if (strp) *strp = NULL; return TRUE; } arg = next; if ((next = strschr(arg, ":=")) != NULL) *next++ = 0; vbank_parse_preset(&item->map, arg); if (strp) *strp = next; return TRUE;}/* parse preset/bank/keynote */static voidvbank_parse_preset(VBnkPtr *vptr, char *arg){ char *next; if ((next = strschr(arg, "/: \t\n")) != NULL) *next++ = 0; vptr->psetnum = vbank_parse_arg(arg); vptr->bank = 0; vptr->keynote = -1; arg = next; if (arg) { if ((next = strschr(arg, "/: \t\n")) != NULL) *next++ = 0; vptr->bank = vbank_parse_arg(arg); if (next) vptr->keynote = vbank_parse_arg(next); }}/* ascii to digit; accept * and - characters */static intvbank_parse_arg(char *arg){ if (isdigit(*arg)) return atoi(arg); else return -1;}/* search delimiers */static char *strschr(char *str, char *dels){ char *p; for (p = str; *p; p++) { if (strchr(dels, *p)) return p; } return NULL;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?