📄 wavetable.c
字号:
/*================================================================== * wavetable.c - Generic wavetable routines (independent of device) * * Smurf Sound Font Editor * Copyright (C) 1999-2001 Josh Green * * 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA or point your web browser to http://www.gnu.org. * * To contact the author of this program: * Email: Josh Green <jgreen@users.sourceforge.net> * Smurf homepage: http://smurf.sourceforge.net *==================================================================*/#include "config.h"#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <glib.h>#include "wavetable.h"#include "sample.h"#include "util.h"#include "sequencer.h"#include "smurfcfg.h"#include "i18n.h"#include "uif_sftree.h" /* For NODE_* defines */#include "uif_piano.h"#include "drivers/wtbl_awe.h"#include "drivers/seq_oss.h"WTblDriverInfo wtbl_drivers[WTBL_COUNT] = { { N_("NONE"), NULL, NULL, NULL, NULL, NULL, NULL },#ifdef AWE_SUPPORT { N_("AWE32/64"), awe_init, seq_oss_fd_close, awe_set_effect, awe_open_patch, awe_close_patch, awe_load_sample, awe_load_patch_info, awe_clear_samples, awe_clear_unlocked_samples, awe_clear_sample_patch_id, awe_mem_avail, awe_samdata_mem_required },#endif};static gint wtbl_auto_detect (void);static void wtbl_silence_temp_audible (void);static gint wtbl_GTraverseFunc_preset_dependents (gpointer key, gpointer value, gpointer data);static gint wtbl_GTraverseFunc_load_preset (gpointer key, gpointer value, gpointer data);static gint wtbl_ptr_compare_func (gconstpointer p1, gconstpointer p2);static gint wtbl_sfont_mem_required (SFData *sf);static gint wtbl_vbank_mem_required (VBnkData *vbnk);static gint wtbl_preset_mem_required (SFPreset *pset, SFData *sf, gboolean locked, GTree *gt);static gint wtbl_inst_mem_required (SFInst *inst, SFData *sf, gboolean locked, GTree *gt);static gint wtbl_update_cache_vars (void);static gint wtbl_clear_cache_if_needed (gint memreq);static gint wtbl_load_preset_real (gint bank, gint prenum, SFPreset *pset, SFData *sf);gint wtbl_driver = WTBL_NONE; /* active wavetable driver */gboolean wtbl_active = FALSE; /* state of wavetable driver */gchar *wtbl_oss_devname = NULL; /* device file for OSS wavetable drivers *//* when samples are loaded as instruments should they be looped or not? */gboolean wtbl_loop_sam_as_inst = TRUE;gboolean wtbl_sample_cache_support = FALSE; /* if AWE driver supports caching */gboolean wtbl_cache_samples = FALSE; /* enable sample caching? */gboolean wtbl_recursive_bank_refresh = FALSE; /* upd8 loaded bank recursively *//* variables for the active temporary audible */SFItemID wtbl_temp_audible = SFITEMID_NONE; /* current temporary audible */gboolean wtbl_temp_audible_changed = FALSE; /* audible needs reload? */GList *wtbl_temp_audible_muted_zones = NULL; /* zones (SFItemIDs) to mute *//* currently loaded sound font or virtual bank */SFItemID wtbl_loaded_sfbank = SFITEMID_NONE;gboolean wtbl_loaded_sfbank_changed = FALSE; /* loaded sfont/vbank changed? */GTree *wtbl_changed_loaded_sfitems = NULL; /* changed sfitems in loaded SF */static gint wtbl_cache_mem_avail = -1; /* amount of mem available to cache *//* clear samples, first time a patch gets loaded */static gboolean wtbl_onetime_clear_samples = TRUE; /* initialize wavetable drivers and load config vars */gintwtbl_init_from_config (void){ GTokenValue *val; gint drvr_id; gboolean retval; char *s; /* get wavetable sample caching config var (1 = on, 0 = off, 2 = auto) */ wtbl_cache_samples = (smurfcfg_get_val (SMURFCFG_WAVETBL_SAM_CACHING)->v_int == 1); /* Same OSS device is used for all OSS based wavetable/sequencer/midi drivers, load the config value here */ if (wtbl_oss_devname) g_free (wtbl_oss_devname); s = smurfcfg_get_str (SMURFCFG_WAVETBL_OSSDEV); if (!strlen (s)) /* if config has blank value, set to default */ s = "/dev/sequencer"; wtbl_oss_devname = g_strdup(s); val = smurfcfg_get_val (SMURFCFG_WAVETBL_DRIVER); if (strcmp (val->v_string, "AUTO") != 0 && (drvr_id = wtbl_locate_byname (val->v_string)) != -1) { log_message (_("Initializing wavetable driver \"%s\".."),val->v_string); wtbl_set_driver (drvr_id); /* try specified wavetable driver */ retval = wtbl_init (); /* initialize the driver */ if (retval) log_message (_("Wavetable driver initialized")); else logit (LogFubar, _("Wavetable driver failed")); return (retval); } else return (wtbl_auto_detect ()); /* auto detect wavetable driver */}/* "auto" detect wavetable routine (just tries each one until one loads) */static gintwtbl_auto_detect (void){ char *name; gint i; log_message (_("Looking for supported wavetable driver...")); if (WTBL_COUNT <= 1) { log_message (_("No wavetable drivers were compiled into Smurf!")); return (FAIL); /* Only dummy driver exists */ } for (i = 1; i < WTBL_COUNT; i++) { name = _(wtbl_drivers[i].name); log_message (_("Trying driver %s..."), name); if (wtbl_drivers[i].init) { if ((*wtbl_drivers[i].init) ()) { log_message (_("Initialization of %s driver successful"), name); wtbl_driver = i; wtbl_active = TRUE; log_message (_("Using supported driver %s"), name); return (OK); } else log_message (_("Driver %s failed"), name); } } log_message (_("Failed to find a supported wavetable driver!")); return (FAIL);}/* Sets active wavetable driver to one specified by its ID */voidwtbl_set_driver (guint drvr_id){ if (drvr_id >= WTBL_COUNT) return; wtbl_driver = drvr_id;}/* Find a driver by its name, return ID */gintwtbl_locate_byname (gchar * name){ gint i; for (i = 0; i < WTBL_COUNT; i++) { if (strcmp (name, wtbl_drivers[i].name) == 0) return (i); } return (-1);}/* silence audible (currently just clears variables) */static voidwtbl_silence_temp_audible (void){ wtbl_temp_audible = SFITEMID_NONE;}/* sound font element change notification (for wavetable refresh) */voidwtbl_sfitem_changed (SFItemID itemid, WTblItemChange change){ if (wtbl_temp_audible != SFITEMID_NONE) /* a temporary audible is loaded? */ { if (itemid == wtbl_temp_audible) /* temp audible changed? */ { if (change == WTBL_ITEM_CHANGE) wtbl_temp_audible_changed = TRUE; else wtbl_silence_temp_audible (); /* item deleted, silence audible */ } } if (wtbl_loaded_sfbank != SFITEMID_NONE) /* a sfont bank is loaded? */ { GtkCTreeNode *node; SFTreeRef *ref; UISFont *loaded_uisf; /* if loaded bank is a sound font (as apposed to a vbank) */ node = SFTREE_LOOKUP_ITEMID (wtbl_loaded_sfbank); if (node && (ref = SFTREE_NODE_REF (node))->type == NODE_SFONT) { loaded_uisf = (UISFont *)(ref->dptr); /* if item's sound font is the same as loaded sound font */ node = SFTREE_LOOKUP_ITEMID (itemid); if (node && SFTREE_UPFIND_UISF (node) == loaded_uisf) { ref = SFTREE_NODE_REF (node); /* if recursive bank refresh is active or item is a preset */ if ((wtbl_recursive_bank_refresh && wtbl_cache_samples) || ref->type == NODE_PRESET) { wtbl_loaded_sfbank_changed = TRUE; if (!wtbl_changed_loaded_sfitems) wtbl_changed_loaded_sfitems = g_tree_new (wtbl_ptr_compare_func); /* add to tree of changed items (tree merges duplicates) */ g_tree_insert (wtbl_changed_loaded_sfitems, GINT_TO_POINTER (itemid), GINT_TO_POINTER (TRUE)); } } } }}/* a little temporary bag for the next 2 functions */typedef struct{ GTree *presets; SFData *sf;} TmpBagPDepends;voidwtbl_note_on_notify (void){ GtkCTreeNode *node; SFTreeRef *ref; UISFont *uisf; SFSample *sam; /* temporary audible need reloading? */ if (wtbl_temp_audible_changed && wtbl_temp_audible != SFITEMID_NONE && (node = SFTREE_LOOKUP_ITEMID (wtbl_temp_audible))) { ref = SFTREE_NODE_REF (node); uisf = SFTREE_UPFIND_UISF (node); switch (ref->type) { case NODE_PRESET: wtbl_load_temp_preset ((SFPreset *)(((GSList *)(ref->dptr))->data), uisf->sf); break; case NODE_INST: wtbl_load_temp_inst ((SFInst *)(((GSList *)(ref->dptr))->data), uisf->sf); break; case NODE_SAMPLE: sam = (SFSample *)(((GSList *)(ref->dptr))->data); /* AWE driver doesn't support reloading of sample info, so force reload of sample data */ wtbl_clear_sample_patch_id (sam, FALSE); wtbl_load_temp_sam_as_inst(sam, uisf->sf); break; default: break; } /* hack for OSS AWE driver, blasted thing resets bank:preset to 0:0 after some wavetable operations (not sure which) */ uipiano_refresh_bank_preset (); } if (wtbl_loaded_sfbank_changed && wtbl_loaded_sfbank != SFITEMID_NONE) { /* item in loaded sfont changed? */ TmpBagPDepends pdeps; if (!(node = SFTREE_LOOKUP_ITEMID (wtbl_loaded_sfbank))) return; if (SFTREE_NODE_REF (node)->type != NODE_SFONT) return; pdeps.sf = SFTREE_SFNODE_SFONT (node); pdeps.presets = g_tree_new (wtbl_ptr_compare_func); g_tree_traverse (wtbl_changed_loaded_sfitems, wtbl_GTraverseFunc_preset_dependents, G_IN_ORDER, &pdeps); /* don't need changed item tree anymore, so kill */ g_tree_destroy (wtbl_changed_loaded_sfitems); wtbl_changed_loaded_sfitems = NULL; /* open patch (with sample locking, no samples loaded, but we want to use the same set of samples) */ if (!wtbl_open_patch (TRUE)) return; /* load each changed preset */ g_tree_traverse (pdeps.presets, wtbl_GTraverseFunc_load_preset, G_IN_ORDER, pdeps.sf); wtbl_close_patch (); wtbl_loaded_sfbank_changed = FALSE; }}static gintwtbl_GTraverseFunc_preset_dependents (gpointer key, gpointer value, gpointer data){ TmpBagPDepends *pdeps = data; GtkCTreeNode *node; SFTreeRef *ref; SFPreset *pset; SFZone *zone; GSList *p, *p2; if (!(node = SFTREE_LOOKUP_ITEMID (GPOINTER_TO_INT (key)))) return (FALSE); ref = SFTREE_NODE_REF (node); switch (ref->type) { case NODE_PRESET: /* item is a preset, add it to tree */ g_tree_insert (pdeps->presets, ((GSList *)(ref->dptr))->data, GINT_TO_POINTER (TRUE)); break; case NODE_INST: /* item is instrument, add preset dependents */ p = pdeps->sf->preset; while (p) { pset = (SFPreset *)(p->data); p2 = pset->zone; while (p2) { zone = (SFZone *)(p2->data); if (zone->instsamp == ref->dptr) { g_tree_insert (pdeps->presets, pset, GINT_TO_POINTER (TRUE)); break; } p2 = g_slist_next (p2); } p = g_slist_next (p); } break; case NODE_SAMPLE: /* grrr, have to reload sample data! */ break; default: break; } return (FALSE); /* don't stop traversal */}static gintwtbl_GTraverseFunc_load_preset (gpointer key, gpointer value, gpointer data){ SFData *sf = data; SFPreset *pset = key; wtbl_load_preset_real (pset->bank, pset->prenum, pset, sf); return (FALSE); /* don't stop traversal */}static gintwtbl_ptr_compare_func (gconstpointer p1, gconstpointer p2){ if (p1 < p2) return (-1); if (p1 > p2) return (1); return (0);}/* calculate wavetable sample data allocation required for sound font */static gintwtbl_sfont_mem_required (SFData *sf){ GTree *gtree; SFPreset *pset; GSList *p; gint size = 0; gint rv; /* binary tree to count multi-used sample data only once */ gtree = g_tree_new (wtbl_ptr_compare_func); p = sf->preset; while (p) /* calc required mem for each preset */ { pset = (SFPreset *)(p->data); rv = wtbl_preset_mem_required (pset, sf, TRUE, gtree); if (rv == -1) break; size += rv; p = g_slist_next (p); } g_tree_destroy (gtree); if (p == NULL) return (size); /* all presets processed? */ else return (-1); /* ?: NO, error occured */}/* calculate wavetable sample data allocation required for virtual bank */static gintwtbl_vbank_mem_required (VBnkData *vbnk){ GTree *gtree; GList *psetmaps, *p; VBnkPresetMap *pmap; gint size = 0; gint rv; /* binary tree to count duplicates only once */ gtree = g_tree_new (wtbl_ptr_compare_func); /* get list of preset maps (VBnkPresetMap's are SFPresets with mapped bank:preset) */ psetmaps = vbank_get_preset_maps (vbnk); p = psetmaps; while (p) /* loop over preset maps */ { pmap = (VBnkPresetMap *)(p->data); /* calculate size of preset */ rv = wtbl_preset_mem_required (pmap->preset, pmap->sf, TRUE, gtree); if (rv == -1) break; size += rv; p = g_list_next (p); } g_list_foreach (psetmaps, (GFunc)g_free, NULL); g_list_free (psetmaps); g_tree_destroy (gtree); if (p == NULL) return (size); /* make sure all presets processed */ else return (-1); /* nope, error occured */}/* amount of sample memory required to load a preset */static gintwtbl_preset_mem_required (SFPreset *pset, SFData *sf, gboolean locked, GTree *gt){ GTree *gtree; SFZone *z; GSList *p; gint size = 0; gint rv; /* create a binary tree if not supplied, for counting duplicates only once */ if (!gt) gtree = g_tree_new (wtbl_ptr_compare_func); else gtree = gt; p = pset->zone; while (p) /* loop over preset zones */ { z = (SFZone *)(p->data); if (z->instsamp) { rv = wtbl_inst_mem_required ((SFInst *)(((GSList *)(z->instsamp)) ->data), sf, locked, gtree); if (rv == -1) break; /* error occured? */ size += rv; } p = g_slist_next (p); } if (!gt) g_tree_destroy (gtree); if (p == NULL) return (size); /* all preset zones processed? */ else return (-1); /* ?: NO, error occured */}/* amount of sample memory required to load an instrument */static gintwtbl_inst_mem_required (SFInst *inst, SFData *sf, gboolean locked, GTree *gt){ GTree *gtree; SFZone *z; SFSample *sam; GSList *p; gint size = 0; gint rv; /* create a binary tree if not supplied, for counting duplicates only once */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -