fluid_settings.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:42k
源码类别:

midi

开发平台:

C/C++

  1. /* FluidSynth - A Software Synthesizer
  2.  *
  3.  * Copyright (C) 2003  Peter Hanappe and others.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Library General Public License
  7.  * as published by the Free Software Foundation; either version 2 of
  8.  * the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Library General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Library General Public
  16.  * License along with this library; if not, write to the Free
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18.  * 02111-1307, USA
  19.  */
  20. #include "fluidsynth_priv.h"
  21. #include "fluid_sys.h"
  22. #include "fluid_hash.h"
  23. #include "fluid_synth.h"
  24. #include "fluid_cmd.h"
  25. #include "fluid_adriver.h"
  26. #include "fluid_mdriver.h"
  27. #include "fluid_settings.h"
  28. #include "fluid_midi.h"
  29. /* Defined in fluid_filerenderer.c */
  30. extern void fluid_file_renderer_settings (fluid_settings_t* settings);
  31. /* maximum allowed components of a settings variable (separated by '.') */
  32. #define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */
  33. #define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */
  34. static void fluid_settings_init(fluid_settings_t* settings);
  35. static void fluid_settings_key_destroy_func(void* value);
  36. static void fluid_settings_value_destroy_func(void* value);
  37. static int fluid_settings_tokenize(const char *s, char *buf, char **ptr);
  38. /* Common structure to all settings nodes */
  39. typedef struct {
  40.   int type;             /**< fluid_types_enum */
  41. } fluid_setting_node_t; 
  42. typedef struct {
  43.   fluid_setting_node_t node;
  44.   char* value;
  45.   char* def;
  46.   int hints;
  47.   fluid_list_t* options;
  48.   fluid_str_update_t update;
  49.   void* data;
  50. } fluid_str_setting_t;
  51. typedef struct {
  52.   fluid_setting_node_t node;
  53.   double value;
  54.   double def;
  55.   double min;
  56.   double max;
  57.   int hints;
  58.   fluid_num_update_t update;
  59.   void* data;
  60. } fluid_num_setting_t;
  61. typedef struct {
  62.   fluid_setting_node_t node;
  63.   int value;
  64.   int def;
  65.   int min;
  66.   int max;
  67.   int hints;
  68.   fluid_int_update_t update;
  69.   void* data;
  70. } fluid_int_setting_t;
  71. typedef struct {
  72.   fluid_setting_node_t node;
  73.   fluid_hashtable_t *hashtable;
  74. } fluid_set_setting_t;
  75. static fluid_str_setting_t*
  76. new_fluid_str_setting(const char* value, char* def, int hints, fluid_str_update_t fun, void* data)
  77. {
  78.   fluid_str_setting_t* str;
  79.   str = FLUID_NEW(fluid_str_setting_t);
  80.   if (!str)
  81.   {
  82.     FLUID_LOG(FLUID_ERR, "Out of memory");
  83.     return NULL;
  84.   }
  85.   str->node.type = FLUID_STR_TYPE;
  86.   str->value = value? FLUID_STRDUP(value) : NULL;
  87.   str->def = def? FLUID_STRDUP(def) : NULL;
  88.   str->hints = hints;
  89.   str->options = NULL;
  90.   str->update = fun;
  91.   str->data = data;
  92.   return str;
  93. }
  94. static void
  95. delete_fluid_str_setting(fluid_str_setting_t* str)
  96. {
  97.   if (!str) return;
  98.   if (str->value) FLUID_FREE(str->value);
  99.   if (str->def) FLUID_FREE(str->def);
  100.   if (str->options) {
  101.     fluid_list_t* list = str->options;
  102.     while (list) {
  103.       FLUID_FREE (list->data);
  104.       list = fluid_list_next(list);
  105.     }
  106.     delete_fluid_list(str->options);
  107.   }
  108.   FLUID_FREE(str);
  109. }
  110. static fluid_num_setting_t*
  111. new_fluid_num_setting(double min, double max, double def,
  112.      int hints, fluid_num_update_t fun, void* data)
  113. {
  114.   fluid_num_setting_t* setting;
  115.   setting = FLUID_NEW(fluid_num_setting_t);
  116.   if (!setting)
  117.   {
  118.     FLUID_LOG(FLUID_ERR, "Out of memory");
  119.     return NULL;
  120.   }
  121.   setting->node.type = FLUID_NUM_TYPE;
  122.   setting->value = def;
  123.   setting->def = def;
  124.   setting->min = min;
  125.   setting->max = max;
  126.   setting->hints = hints;
  127.   setting->update = fun;
  128.   setting->data = data;
  129.   return setting;
  130. }
  131. static void
  132. delete_fluid_num_setting(fluid_num_setting_t* setting)
  133. {
  134.   if (setting) FLUID_FREE(setting);
  135. }
  136. static fluid_int_setting_t*
  137. new_fluid_int_setting(int min, int max, int def,
  138.      int hints, fluid_int_update_t fun, void* data)
  139. {
  140.   fluid_int_setting_t* setting;
  141.   setting = FLUID_NEW(fluid_int_setting_t);
  142.   if (!setting)
  143.   {
  144.     FLUID_LOG(FLUID_ERR, "Out of memory");
  145.     return NULL;
  146.   }
  147.   setting->node.type = FLUID_INT_TYPE;
  148.   setting->value = def;
  149.   setting->def = def;
  150.   setting->min = min;
  151.   setting->max = max;
  152.   setting->hints = hints;
  153.   setting->update = fun;
  154.   setting->data = data;
  155.   return setting;
  156. }
  157. static void
  158. delete_fluid_int_setting(fluid_int_setting_t* setting)
  159. {
  160.   if (setting) FLUID_FREE(setting);
  161. }
  162. static fluid_set_setting_t*
  163. new_fluid_set_setting(void)
  164. {
  165.   fluid_set_setting_t* setting;
  166.   setting = FLUID_NEW(fluid_set_setting_t);
  167.   if (!setting)
  168.   {
  169.     FLUID_LOG(FLUID_ERR, "Out of memory");
  170.     return NULL;
  171.   }
  172.   setting->node.type = FLUID_SET_TYPE;
  173.   setting->hashtable = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
  174.                                                 fluid_settings_key_destroy_func,
  175.                                                 fluid_settings_value_destroy_func);
  176.   if (!setting->hashtable)
  177.   {
  178.     FLUID_FREE (setting);
  179.     return NULL;
  180.   }
  181.   return setting;
  182. }
  183. static void
  184. delete_fluid_set_setting(fluid_set_setting_t* setting)
  185. {
  186.   if (setting)
  187.   {
  188.     delete_fluid_hashtable(setting->hashtable);
  189.     FLUID_FREE(setting);
  190.   }
  191. }
  192. /**
  193.  * Create a new settings object
  194.  * @return the pointer to the settings object
  195.  */
  196. fluid_settings_t *
  197. new_fluid_settings(void)
  198. {
  199.   fluid_settings_t* settings;
  200.   settings = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
  201.                                       fluid_settings_key_destroy_func,
  202.                                       fluid_settings_value_destroy_func);
  203.   if (settings == NULL) return NULL;
  204.   fluid_rec_mutex_init (settings->mutex);
  205.   fluid_settings_init(settings);
  206.   return settings;
  207. }
  208. /**
  209.  * Delete the provided settings object
  210.  * @param settings a settings object
  211.  */
  212. void
  213. delete_fluid_settings(fluid_settings_t* settings)
  214. {
  215.   fluid_return_if_fail (settings != NULL);
  216.   fluid_rec_mutex_destroy (settings->mutex);
  217.   delete_fluid_hashtable(settings);
  218. }
  219. /* Settings hash key destroy function */
  220. static void
  221. fluid_settings_key_destroy_func(void* value)
  222. {
  223.   FLUID_FREE (value);   /* Free the string key value */
  224. }
  225. /* Settings hash value destroy function */
  226. static void
  227. fluid_settings_value_destroy_func(void* value)
  228. {
  229.   fluid_setting_node_t *node = value;
  230.   switch (node->type) {
  231.   case FLUID_NUM_TYPE:
  232.     delete_fluid_num_setting((fluid_num_setting_t*) value);
  233.     break;
  234.   case FLUID_INT_TYPE:
  235.     delete_fluid_int_setting((fluid_int_setting_t*) value);
  236.     break;
  237.   case FLUID_STR_TYPE:
  238.     delete_fluid_str_setting((fluid_str_setting_t*) value);
  239.     break;
  240.   case FLUID_SET_TYPE:
  241.     delete_fluid_set_setting((fluid_set_setting_t*) value);
  242.     break;
  243.   }
  244. }
  245. void
  246. fluid_settings_init(fluid_settings_t* settings)
  247. {
  248.   fluid_return_if_fail (settings != NULL);
  249.   fluid_synth_settings(settings);
  250.   fluid_shell_settings(settings);
  251.   fluid_player_settings(settings);
  252.   fluid_file_renderer_settings(settings);
  253.   fluid_audio_driver_settings(settings);
  254.   fluid_midi_driver_settings(settings);
  255. }
  256. static int
  257. fluid_settings_tokenize(const char *s, char *buf, char **ptr)
  258. {
  259.   char *tokstr, *tok;
  260.   int n = 0;
  261.   if (strlen (s) > MAX_SETTINGS_LABEL)
  262.   {
  263.     FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
  264.       MAX_SETTINGS_LABEL);
  265.     return 0;
  266.   }
  267.   FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
  268.   tokstr = buf;
  269.   while ((tok = fluid_strtok (&tokstr, ".")))
  270.   {
  271.     if (n > MAX_SETTINGS_TOKENS)
  272.     {
  273.       FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
  274. MAX_SETTINGS_TOKENS);
  275.       return 0;
  276.     }
  277.     ptr[n++] = tok;
  278.   }
  279.   return n;
  280. }
  281. /**
  282.  * Get a setting name, value and type
  283.  *
  284.  * @param settings a settings object
  285.  * @param name Settings name
  286.  * @param value Location to store setting node if found
  287.  * @return 1 if the node exists, 0 otherwise
  288.  */
  289. static int
  290. fluid_settings_get(fluid_settings_t* settings, const char *name,
  291.                    fluid_setting_node_t **value)
  292. {
  293.   fluid_hashtable_t* table = settings;
  294.   fluid_setting_node_t *node = NULL;
  295.   char* tokens[MAX_SETTINGS_TOKENS];
  296.   char buf[MAX_SETTINGS_LABEL+1];
  297.   int ntokens;
  298.   int n;
  299.   ntokens = fluid_settings_tokenize (name, buf, tokens);
  300.   for (n = 0; n < ntokens; n++) {
  301.     if (table == NULL) return 0;
  302.     node = fluid_hashtable_lookup(table, tokens[n]);
  303.     if (!node) return 0;
  304.     table = (node->type == FLUID_SET_TYPE) ? ((fluid_set_setting_t *)node)->hashtable : NULL;
  305.   }
  306.   if (value) *value = node;
  307.   return 1;
  308. }
  309. /**
  310.  * Set a setting name, value and type, replacing it if already exists
  311.  *
  312.  * @param settings a settings object
  313.  * @param name Settings name
  314.  * @param value Node instance to assign (used directly)
  315.  * @return 1 if the value has been set, zero otherwise
  316.  */
  317. static int
  318. fluid_settings_set(fluid_settings_t* settings, const char *name, void* value)
  319. {
  320.   fluid_hashtable_t* table = settings;
  321.   fluid_setting_node_t *node;
  322.   char* tokens[MAX_SETTINGS_TOKENS];
  323.   char buf[MAX_SETTINGS_LABEL+1];
  324.   int n, num;
  325.   char *dupname;
  326.   num = fluid_settings_tokenize (name, buf, tokens) - 1;
  327.   for (n = 0; n < num; n++) {
  328.     node = fluid_hashtable_lookup(table, tokens[n]);
  329.     if (node) {
  330.       if (node->type == FLUID_SET_TYPE) {
  331. table = ((fluid_set_setting_t *)node)->hashtable;
  332.       } else {
  333. /* path ends prematurely */
  334. FLUID_LOG(FLUID_WARN, "'%s' is not a node", name[n]);
  335. return 0;
  336.       }
  337.     } else {
  338.       /* create a new node */
  339.       fluid_set_setting_t* setnode;
  340.       dupname = FLUID_STRDUP (tokens[n]);
  341.       setnode = new_fluid_set_setting ();
  342.       if (!dupname || !setnode)
  343.       {
  344.         if (dupname) FLUID_FREE (dupname);
  345.         else FLUID_LOG(FLUID_ERR, "Out of memory");
  346.         if (setnode) delete_fluid_set_setting (setnode);
  347.         return 0;
  348.       }
  349.       fluid_hashtable_insert(table, dupname, setnode);
  350.       table = setnode->hashtable;
  351.     }
  352.   }
  353.   dupname = FLUID_STRDUP (tokens[num]);
  354.   if (!dupname)
  355.   {
  356.     FLUID_LOG(FLUID_ERR, "Out of memory");
  357.     return 0;
  358.   }
  359.   fluid_hashtable_insert(table, dupname, value);
  360.   return 1;
  361. }
  362. /** returns 1 if the value has been registered correctly, 0
  363.     otherwise */
  364. int
  365. fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, int hints,
  366.     fluid_str_update_t fun, void* data)
  367. {
  368.   fluid_setting_node_t *node;
  369.   fluid_str_setting_t* setting;
  370.   int retval;
  371.   fluid_return_val_if_fail (settings != NULL, 0);
  372.   fluid_return_val_if_fail (name != NULL, 0);
  373.   fluid_rec_mutex_lock (settings->mutex);
  374.   if (!fluid_settings_get(settings, name, &node)) {
  375.     setting = new_fluid_str_setting(def, def, hints, fun, data);
  376.     retval = fluid_settings_set(settings, name, setting);
  377.     if (retval != 1) delete_fluid_str_setting (setting);
  378.   } else {
  379.     /* if variable already exists, don't change its value. */
  380.     if (node->type == FLUID_STR_TYPE) {
  381.       setting = (fluid_str_setting_t*) node;
  382.       setting->update = fun;
  383.       setting->data = data;
  384.       setting->def = def? FLUID_STRDUP(def) : NULL;
  385.       setting->hints = hints;
  386.       retval = 1;
  387.     } else {
  388.       FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
  389.       retval = 0;
  390.     }
  391.   }
  392.   fluid_rec_mutex_unlock (settings->mutex);
  393.   return retval;
  394. }
  395. /** returns 1 if the value has been register correctly, zero
  396.     otherwise */
  397. int
  398. fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
  399.     double min, double max, int hints,
  400.     fluid_num_update_t fun, void* data)
  401. {
  402.   fluid_setting_node_t *node;
  403.   int retval;
  404.   fluid_return_val_if_fail (settings != NULL, 0);
  405.   fluid_return_val_if_fail (name != NULL, 0);
  406.   /* For now, all floating point settings are bounded below and above */
  407.   hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
  408.   fluid_rec_mutex_lock (settings->mutex);
  409.   if (!fluid_settings_get(settings, name, &node)) {
  410.     /* insert a new setting */
  411.     fluid_num_setting_t* setting;
  412.     setting = new_fluid_num_setting(min, max, def, hints, fun, data);
  413.     retval = fluid_settings_set(settings, name, setting);
  414.     if (retval != 1) delete_fluid_num_setting (setting);
  415.   } else {
  416.     if (node->type == FLUID_NUM_TYPE) {
  417.       /* update the existing setting but don't change its value */
  418.       fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
  419.       setting->update = fun;
  420.       setting->data = data;
  421.       setting->min = min;
  422.       setting->max = max;
  423.       setting->def = def;
  424.       setting->hints = hints;
  425.       retval = 1;
  426.     } else {
  427.       /* type mismatch */
  428.       FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
  429.       retval = 0;
  430.     }
  431.   }
  432.   fluid_rec_mutex_unlock (settings->mutex);
  433.   return retval;
  434. }
  435. /** returns 1 if the value has been register correctly, zero
  436.     otherwise. */
  437. int
  438. fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
  439.     int min, int max, int hints,
  440.     fluid_int_update_t fun, void* data)
  441. {
  442.   fluid_setting_node_t *node;
  443.   int retval;
  444.   fluid_return_val_if_fail (settings != NULL, 0);
  445.   fluid_return_val_if_fail (name != NULL, 0);
  446.   /* For now, all integer settings are bounded below and above */
  447.   hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
  448.   fluid_rec_mutex_lock (settings->mutex);
  449.   if (!fluid_settings_get(settings, name, &node)) {
  450.     /* insert a new setting */
  451.     fluid_int_setting_t* setting;
  452.     setting = new_fluid_int_setting(min, max, def, hints, fun, data);
  453.     retval = fluid_settings_set(settings, name, setting);
  454.     if (retval != 1) delete_fluid_int_setting (setting);
  455.   } else {
  456.     if (node->type == FLUID_INT_TYPE) {
  457.       /* update the existing setting but don't change its value */
  458.       fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
  459.       setting->update = fun;
  460.       setting->data = data;
  461.       setting->min = min;
  462.       setting->max = max;
  463.       setting->def = def;
  464.       setting->hints = hints;
  465.       retval = 1;
  466.     } else {
  467.       /* type mismatch */
  468.       FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
  469.       retval = 0;
  470.     }
  471.   }
  472.   fluid_rec_mutex_unlock (settings->mutex);
  473.   return retval;
  474. }
  475. /**
  476.  * Get the type of the setting with the given name
  477.  *
  478.  * @param settings a settings object
  479.  * @param name a setting's name
  480.  * @return the type for the named setting, or #FLUID_NO_TYPE when it does not exist
  481.  */
  482. int
  483. fluid_settings_get_type(fluid_settings_t* settings, const char *name)
  484. {
  485.   fluid_setting_node_t *node;
  486.   int type;
  487.   fluid_return_val_if_fail (settings != NULL, FLUID_NO_TYPE);
  488.   fluid_return_val_if_fail (name != NULL, FLUID_NO_TYPE);
  489.   fluid_rec_mutex_lock (settings->mutex);
  490.   type = fluid_settings_get (settings, name, &node) ? node->type : FLUID_NO_TYPE;
  491.   fluid_rec_mutex_unlock (settings->mutex);
  492.   return (type);
  493. }
  494. /**
  495.  * Get the hints for the named setting as an integer bitmap
  496.  *
  497.  * @param settings a settings object
  498.  * @param name a setting's name
  499.  * @return the hints associated to the named setting if it exists, zero otherwise
  500.  */
  501. int
  502. fluid_settings_get_hints(fluid_settings_t* settings, const char *name)
  503. {
  504.   fluid_setting_node_t *node;
  505.   int hints = 0;
  506.   fluid_return_val_if_fail (settings != NULL, 0);
  507.   fluid_return_val_if_fail (name != NULL, 0);
  508.   fluid_rec_mutex_lock (settings->mutex);
  509.   if (fluid_settings_get(settings, name, &node)) {
  510.     if (node->type == FLUID_NUM_TYPE) {
  511.       fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
  512.       hints = setting->hints;
  513.     } else if (node->type == FLUID_STR_TYPE) {
  514.       fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
  515.       hints = setting->hints;
  516.     } else if (node->type == FLUID_INT_TYPE) {
  517.       fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
  518.       hints = setting->hints;
  519.     }
  520.   }
  521.   fluid_rec_mutex_unlock (settings->mutex);
  522.   return hints;
  523. }
  524. /**
  525.  * Ask whether the setting is changeable in real-time.
  526.  *
  527.  * @param settings a settings object
  528.  * @param name a setting's name
  529.  * @return non zero if the setting is changeable in real-time
  530.  */
  531. int
  532. fluid_settings_is_realtime(fluid_settings_t* settings, const char *name)
  533. {
  534.   fluid_setting_node_t *node;
  535.   int isrealtime = FALSE;
  536.   fluid_return_val_if_fail (settings != NULL, 0);
  537.   fluid_return_val_if_fail (name != NULL, 0);
  538.   fluid_rec_mutex_lock (settings->mutex);
  539.   if (fluid_settings_get(settings, name, &node)) {
  540.     if (node->type == FLUID_NUM_TYPE) {
  541.       fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
  542.       isrealtime = setting->update != NULL;
  543.     } else if (node->type == FLUID_STR_TYPE) {
  544.       fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
  545.       isrealtime = setting->update != NULL;
  546.     } else if (node->type == FLUID_INT_TYPE) {
  547.       fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
  548.       isrealtime = setting->update != NULL;
  549.     }
  550.   }
  551.   fluid_rec_mutex_unlock (settings->mutex);
  552.   return isrealtime;
  553. }
  554. /**
  555.  * Set a string value for a named setting
  556.  *
  557.  * @param settings a settings object
  558.  * @param name a setting's name
  559.  * @param str new string value
  560.  * @return 1 if the value has been set, 0 otherwise
  561.  */
  562. int
  563. fluid_settings_setstr(fluid_settings_t* settings, const char *name, const char *str)
  564. {
  565.   fluid_setting_node_t *node;
  566.   int retval = 0;
  567.   fluid_return_val_if_fail (settings != NULL, 0);
  568.   fluid_return_val_if_fail (name != NULL, 0);
  569.   fluid_rec_mutex_lock (settings->mutex);
  570.   if (fluid_settings_get (settings, name, &node)) {
  571.     if (node->type == FLUID_STR_TYPE) {
  572.       fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
  573.       if (setting->value) FLUID_FREE (setting->value);
  574.       setting->value = str ? FLUID_STRDUP (str) : NULL;
  575.       /* Call under lock to keep update() synchronized with the current value */
  576.       if (setting->update) (*setting->update)(setting->data, name, str);
  577.       retval = 1;
  578.     }
  579.     else if (node->type == FLUID_INT_TYPE)      /* Handle yes/no for boolean values for backwards compatibility */
  580.     {
  581.       fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
  582.       if (setting->hints & FLUID_HINT_TOGGLED)
  583.       {
  584.         if (FLUID_STRCMP (str, "yes") == 0)
  585.         {
  586.           setting->value = TRUE;
  587.           if (setting->update) (*setting->update)(setting->data, name, TRUE);
  588.         }
  589.         else if (FLUID_STRCMP (str, "no") == 0)
  590.         {
  591.           setting->value = FALSE;
  592.           if (setting->update) (*setting->update)(setting->data, name, FALSE);
  593.         }
  594.       }
  595.     }
  596.   } else {
  597.     /* insert a new setting */
  598.     fluid_str_setting_t* setting;
  599.     setting = new_fluid_str_setting(str, NULL, 0, NULL, NULL);
  600.     retval = fluid_settings_set(settings, name, setting);
  601.     if (retval != 1) delete_fluid_str_setting (setting);
  602.   }
  603.   fluid_rec_mutex_unlock (settings->mutex);
  604.   return retval;
  605. }
  606. /**
  607.  * Copy the value of a string setting
  608.  * @param settings a settings object
  609.  * @param name a setting's name
  610.  * @param str Caller supplied buffer to copy string value to
  611.  * @param len Size of 'str' buffer (no more than len bytes will be written, which
  612.  *   will always include a zero terminator)
  613.  * @return 1 if the value exists, 0 otherwise
  614.  * @since 1.1.0
  615.  *
  616.  * Like fluid_settings_getstr() but is thread safe.  A size of 256 should be
  617.  * more than sufficient for the string buffer.
  618.  */
  619. int
  620. fluid_settings_copystr(fluid_settings_t* settings, const char *name,
  621.                        char *str, int len)
  622. {
  623.   fluid_setting_node_t *node;
  624.   int retval = 0;
  625.   fluid_return_val_if_fail (settings != NULL, 0);
  626.   fluid_return_val_if_fail (name != NULL, 0);
  627.   fluid_return_val_if_fail (str != NULL, 0);
  628.   fluid_return_val_if_fail (len > 0, 0);
  629.   str[0] = 0;
  630.   fluid_rec_mutex_lock (settings->mutex);
  631.   if (fluid_settings_get (settings, name, &node))
  632.   {
  633.     if (node->type == FLUID_STR_TYPE)
  634.     {
  635.       fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
  636.       if (setting->value)
  637.       {
  638.         FLUID_STRNCPY (str, setting->value, len);
  639.         str[len - 1] = 0;   /* Force terminate, in case of truncation */
  640.       }
  641.       retval = 1;
  642.     }
  643.     else if (node->type == FLUID_INT_TYPE)      /* Handle boolean integers for backwards compatibility */
  644.     {
  645.       fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
  646.       if (setting->hints & FLUID_HINT_TOGGLED)
  647.       {
  648.         FLUID_STRNCPY (str, setting->value ? "yes" : "no", len);
  649.         str[len - 1] = 0;   /* Force terminate, in case of truncation */
  650.         retval = 1;
  651.       }
  652.     }
  653.   }
  654.   fluid_rec_mutex_unlock (settings->mutex);
  655.   return retval;
  656. }
  657. /**
  658.  * Duplicate the value of a string setting
  659.  * @param settings a settings object
  660.  * @param name a setting's name
  661.  * @param str Location to store pointer to allocated duplicate string
  662.  * @return 1 if the value exists and was successfully duplicated, 0 otherwise
  663.  * @since 1.1.0
  664.  *
  665.  * Like fluid_settings_copystr() but allocates a new copy of the string.  Caller
  666.  * owns the string and should free it with free() when done using it.
  667.  */
  668. int
  669. fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str)
  670. {
  671.   fluid_setting_node_t *node;
  672.   int retval = 0;
  673.   fluid_return_val_if_fail (settings != NULL, 0);
  674.   fluid_return_val_if_fail (name != NULL, 0);
  675.   fluid_return_val_if_fail (str != NULL, 0);
  676.   fluid_rec_mutex_lock (settings->mutex);
  677.   if (fluid_settings_get(settings, name, &node))
  678.   {
  679.     if (node->type == FLUID_STR_TYPE)
  680.     {
  681.       fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
  682.       if (setting->value)
  683.       {
  684.         *str = FLUID_STRDUP (setting->value);
  685.         if (!*str) FLUID_LOG (FLUID_ERR, "Out of memory");
  686.       }
  687.       if (!setting->value || *str) retval = 1;    /* Don't set to 1 if out of memory */
  688.     }
  689.     else if (node->type == FLUID_INT_TYPE)      /* Handle boolean integers for backwards compatibility */
  690.     {
  691.       fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
  692.       if (setting->hints & FLUID_HINT_TOGGLED)
  693.       {
  694.         *str = FLUID_STRDUP (setting->value ? "yes" : "no");
  695.         if (!*str) FLUID_LOG (FLUID_ERR, "Out of memory");
  696.         if (!setting->value || *str) retval = 1;    /* Don't set to 1 if out of memory */
  697.       }
  698.     }
  699.   }
  700.   fluid_rec_mutex_unlock (settings->mutex);
  701.   return retval;
  702. }
  703. /**
  704.  * Get the value of a string setting
  705.  * @param settings a settings object
  706.  * @param name a setting's name
  707.  * @param str Location to store pointer to the settings string value
  708.  * @return 1 if the value exists, 0 otherwise
  709.  * @deprecated
  710.  *
  711.  * If the value does not exists, 'str' is set to NULL. Otherwise, 'str' will
  712.  * point to the value. The application does not own the returned value and it
  713.  * is valid only until a new value is assigned to the setting of the given name.
  714.  *
  715.  * NOTE: In a multi-threaded environment, caller must ensure that the setting
  716.  * being read by fluid_settings_getstr() is not assigned during the
  717.  * duration of callers use of the setting's value.  Use fluid_settings_copystr()
  718.  * or fluid_settings_dupstr() which does not have this restriction.
  719.  */
  720. int
  721. fluid_settings_getstr(fluid_settings_t* settings, const char *name, char** str)
  722. {
  723.   fluid_setting_node_t *node;
  724.   int retval = 0;
  725.   fluid_return_val_if_fail (settings != NULL, 0);
  726.   fluid_return_val_if_fail (name != NULL, 0);
  727.   fluid_return_val_if_fail (str != NULL, 0);
  728.   fluid_rec_mutex_lock (settings->mutex);
  729.   if (fluid_settings_get(settings, name, &node))
  730.   {
  731.     if (node->type == FLUID_STR_TYPE)
  732.     {
  733.       fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
  734.       *str = setting->value;
  735.       retval = 1;
  736.     }
  737.     else if (node->type == FLUID_INT_TYPE)      /* Handle boolean integers for backwards compatibility */
  738.     {
  739.       fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
  740.       if (setting->hints & FLUID_HINT_TOGGLED)
  741.       {
  742.         *str = setting->value ? "yes" : "no";
  743.         retval = 1;
  744.       }
  745.     }
  746.   }
  747.   else *str = NULL;
  748.   fluid_rec_mutex_unlock (settings->mutex);
  749.   return retval;
  750. }
  751. /**
  752.  * Test a string setting for some value.
  753.  *
  754.  * @param settings a settings object
  755.  * @param name a setting's name
  756.  * @param s a string to be tested
  757.  * @return 1 if the value exists and is equal to 's', 0 otherwise
  758.  */
  759. int
  760. fluid_settings_str_equal (fluid_settings_t* settings, const char *name, const char *s)
  761. {
  762.   fluid_setting_node_t *node;
  763.   int retval = 0;
  764.   fluid_return_val_if_fail (settings != NULL, 0);
  765.   fluid_return_val_if_fail (name != NULL, 0);
  766.   fluid_return_val_if_fail (s != NULL, 0);
  767.   fluid_rec_mutex_lock (settings->mutex);
  768.   if (fluid_settings_get (settings, name, &node))
  769.   {
  770.     if (node->type == FLUID_STR_TYPE)
  771.     {
  772.       fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
  773.       if (setting->value) retval = FLUID_STRCMP (setting->value, s) == 0;
  774.     }
  775.     else if (node->type == FLUID_INT_TYPE)      /* Handle boolean integers for backwards compatibility */
  776.     {
  777.       fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
  778.       if (setting->hints & FLUID_HINT_TOGGLED)
  779.         retval = FLUID_STRCMP (setting->value ? "yes" : "no", s) == 0;
  780.     }
  781.   }
  782.   fluid_rec_mutex_unlock (settings->mutex);
  783.   return retval;
  784. }
  785. /**
  786.  * Get the default value of a string setting.  Note that the returned string is
  787.  * not owned by the caller and should not be modified or freed.
  788.  *
  789.  * @param settings a settings object
  790.  * @param name a setting's name
  791.  * @return the default string value of the setting if it exists, NULL otherwise
  792.  */
  793. char*
  794. fluid_settings_getstr_default(fluid_settings_t* settings, const char *name)
  795. {
  796.   fluid_setting_node_t *node;
  797.   char *retval = NULL;
  798.   fluid_return_val_if_fail (settings != NULL, NULL);
  799.   fluid_return_val_if_fail (name != NULL, NULL);
  800.   fluid_rec_mutex_lock (settings->mutex);
  801.   if (fluid_settings_get (settings, name, &node))
  802.   {
  803.     if (node->type == FLUID_STR_TYPE)
  804.     {
  805.       fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
  806.       retval = setting->def;
  807.     }
  808.     else if (node->type == FLUID_INT_TYPE)      /* Handle boolean integers for backwards compatibility */
  809.     {
  810.       fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
  811.       if (setting->hints & FLUID_HINT_TOGGLED)
  812.         retval = setting->def ? "yes" : "no";
  813.     }
  814.   }
  815.   fluid_rec_mutex_unlock (settings->mutex);
  816.   return retval;
  817. }
  818. /**
  819.  * Add an option to a string setting (like an enumeration value).
  820.  * @param settings a settings object
  821.  * @param name a setting's name
  822.  * @param s option string to add
  823.  * @return 1 if the setting exists and option was added, 0 otherwise
  824.  *
  825.  * Causes the setting's #FLUID_HINT_OPTIONLIST hint to be set.
  826.  */
  827. int
  828. fluid_settings_add_option(fluid_settings_t* settings, const char *name, const char *s)
  829. {
  830.   fluid_setting_node_t *node;
  831.   int retval = 0;
  832.   fluid_return_val_if_fail (settings != NULL, 0);
  833.   fluid_return_val_if_fail (name != NULL, 0);
  834.   fluid_return_val_if_fail (s != NULL, 0);
  835.   fluid_rec_mutex_lock (settings->mutex);
  836.   if (fluid_settings_get(settings, name, &node)
  837.       && (node->type == FLUID_STR_TYPE)) {
  838.     fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
  839.     char* copy = FLUID_STRDUP(s);
  840.     setting->options = fluid_list_append(setting->options, copy);
  841.     setting->hints |= FLUID_HINT_OPTIONLIST;
  842.     retval = 1;
  843.   }
  844.   fluid_rec_mutex_unlock (settings->mutex);
  845.   return retval;
  846. }
  847. /**
  848.  * Remove an option previously assigned by fluid_settings_add_option().
  849.  * @param settings a settings object
  850.  * @param name a setting's name
  851.  * @param s option string to remove
  852.  * @return 1 if the setting exists and option was removed, 0 otherwise
  853.  */
  854. int
  855. fluid_settings_remove_option(fluid_settings_t* settings, const char *name, const char* s)
  856. {
  857.   fluid_setting_node_t *node;
  858.   int retval = 0;
  859.   fluid_return_val_if_fail (settings != NULL, 0);
  860.   fluid_return_val_if_fail (name != NULL, 0);
  861.   fluid_return_val_if_fail (s != NULL, 0);
  862.   fluid_rec_mutex_lock (settings->mutex);
  863.   if (fluid_settings_get(settings, name, &node)
  864.       && (node->type == FLUID_STR_TYPE)) {
  865.     fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
  866.     fluid_list_t* list = setting->options;
  867.     while (list) {
  868.       char* option = (char*) fluid_list_get(list);
  869.       if (FLUID_STRCMP(s, option) == 0) {
  870. FLUID_FREE (option);
  871. setting->options = fluid_list_remove_link(setting->options, list);
  872. retval = 1;
  873.         break;
  874.       }
  875.       list = fluid_list_next(list);
  876.     }
  877.   }
  878.   fluid_rec_mutex_unlock (settings->mutex);
  879.   return retval;
  880. }
  881. /**
  882.  * Set a numeric value for a named setting.
  883.  *
  884.  * @param settings a settings object
  885.  * @param name a setting's name
  886.  * @param val new setting's value
  887.  * @return 1 if the value has been set, 0 otherwise
  888.  */
  889. int
  890. fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val)
  891. {
  892.   fluid_setting_node_t *node;
  893.   fluid_num_setting_t* setting;
  894.   int retval = 0;
  895.   fluid_return_val_if_fail (settings != NULL, 0);
  896.   fluid_return_val_if_fail (name != NULL, 0);
  897.   fluid_rec_mutex_lock (settings->mutex);
  898.   if (fluid_settings_get(settings, name, &node)) {
  899.     if (node->type == FLUID_NUM_TYPE) {
  900.       setting = (fluid_num_setting_t*) node;
  901.       if (val < setting->min) val = setting->min;
  902.       else if (val > setting->max) val = setting->max;
  903.       setting->value = val;
  904.       /* Call under lock to keep update() synchronized with the current value */
  905.       if (setting->update) (*setting->update)(setting->data, name, val);
  906.       retval = 1;
  907.     }
  908.   } else {
  909.     /* insert a new setting */
  910.     fluid_num_setting_t* setting;
  911.     setting = new_fluid_num_setting(-1e10, 1e10, 0.0f, 0, NULL, NULL);
  912.     setting->value = val;
  913.     retval = fluid_settings_set(settings, name, setting);
  914.     if (retval != 1) delete_fluid_num_setting (setting);
  915.   }
  916.   fluid_rec_mutex_unlock (settings->mutex);
  917.   return retval;
  918. }
  919. /**
  920.  * Get the numeric value of a named setting
  921.  *
  922.  * @param settings a settings object
  923.  * @param name a setting's name
  924.  * @param val variable pointer to receive the setting's numeric value
  925.  * @return 1 if the value exists, 0 otherwise
  926.  */
  927. int
  928. fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val)
  929. {
  930.   fluid_setting_node_t *node;
  931.   int retval = 0;
  932.   fluid_return_val_if_fail (settings != NULL, 0);
  933.   fluid_return_val_if_fail (name != NULL, 0);
  934.   fluid_return_val_if_fail (val != NULL, 0);
  935.   fluid_rec_mutex_lock (settings->mutex);
  936.   if (fluid_settings_get(settings, name, &node)
  937.       && (node->type == FLUID_NUM_TYPE)) {
  938.     fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
  939.     *val = setting->value;
  940.     retval = 1;
  941.   }
  942.   fluid_rec_mutex_unlock (settings->mutex);
  943.   return retval;
  944. }
  945. /**
  946.  * Get the range of values of a numeric setting
  947.  *
  948.  * @param settings a settings object
  949.  * @param name a setting's name
  950.  * @param min setting's range lower limit
  951.  * @param max setting's range upper limit
  952.  */
  953. void
  954. fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
  955.                             double* min, double* max)
  956. {
  957.   fluid_setting_node_t *node;
  958.   fluid_return_if_fail (settings != NULL);
  959.   fluid_return_if_fail (name != NULL);
  960.   fluid_return_if_fail (min != NULL);
  961.   fluid_return_if_fail (max != NULL);
  962.   fluid_rec_mutex_lock (settings->mutex);
  963.   if (fluid_settings_get(settings, name, &node)
  964.       && (node->type == FLUID_NUM_TYPE)) {
  965.     fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
  966.     *min = setting->min;
  967.     *max = setting->max;
  968.   }
  969.   fluid_rec_mutex_unlock (settings->mutex);
  970. }
  971. /**
  972.  * Get the default value of a named numeric (double) setting
  973.  *
  974.  * @param settings a settings object
  975.  * @param name a setting's name
  976.  * @return the default value if the named setting exists, 0.0f otherwise
  977.  */
  978. double
  979. fluid_settings_getnum_default(fluid_settings_t* settings, const char *name)
  980. {
  981.   fluid_setting_node_t *node;
  982.   double retval = 0.0;
  983.   fluid_return_val_if_fail (settings != NULL, 0.0);
  984.   fluid_return_val_if_fail (name != NULL, 0.0);
  985.   fluid_rec_mutex_lock (settings->mutex);
  986.   if (fluid_settings_get(settings, name, &node)
  987.       && (node->type == FLUID_NUM_TYPE)) {
  988.     fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
  989.     retval = setting->def;
  990.   }
  991.   fluid_rec_mutex_unlock (settings->mutex);
  992.   return retval;
  993. }
  994. /**
  995.  * Set an integer value for a setting
  996.  *
  997.  * @param settings a settings object
  998.  * @param name a setting's name
  999.  * @param val new setting's integer value
  1000.  * @return 1 if the value has been set, 0 otherwise
  1001.  */
  1002. int
  1003. fluid_settings_setint(fluid_settings_t* settings, const char *name, int val)
  1004. {
  1005.   fluid_setting_node_t *node;
  1006.   fluid_int_setting_t* setting;
  1007.   int retval = 0;
  1008.   fluid_return_val_if_fail (settings != NULL, 0);
  1009.   fluid_return_val_if_fail (name != NULL, 0);
  1010.   fluid_rec_mutex_lock (settings->mutex);
  1011.   if (fluid_settings_get(settings, name, &node)) {
  1012.     if (node->type == FLUID_INT_TYPE) {
  1013.       setting = (fluid_int_setting_t*) node;
  1014.       if (val < setting->min) val = setting->min;
  1015.       else if (val > setting->max) val = setting->max;
  1016.       setting->value = val;
  1017.       /* Call under lock to keep update() synchronized with the current value */
  1018.       if (setting->update) (*setting->update)(setting->data, name, val);
  1019.       retval = 1;
  1020.     }
  1021.   } else {
  1022.     /* insert a new setting */
  1023.     fluid_int_setting_t* setting;
  1024.     setting = new_fluid_int_setting(INT_MIN, INT_MAX, 0, 0, NULL, NULL);
  1025.     setting->value = val;
  1026.     retval = fluid_settings_set(settings, name, setting);
  1027.     if (retval != 1) delete_fluid_int_setting (setting);
  1028.   }
  1029.   fluid_rec_mutex_unlock (settings->mutex);
  1030.   return retval;
  1031. }
  1032. /**
  1033.  * Get an integer value setting.
  1034.  *
  1035.  * @param settings a settings object
  1036.  * @param name a setting's name
  1037.  * @param val pointer to a variable to receive the setting's integer value
  1038.  * @return 1 if the value exists, 0 otherwise
  1039.  */
  1040. int
  1041. fluid_settings_getint(fluid_settings_t* settings, const char *name, int* val)
  1042. {
  1043.   fluid_setting_node_t *node;
  1044.   int retval = 0;
  1045.   fluid_return_val_if_fail (settings != NULL, 0);
  1046.   fluid_return_val_if_fail (name != NULL, 0);
  1047.   fluid_return_val_if_fail (val != NULL, 0);
  1048.   fluid_rec_mutex_lock (settings->mutex);
  1049.   if (fluid_settings_get(settings, name, &node)
  1050.       && (node->type == FLUID_INT_TYPE)) {
  1051.     fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
  1052.     *val = setting->value;
  1053.     retval = 1;
  1054.   }
  1055.   fluid_rec_mutex_unlock (settings->mutex);
  1056.   return retval;
  1057. }
  1058. /**
  1059.  * Get the range of values of an integer setting
  1060.  * @param settings a settings object
  1061.  * @param name a setting's name
  1062.  * @param min setting's range lower limit
  1063.  * @param max setting's range upper limit
  1064.  */
  1065. void
  1066. fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
  1067.                             int* min, int* max)
  1068. {
  1069.   fluid_setting_node_t *node;
  1070.   fluid_return_if_fail (settings != NULL);
  1071.   fluid_return_if_fail (name != NULL);
  1072.   fluid_return_if_fail (min != NULL);
  1073.   fluid_return_if_fail (max != NULL);
  1074.   fluid_rec_mutex_lock (settings->mutex);
  1075.   if (fluid_settings_get(settings, name, &node)
  1076.       && (node->type == FLUID_INT_TYPE)) {
  1077.     fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
  1078.     *min = setting->min;
  1079.     *max = setting->max;
  1080.   }
  1081.   fluid_rec_mutex_unlock (settings->mutex);
  1082. }
  1083. /**
  1084.  * Get the default value of an integer setting.
  1085.  *
  1086.  * @param settings a settings object
  1087.  * @param name a setting's name
  1088.  * @return the setting's default integer value it it exists, zero otherwise
  1089.  */
  1090. int
  1091. fluid_settings_getint_default(fluid_settings_t* settings, const char *name)
  1092. {
  1093.   fluid_setting_node_t *node;
  1094.   int retval = 0;
  1095.   fluid_return_val_if_fail (settings != NULL, 0);
  1096.   fluid_return_val_if_fail (name != NULL, 0);
  1097.   fluid_rec_mutex_lock (settings->mutex);
  1098.   if (fluid_settings_get(settings, name, &node)
  1099.       && (node->type == FLUID_INT_TYPE)) {
  1100.     fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
  1101.     retval = setting->def;
  1102.   }
  1103.   fluid_rec_mutex_unlock (settings->mutex);
  1104.   return retval;
  1105. }
  1106. /**
  1107.  * Iterate the available options for a named string setting, calling the provided
  1108.  * callback function for each existing option.
  1109.  *
  1110.  * @param settings a settings object
  1111.  * @param name a setting's name
  1112.  * @param data any user provided pointer
  1113.  * @param func callback function to be called on each iteration
  1114.  *
  1115.  * NOTE: Starting with FluidSynth 1.1.0 the a func callback is called for each
  1116.  * option in alphabetical order.  Sort order was undefined in previous versions.
  1117.  */
  1118. void
  1119. fluid_settings_foreach_option (fluid_settings_t* settings, const char *name,
  1120.                                void* data, fluid_settings_foreach_option_t func)
  1121. {
  1122.   fluid_setting_node_t *node;
  1123.   fluid_str_setting_t *setting;
  1124.   fluid_list_t *p, *newlist = NULL;
  1125.   fluid_return_if_fail (settings != NULL);
  1126.   fluid_return_if_fail (name != NULL);
  1127.   fluid_return_if_fail (func != NULL);
  1128.   fluid_rec_mutex_lock (settings->mutex);       /* ++ lock */
  1129.   if (!fluid_settings_get (settings, name, &node) || node->type != FLUID_STR_TYPE)
  1130.   {
  1131.     fluid_rec_mutex_unlock (settings->mutex);   /* -- unlock */
  1132.     return;
  1133.   }
  1134.   setting = (fluid_str_setting_t*)node;
  1135.   /* Duplicate option list */
  1136.   for (p = setting->options; p; p = p->next)
  1137.     newlist = fluid_list_append (newlist, fluid_list_get (p));
  1138.   /* Sort by name */
  1139.   newlist = fluid_list_sort (newlist, fluid_list_str_compare_func);
  1140.   for (p = newlist; p; p = p->next)
  1141.     (*func)(data, (char *)name, (char *)fluid_list_get (p));
  1142.   fluid_rec_mutex_unlock (settings->mutex);   /* -- unlock */
  1143.   delete_fluid_list (newlist);
  1144. }
  1145. /**
  1146.  * Count option string values for a string setting.
  1147.  * @param settings a settings object
  1148.  * @param name Name of setting
  1149.  * @return Count of options for this string setting (0 if none, -1 if not found
  1150.  *   or not a string setting)
  1151.  * @since 1.1.0
  1152.  */
  1153. int
  1154. fluid_settings_option_count (fluid_settings_t *settings, const char *name)
  1155. {
  1156.   fluid_setting_node_t *node;
  1157.   int count = -1;
  1158.   fluid_return_val_if_fail (settings != NULL, -1);
  1159.   fluid_return_val_if_fail (name != NULL, -1);
  1160.   fluid_rec_mutex_lock (settings->mutex);
  1161.   if (fluid_settings_get(settings, name, &node) && node->type == FLUID_STR_TYPE)
  1162.     count = fluid_list_size (((fluid_str_setting_t *)node)->options);
  1163.   fluid_rec_mutex_unlock (settings->mutex);
  1164.   return (count);
  1165. }
  1166. /**
  1167.  * Concatenate options for a string setting together with a separator between.
  1168.  * @param settings Settings object
  1169.  * @param name Settings name
  1170.  * @param separator String to use between options (NULL to use ", ")
  1171.  * @return Newly allocated string or NULL on error (out of memory, not a valid
  1172.  *   setting a name or not a string setting).  Free the string when finished with it.
  1173.  * @since 1.1.0
  1174.  */
  1175. char *
  1176. fluid_settings_option_concat (fluid_settings_t *settings, const char *name,
  1177.                               const char *separator)
  1178. {
  1179.   fluid_setting_node_t *node;
  1180.   fluid_str_setting_t *setting;
  1181.   fluid_list_t *p, *newlist = NULL;
  1182.   int count, len;
  1183.   char *str, *option;
  1184.   fluid_return_val_if_fail (settings != NULL, NULL);
  1185.   fluid_return_val_if_fail (name != NULL, NULL);
  1186.   if (!separator) separator = ", ";
  1187.   fluid_rec_mutex_lock (settings->mutex);       /* ++ lock */
  1188.   if (!fluid_settings_get (settings, name, &node) || node->type != FLUID_STR_TYPE)
  1189.   {
  1190.     fluid_rec_mutex_unlock (settings->mutex);   /* -- unlock */
  1191.     return (NULL);
  1192.   }
  1193.   setting = (fluid_str_setting_t*)node;
  1194.   /* Duplicate option list, count options and get total string length */
  1195.   for (p = setting->options, count = 0, len = 0; p; p = p->next, count++)
  1196.   {
  1197.     option = fluid_list_get (p);
  1198.     if (option)
  1199.     {
  1200.       newlist = fluid_list_append (newlist, option);
  1201.       len += strlen (option);
  1202.     }
  1203.   }
  1204.   if (count > 1) len += (count - 1) * strlen (separator);
  1205.   len++;        /* For terminator */
  1206.   /* Sort by name */
  1207.   newlist = fluid_list_sort (newlist, fluid_list_str_compare_func);
  1208.   str = FLUID_MALLOC (len);
  1209.   str[0] = 0;
  1210.   if (str)
  1211.   {
  1212.     for (p = newlist; p; p = p->next)
  1213.     {
  1214.       option = fluid_list_get (p);
  1215.       strcat (str, option);
  1216.       if (p->next) strcat (str, separator);
  1217.     }
  1218.   }
  1219.   fluid_rec_mutex_unlock (settings->mutex);   /* -- unlock */
  1220.   delete_fluid_list (newlist);
  1221.   if (!str) FLUID_LOG (FLUID_ERR, "Out of memory");
  1222.   return (str);
  1223. }
  1224. /* Structure passed to fluid_settings_foreach_iter recursive function */
  1225. typedef struct
  1226. {
  1227.   char path[MAX_SETTINGS_LABEL+1];      /* Maximum settings label length */
  1228.   fluid_list_t *names;                  /* For fluid_settings_foreach() */
  1229. } fluid_settings_foreach_bag_t;
  1230. static int
  1231. fluid_settings_foreach_iter (void* key, void* value, void* data)
  1232. {
  1233.   fluid_settings_foreach_bag_t *bag = data;
  1234.   char *keystr = key;
  1235.   fluid_setting_node_t *node = value;
  1236.   int pathlen;
  1237.   char *s;
  1238.   pathlen = strlen (bag->path);
  1239.   if (pathlen > 0)
  1240.   {
  1241.     bag->path[pathlen] = '.';
  1242.     bag->path[pathlen + 1] = 0;
  1243.   }
  1244.   strcat (bag->path, keystr);
  1245.   switch (node->type) {
  1246.   case FLUID_NUM_TYPE:
  1247.   case FLUID_INT_TYPE:
  1248.   case FLUID_STR_TYPE:
  1249.     s = FLUID_STRDUP (bag->path);
  1250.     if (s) bag->names = fluid_list_append (bag->names, s);
  1251.     break;
  1252.   case FLUID_SET_TYPE:
  1253.     fluid_hashtable_foreach(((fluid_set_setting_t *)value)->hashtable,
  1254.                             fluid_settings_foreach_iter, bag);
  1255.     break;
  1256.   }
  1257.   bag->path[pathlen] = 0;
  1258.   return 0;
  1259. }
  1260. /**
  1261.  * Iterate the existing settings defined in a settings object, calling the
  1262.  * provided callback function for each setting.
  1263.  *
  1264.  * @param settings a settings object
  1265.  * @param data any user provided pointer
  1266.  * @param func callback function to be called on each iteration
  1267.  *
  1268.  * NOTE: Starting with FluidSynth 1.1.0 the a func callback is called for each
  1269.  * setting in alphabetical order.  Sort order was undefined in previous versions.
  1270.  */
  1271. void
  1272. fluid_settings_foreach (fluid_settings_t* settings, void* data,
  1273.                         fluid_settings_foreach_t func)
  1274. {
  1275.   fluid_settings_foreach_bag_t bag;
  1276.   fluid_setting_node_t *node;
  1277.   fluid_list_t *p;
  1278.   int r;
  1279.   fluid_return_if_fail (settings != NULL);
  1280.   fluid_return_if_fail (func != NULL);
  1281.   bag.path[0] = 0;
  1282.   bag.names = NULL;
  1283.   fluid_rec_mutex_lock (settings->mutex);
  1284.   /* Add all node names to the bag.names list */
  1285.   fluid_hashtable_foreach (settings, fluid_settings_foreach_iter, &bag);
  1286.   /* Sort names */
  1287.   bag.names = fluid_list_sort (bag.names, fluid_list_str_compare_func);
  1288.   /* Loop over names and call the callback */
  1289.   for (p = bag.names; p; p = p->next)
  1290.   {
  1291.     r = fluid_settings_get (settings, (char *)(p->data), &node);
  1292.     if (r && node) (*func) (data, (char *)(p->data), node->type);
  1293.     FLUID_FREE (p->data);       /* -- Free name */
  1294.   }
  1295.   fluid_rec_mutex_unlock (settings->mutex);
  1296.   delete_fluid_list (bag.names);        /* -- Free names list */
  1297. }