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