Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/fluidsynth/src/utils/fluid_settings.c
4396 views
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 Lesser General Public License
7
* as published by the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
14
*
15
* You should have received a copy of the GNU Lesser 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 "fluid_sys.h"
22
#include "fluid_hash.h"
23
#include "fluid_synth.h"
24
#if 0 /* unused in Wine */
25
#include "fluid_cmd.h"
26
#include "fluid_adriver.h"
27
#include "fluid_mdriver.h"
28
#endif /* unused in Wine */
29
#include "fluid_settings.h"
30
#include "fluid_midi.h"
31
32
/* maximum allowed components of a settings variable (separated by '.') */
33
#define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */
34
#define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */
35
36
static void fluid_settings_init(fluid_settings_t *settings);
37
static void fluid_settings_key_destroy_func(void *value);
38
static void fluid_settings_value_destroy_func(void *value);
39
static int fluid_settings_tokenize(const char *s, char *buf, char **ptr);
40
41
/* Common structure to all settings nodes */
42
typedef struct
43
{
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
52
typedef struct
53
{
54
double value;
55
double def;
56
double min;
57
double max;
58
int hints;
59
fluid_num_update_t update;
60
void *data;
61
} fluid_num_setting_t;
62
63
typedef struct
64
{
65
int value;
66
int def;
67
int min;
68
int max;
69
int hints;
70
fluid_int_update_t update;
71
void *data;
72
} fluid_int_setting_t;
73
74
typedef struct
75
{
76
fluid_hashtable_t *hashtable;
77
} fluid_set_setting_t;
78
79
typedef struct
80
{
81
int type; /**< fluid_types_enum */
82
83
union
84
{
85
fluid_str_setting_t str;
86
fluid_num_setting_t num;
87
fluid_int_setting_t i;
88
fluid_set_setting_t set;
89
};
90
} fluid_setting_node_t;
91
92
static fluid_setting_node_t *
93
new_fluid_str_setting(const char *value, const char *def, int hints)
94
{
95
fluid_setting_node_t *node;
96
fluid_str_setting_t *str;
97
98
node = FLUID_NEW(fluid_setting_node_t);
99
100
if(!node)
101
{
102
FLUID_LOG(FLUID_ERR, "Out of memory");
103
return NULL;
104
}
105
106
node->type = FLUID_STR_TYPE;
107
108
str = &node->str;
109
str->value = value ? FLUID_STRDUP(value) : NULL;
110
str->def = def ? FLUID_STRDUP(def) : NULL;
111
str->hints = hints;
112
str->options = NULL;
113
str->update = NULL;
114
str->data = NULL;
115
return node;
116
}
117
118
static void
119
delete_fluid_str_setting(fluid_setting_node_t *node)
120
{
121
fluid_return_if_fail(node != NULL);
122
123
FLUID_ASSERT(node->type == FLUID_STR_TYPE);
124
125
FLUID_FREE(node->str.value);
126
FLUID_FREE(node->str.def);
127
128
if(node->str.options)
129
{
130
fluid_list_t *list = node->str.options;
131
132
while(list)
133
{
134
FLUID_FREE(list->data);
135
list = fluid_list_next(list);
136
}
137
138
delete_fluid_list(node->str.options);
139
}
140
141
FLUID_FREE(node);
142
}
143
144
145
static fluid_setting_node_t *
146
new_fluid_num_setting(double min, double max, double def, int hints)
147
{
148
fluid_setting_node_t *node;
149
fluid_num_setting_t *num;
150
151
node = FLUID_NEW(fluid_setting_node_t);
152
153
if(!node)
154
{
155
FLUID_LOG(FLUID_ERR, "Out of memory");
156
return NULL;
157
}
158
159
node->type = FLUID_NUM_TYPE;
160
161
num = &node->num;
162
num->value = def;
163
num->def = def;
164
num->min = min;
165
num->max = max;
166
num->hints = hints;
167
num->update = NULL;
168
num->data = NULL;
169
170
return node;
171
}
172
173
static void
174
delete_fluid_num_setting(fluid_setting_node_t *node)
175
{
176
fluid_return_if_fail(node != NULL);
177
178
FLUID_ASSERT(node->type == FLUID_NUM_TYPE);
179
FLUID_FREE(node);
180
}
181
182
static fluid_setting_node_t *
183
new_fluid_int_setting(int min, int max, int def, int hints)
184
{
185
fluid_setting_node_t *node;
186
fluid_int_setting_t *i;
187
188
node = FLUID_NEW(fluid_setting_node_t);
189
190
if(!node)
191
{
192
FLUID_LOG(FLUID_ERR, "Out of memory");
193
return NULL;
194
}
195
196
node->type = FLUID_INT_TYPE;
197
198
i = &node->i;
199
i->value = def;
200
i->def = def;
201
i->min = min;
202
i->max = max;
203
i->hints = hints;
204
i->update = NULL;
205
i->data = NULL;
206
return node;
207
}
208
209
static void
210
delete_fluid_int_setting(fluid_setting_node_t *node)
211
{
212
fluid_return_if_fail(node != NULL);
213
214
FLUID_ASSERT(node->type == FLUID_INT_TYPE);
215
FLUID_FREE(node);
216
}
217
218
static fluid_setting_node_t *
219
new_fluid_set_setting(void)
220
{
221
fluid_setting_node_t *node;
222
fluid_set_setting_t *set;
223
224
node = FLUID_NEW(fluid_setting_node_t);
225
226
if(!node)
227
{
228
FLUID_LOG(FLUID_ERR, "Out of memory");
229
return NULL;
230
}
231
232
node->type = FLUID_SET_TYPE;
233
set = &node->set;
234
235
set->hashtable = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
236
fluid_settings_key_destroy_func,
237
fluid_settings_value_destroy_func);
238
239
if(!set->hashtable)
240
{
241
FLUID_FREE(node);
242
return NULL;
243
}
244
245
return node;
246
}
247
248
static void
249
delete_fluid_set_setting(fluid_setting_node_t *node)
250
{
251
fluid_return_if_fail(node != NULL);
252
253
FLUID_ASSERT(node->type == FLUID_SET_TYPE);
254
delete_fluid_hashtable(node->set.hashtable);
255
FLUID_FREE(node);
256
}
257
258
/**
259
* Create a new settings object
260
*
261
* @return the pointer to the settings object
262
*/
263
fluid_settings_t *
264
new_fluid_settings(void)
265
{
266
fluid_settings_t *settings;
267
268
settings = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
269
fluid_settings_key_destroy_func,
270
fluid_settings_value_destroy_func);
271
272
if(settings == NULL)
273
{
274
return NULL;
275
}
276
277
fluid_rec_mutex_init(settings->mutex);
278
fluid_settings_init(settings);
279
return settings;
280
}
281
282
/**
283
* Delete the provided settings object
284
*
285
* @param settings a settings object
286
*/
287
void
288
delete_fluid_settings(fluid_settings_t *settings)
289
{
290
fluid_return_if_fail(settings != NULL);
291
292
fluid_rec_mutex_destroy(settings->mutex);
293
delete_fluid_hashtable(settings);
294
}
295
296
/* Settings hash key destroy function */
297
static void
298
fluid_settings_key_destroy_func(void *value)
299
{
300
FLUID_FREE(value); /* Free the string key value */
301
}
302
303
/* Settings hash value destroy function */
304
static void
305
fluid_settings_value_destroy_func(void *value)
306
{
307
fluid_setting_node_t *node = value;
308
309
switch(node->type)
310
{
311
case FLUID_NUM_TYPE:
312
delete_fluid_num_setting(node);
313
break;
314
315
case FLUID_INT_TYPE:
316
delete_fluid_int_setting(node);
317
break;
318
319
case FLUID_STR_TYPE:
320
delete_fluid_str_setting(node);
321
break;
322
323
case FLUID_SET_TYPE:
324
delete_fluid_set_setting(node);
325
break;
326
}
327
}
328
329
void
330
fluid_settings_init(fluid_settings_t *settings)
331
{
332
fluid_return_if_fail(settings != NULL);
333
334
fluid_synth_settings(settings);
335
#if 0 /* unused in Wine */
336
fluid_shell_settings(settings);
337
fluid_player_settings(settings);
338
fluid_file_renderer_settings(settings);
339
fluid_audio_driver_settings(settings);
340
fluid_midi_driver_settings(settings);
341
#endif /* unused in Wine */
342
}
343
344
static int
345
fluid_settings_tokenize(const char *s, char *buf, char **ptr)
346
{
347
char *tokstr, *tok;
348
int n = 0;
349
350
if(FLUID_STRLEN(s) > MAX_SETTINGS_LABEL)
351
{
352
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
353
MAX_SETTINGS_LABEL);
354
return 0;
355
}
356
357
FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
358
tokstr = buf;
359
360
while((tok = fluid_strtok(&tokstr, ".")))
361
{
362
if(n >= MAX_SETTINGS_TOKENS)
363
{
364
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
365
MAX_SETTINGS_TOKENS);
366
return 0;
367
}
368
else
369
{
370
ptr[n++] = tok;
371
}
372
}
373
374
return n;
375
}
376
377
/**
378
* Get a setting name, value and type
379
*
380
* @param settings a settings object
381
* @param name Settings name
382
* @param value Location to store setting node if found
383
* @return #FLUID_OK if the node exists, #FLUID_FAILED otherwise
384
*/
385
static int
386
fluid_settings_get(fluid_settings_t *settings, const char *name,
387
fluid_setting_node_t **value)
388
{
389
fluid_hashtable_t *table = settings;
390
fluid_setting_node_t *node = NULL;
391
char *tokens[MAX_SETTINGS_TOKENS];
392
char buf[MAX_SETTINGS_LABEL + 1];
393
int ntokens;
394
int n;
395
396
ntokens = fluid_settings_tokenize(name, buf, tokens);
397
398
if(table == NULL || ntokens <= 0)
399
{
400
return FLUID_FAILED;
401
}
402
403
for(n = 0; n < ntokens; n++)
404
{
405
406
node = fluid_hashtable_lookup(table, tokens[n]);
407
408
if(!node)
409
{
410
return FLUID_FAILED;
411
}
412
413
table = (node->type == FLUID_SET_TYPE) ? node->set.hashtable : NULL;
414
}
415
416
if(value)
417
{
418
*value = node;
419
}
420
421
return FLUID_OK;
422
}
423
424
/**
425
* Set a setting name, value and type, replacing it if already exists
426
*
427
* @param settings a settings object
428
* @param name Settings name
429
* @param value Node instance to assign (used directly)
430
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
431
*/
432
static int
433
fluid_settings_set(fluid_settings_t *settings, const char *name, fluid_setting_node_t *value)
434
{
435
fluid_hashtable_t *table = settings;
436
fluid_setting_node_t *node;
437
char *tokens[MAX_SETTINGS_TOKENS];
438
char buf[MAX_SETTINGS_LABEL + 1];
439
int n, num;
440
char *dupname;
441
442
num = fluid_settings_tokenize(name, buf, tokens);
443
444
if(num == 0)
445
{
446
return FLUID_FAILED;
447
}
448
449
num--;
450
451
for(n = 0; n < num; n++)
452
{
453
454
node = fluid_hashtable_lookup(table, tokens[n]);
455
456
if(node)
457
{
458
459
if(node->type == FLUID_SET_TYPE)
460
{
461
table = node->set.hashtable;
462
}
463
else
464
{
465
/* path ends prematurely */
466
FLUID_LOG(FLUID_ERR, "'%s' is not a node. Name of the setting was '%s'", tokens[n], name);
467
return FLUID_FAILED;
468
}
469
470
}
471
else
472
{
473
/* create a new node */
474
fluid_setting_node_t *setnode;
475
476
dupname = FLUID_STRDUP(tokens[n]);
477
setnode = new_fluid_set_setting();
478
479
if(!dupname || !setnode)
480
{
481
if(dupname)
482
{
483
FLUID_FREE(dupname);
484
}
485
else
486
{
487
FLUID_LOG(FLUID_ERR, "Out of memory");
488
}
489
490
if(setnode)
491
{
492
delete_fluid_set_setting(setnode);
493
}
494
495
return FLUID_FAILED;
496
}
497
498
fluid_hashtable_insert(table, dupname, setnode);
499
table = setnode->set.hashtable;
500
}
501
}
502
503
dupname = FLUID_STRDUP(tokens[num]);
504
505
if(!dupname)
506
{
507
FLUID_LOG(FLUID_ERR, "Out of memory");
508
return FLUID_FAILED;
509
}
510
511
fluid_hashtable_insert(table, dupname, value);
512
513
return FLUID_OK;
514
}
515
516
/**
517
* Registers a new string value for the specified setting.
518
*
519
* @param settings a settings object
520
* @param name the setting's name
521
* @param def the default value for the setting
522
* @param hints the hints for the setting
523
* @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
524
*/
525
int
526
fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints)
527
{
528
fluid_setting_node_t *node;
529
int retval = FLUID_FAILED;
530
531
fluid_return_val_if_fail(settings != NULL, retval);
532
fluid_return_val_if_fail(name != NULL, retval);
533
fluid_return_val_if_fail(name[0] != '\0', retval);
534
535
fluid_rec_mutex_lock(settings->mutex);
536
537
if(fluid_settings_get(settings, name, &node) != FLUID_OK)
538
{
539
node = new_fluid_str_setting(def, def, hints);
540
retval = fluid_settings_set(settings, name, node);
541
542
if(retval != FLUID_OK)
543
{
544
delete_fluid_str_setting(node);
545
}
546
}
547
else
548
{
549
/* if variable already exists, don't change its value. */
550
if(node->type == FLUID_STR_TYPE)
551
{
552
fluid_str_setting_t *setting = &node->str;
553
FLUID_FREE(setting->def);
554
setting->def = def ? FLUID_STRDUP(def) : NULL;
555
setting->hints = hints;
556
retval = FLUID_OK;
557
}
558
else
559
{
560
FLUID_LOG(FLUID_ERR, "Failed to register string setting '%s' as it already exists with a different type", name);
561
}
562
}
563
564
fluid_rec_mutex_unlock(settings->mutex);
565
566
return retval;
567
}
568
569
/**
570
* Registers a new float value for the specified setting.
571
*
572
* @param settings a settings object
573
* @param name the setting's name
574
* @param def the default value for the setting
575
* @param min the smallest allowed value for the setting
576
* @param max the largest allowed value for the setting
577
* @param hints the hints for the setting
578
* @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
579
*/
580
int
581
fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def,
582
double min, double max, int hints)
583
{
584
fluid_setting_node_t *node;
585
int retval = FLUID_FAILED;
586
587
fluid_return_val_if_fail(settings != NULL, retval);
588
fluid_return_val_if_fail(name != NULL, retval);
589
fluid_return_val_if_fail(name[0] != '\0', retval);
590
591
/* For now, all floating point settings are bounded below and above */
592
hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
593
594
fluid_rec_mutex_lock(settings->mutex);
595
596
if(fluid_settings_get(settings, name, &node) != FLUID_OK)
597
{
598
/* insert a new setting */
599
node = new_fluid_num_setting(min, max, def, hints);
600
retval = fluid_settings_set(settings, name, node);
601
602
if(retval != FLUID_OK)
603
{
604
delete_fluid_num_setting(node);
605
}
606
}
607
else
608
{
609
if(node->type == FLUID_NUM_TYPE)
610
{
611
/* update the existing setting but don't change its value */
612
fluid_num_setting_t *setting = &node->num;
613
setting->min = min;
614
setting->max = max;
615
setting->def = def;
616
setting->hints = hints;
617
retval = FLUID_OK;
618
}
619
else
620
{
621
/* type mismatch */
622
FLUID_LOG(FLUID_ERR, "Failed to register numeric setting '%s' as it already exists with a different type", name);
623
}
624
}
625
626
fluid_rec_mutex_unlock(settings->mutex);
627
628
return retval;
629
}
630
631
/**
632
* Registers a new integer value for the specified setting.
633
*
634
* @param settings a settings object
635
* @param name the setting's name
636
* @param def the default value for the setting
637
* @param min the smallest allowed value for the setting
638
* @param max the largest allowed value for the setting
639
* @param hints the hints for the setting
640
* @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
641
*/
642
int
643
fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def,
644
int min, int max, int hints)
645
{
646
fluid_setting_node_t *node;
647
int retval = FLUID_FAILED;
648
649
fluid_return_val_if_fail(settings != NULL, retval);
650
fluid_return_val_if_fail(name != NULL, retval);
651
fluid_return_val_if_fail(name[0] != '\0', retval);
652
653
/* For now, all integer settings are bounded below and above */
654
hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
655
656
fluid_rec_mutex_lock(settings->mutex);
657
658
if(fluid_settings_get(settings, name, &node) != FLUID_OK)
659
{
660
/* insert a new setting */
661
node = new_fluid_int_setting(min, max, def, hints);
662
retval = fluid_settings_set(settings, name, node);
663
664
if(retval != FLUID_OK)
665
{
666
delete_fluid_int_setting(node);
667
}
668
}
669
else
670
{
671
if(node->type == FLUID_INT_TYPE)
672
{
673
/* update the existing setting but don't change its value */
674
fluid_int_setting_t *setting = &node->i;
675
setting->min = min;
676
setting->max = max;
677
setting->def = def;
678
setting->hints = hints;
679
retval = FLUID_OK;
680
}
681
else
682
{
683
/* type mismatch */
684
FLUID_LOG(FLUID_ERR, "Failed to register int setting '%s' as it already exists with a different type", name);
685
}
686
}
687
688
fluid_rec_mutex_unlock(settings->mutex);
689
690
return retval;
691
}
692
693
/**
694
* Registers a callback for the specified string setting.
695
*
696
* @param settings a settings object
697
* @param name the setting's name
698
* @param callback an update function for the setting
699
* @param data user supplied data passed to the update function
700
* @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
701
*/
702
int fluid_settings_callback_str(fluid_settings_t *settings, const char *name,
703
fluid_str_update_t callback, void *data)
704
{
705
fluid_setting_node_t *node;
706
fluid_str_setting_t *setting;
707
708
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
709
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
710
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
711
712
fluid_rec_mutex_lock(settings->mutex);
713
714
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
715
|| node->type != FLUID_STR_TYPE)
716
{
717
fluid_rec_mutex_unlock(settings->mutex);
718
return FLUID_FAILED;
719
}
720
721
setting = &node->str;
722
setting->update = callback;
723
setting->data = data;
724
725
fluid_rec_mutex_unlock(settings->mutex);
726
return FLUID_OK;
727
}
728
729
/**
730
* Registers a callback for the specified numeric setting.
731
*
732
* @param settings a settings object
733
* @param name the setting's name
734
* @param callback an update function for the setting
735
* @param data user supplied data passed to the update function
736
* @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
737
*/
738
int fluid_settings_callback_num(fluid_settings_t *settings, const char *name,
739
fluid_num_update_t callback, void *data)
740
{
741
fluid_setting_node_t *node;
742
fluid_num_setting_t *setting;
743
744
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
745
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
746
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
747
748
fluid_rec_mutex_lock(settings->mutex);
749
750
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
751
|| node->type != FLUID_NUM_TYPE)
752
{
753
fluid_rec_mutex_unlock(settings->mutex);
754
return FLUID_FAILED;
755
}
756
757
setting = &node->num;
758
setting->update = callback;
759
setting->data = data;
760
761
fluid_rec_mutex_unlock(settings->mutex);
762
return FLUID_OK;
763
}
764
765
/**
766
* Registers a callback for the specified int setting.
767
*
768
* @param settings a settings object
769
* @param name the setting's name
770
* @param callback an update function for the setting
771
* @param data user supplied data passed to the update function
772
* @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
773
*/
774
int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
775
fluid_int_update_t callback, void *data)
776
{
777
fluid_setting_node_t *node;
778
fluid_int_setting_t *setting;
779
780
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
781
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
782
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
783
784
fluid_rec_mutex_lock(settings->mutex);
785
786
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
787
|| node->type != FLUID_INT_TYPE)
788
{
789
fluid_rec_mutex_unlock(settings->mutex);
790
return FLUID_FAILED;
791
}
792
793
setting = &node->i;
794
setting->update = callback;
795
setting->data = data;
796
797
fluid_rec_mutex_unlock(settings->mutex);
798
return FLUID_OK;
799
}
800
801
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name)
802
{
803
fluid_setting_node_t *node;
804
void* retval = NULL;
805
806
fluid_return_val_if_fail(settings != NULL, NULL);
807
fluid_return_val_if_fail(name != NULL, NULL);
808
fluid_return_val_if_fail(name[0] != '\0', NULL);
809
810
fluid_rec_mutex_lock(settings->mutex);
811
812
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
813
{
814
if(node->type == FLUID_NUM_TYPE)
815
{
816
fluid_num_setting_t *setting = &node->num;
817
retval = setting->data;
818
}
819
else if(node->type == FLUID_STR_TYPE)
820
{
821
fluid_str_setting_t *setting = &node->str;
822
retval = setting->data;
823
}
824
else if(node->type == FLUID_INT_TYPE)
825
{
826
fluid_int_setting_t *setting = &node->i;
827
retval = setting->data;
828
}
829
}
830
831
fluid_rec_mutex_unlock(settings->mutex);
832
return retval;
833
}
834
835
/**
836
* Get the type of the setting with the given name
837
*
838
* @param settings a settings object
839
* @param name a setting's name
840
* @return the type for the named setting (see #fluid_types_enum), or #FLUID_NO_TYPE when it does not exist
841
*/
842
int
843
fluid_settings_get_type(fluid_settings_t *settings, const char *name)
844
{
845
fluid_setting_node_t *node;
846
int type = FLUID_NO_TYPE;
847
848
fluid_return_val_if_fail(settings != NULL, type);
849
fluid_return_val_if_fail(name != NULL, type);
850
fluid_return_val_if_fail(name[0] != '\0', type);
851
852
fluid_rec_mutex_lock(settings->mutex);
853
854
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
855
{
856
type = node->type;
857
}
858
859
fluid_rec_mutex_unlock(settings->mutex);
860
861
return type;
862
}
863
864
/**
865
* Get the hints for the named setting as an integer bitmap
866
*
867
* @param settings a settings object
868
* @param name a setting's name
869
* @param hints set to the hints associated to the setting if it exists
870
* @return #FLUID_OK if hints associated to the named setting exist, #FLUID_FAILED otherwise
871
*/
872
int
873
fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *hints)
874
{
875
fluid_setting_node_t *node;
876
int retval = FLUID_FAILED;
877
878
fluid_return_val_if_fail(settings != NULL, retval);
879
fluid_return_val_if_fail(name != NULL, retval);
880
fluid_return_val_if_fail(name[0] != '\0', retval);
881
882
fluid_rec_mutex_lock(settings->mutex);
883
884
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
885
{
886
if(node->type == FLUID_NUM_TYPE)
887
{
888
fluid_num_setting_t *setting = &node->num;
889
*hints = setting->hints;
890
retval = FLUID_OK;
891
}
892
else if(node->type == FLUID_STR_TYPE)
893
{
894
fluid_str_setting_t *setting = &node->str;
895
*hints = setting->hints;
896
retval = FLUID_OK;
897
}
898
else if(node->type == FLUID_INT_TYPE)
899
{
900
fluid_int_setting_t *setting = &node->i;
901
*hints = setting->hints;
902
retval = FLUID_OK;
903
}
904
}
905
906
fluid_rec_mutex_unlock(settings->mutex);
907
908
return retval;
909
}
910
911
/**
912
* Ask whether the setting is changeable in real-time.
913
*
914
* @param settings a settings object
915
* @param name a setting's name
916
* @return TRUE if the setting is changeable in real-time, FALSE otherwise
917
*
918
* @note Before using this function, make sure the @p settings object has already been used to create
919
* a synthesizer, a MIDI driver, an audio driver, a MIDI player, or a command handler (depending on
920
* which settings you want to query).
921
*/
922
int
923
fluid_settings_is_realtime(fluid_settings_t *settings, const char *name)
924
{
925
fluid_setting_node_t *node;
926
int isrealtime = FALSE;
927
928
fluid_return_val_if_fail(settings != NULL, 0);
929
fluid_return_val_if_fail(name != NULL, 0);
930
fluid_return_val_if_fail(name[0] != '\0', 0);
931
932
fluid_rec_mutex_lock(settings->mutex);
933
934
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
935
{
936
if(node->type == FLUID_NUM_TYPE)
937
{
938
fluid_num_setting_t *setting = &node->num;
939
isrealtime = setting->update != NULL;
940
}
941
else if(node->type == FLUID_STR_TYPE)
942
{
943
fluid_str_setting_t *setting = &node->str;
944
isrealtime = setting->update != NULL;
945
}
946
else if(node->type == FLUID_INT_TYPE)
947
{
948
fluid_int_setting_t *setting = &node->i;
949
isrealtime = setting->update != NULL;
950
}
951
}
952
953
fluid_rec_mutex_unlock(settings->mutex);
954
955
return isrealtime;
956
}
957
958
/**
959
* Set a string value for a named setting
960
*
961
* @param settings a settings object
962
* @param name a setting's name
963
* @param str new string value
964
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
965
*/
966
int
967
fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str)
968
{
969
fluid_setting_node_t *node;
970
fluid_str_setting_t *setting;
971
char *new_value = NULL;
972
fluid_str_update_t callback = NULL;
973
void *data = NULL;
974
975
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
976
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
977
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
978
979
fluid_rec_mutex_lock(settings->mutex);
980
981
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
982
|| (node->type != FLUID_STR_TYPE))
983
{
984
FLUID_LOG(FLUID_ERR, "Unknown string setting '%s'", name);
985
goto error_recovery;
986
}
987
988
setting = &node->str;
989
990
if(setting->value)
991
{
992
FLUID_FREE(setting->value);
993
}
994
995
if(str)
996
{
997
new_value = FLUID_STRDUP(str);
998
999
if(new_value == NULL)
1000
{
1001
FLUID_LOG(FLUID_ERR, "Out of memory");
1002
goto error_recovery;
1003
}
1004
}
1005
1006
setting->value = new_value;
1007
1008
callback = setting->update;
1009
data = setting->data;
1010
1011
/* Release the mutex before calling the update callback, to avoid
1012
* possible deadlocks with FluidSynths API lock */
1013
fluid_rec_mutex_unlock(settings->mutex);
1014
1015
if(callback)
1016
{
1017
(*callback)(data, name, new_value);
1018
}
1019
1020
return FLUID_OK;
1021
1022
error_recovery:
1023
fluid_rec_mutex_unlock(settings->mutex);
1024
return FLUID_FAILED;
1025
}
1026
1027
/**
1028
* Copy the value of a string setting into the provided buffer (thread safe)
1029
*
1030
* @param settings a settings object
1031
* @param name a setting's name
1032
* @param str Caller supplied buffer to copy string value to
1033
* @param len Size of 'str' buffer (no more than len bytes will be written, which
1034
* will always include a zero terminator)
1035
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
1036
*
1037
* @note A size of 256 should be more than sufficient for the string buffer.
1038
*
1039
* @since 1.1.0
1040
*/
1041
int
1042
fluid_settings_copystr(fluid_settings_t *settings, const char *name,
1043
char *str, int len)
1044
{
1045
fluid_setting_node_t *node;
1046
int retval = FLUID_FAILED;
1047
1048
fluid_return_val_if_fail(settings != NULL, retval);
1049
fluid_return_val_if_fail(name != NULL, retval);
1050
fluid_return_val_if_fail(name[0] != '\0', retval);
1051
fluid_return_val_if_fail(str != NULL, retval);
1052
fluid_return_val_if_fail(len > 0, retval);
1053
1054
str[0] = 0;
1055
1056
fluid_rec_mutex_lock(settings->mutex);
1057
1058
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
1059
{
1060
if(node->type == FLUID_STR_TYPE)
1061
{
1062
fluid_str_setting_t *setting = &node->str;
1063
1064
if(setting->value)
1065
{
1066
FLUID_STRNCPY(str, setting->value, len);
1067
}
1068
1069
retval = FLUID_OK;
1070
}
1071
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
1072
{
1073
fluid_int_setting_t *setting = &node->i;
1074
1075
if(setting->hints & FLUID_HINT_TOGGLED)
1076
{
1077
FLUID_STRNCPY(str, setting->value ? "yes" : "no", len);
1078
1079
retval = FLUID_OK;
1080
}
1081
}
1082
}
1083
1084
fluid_rec_mutex_unlock(settings->mutex);
1085
1086
return retval;
1087
}
1088
1089
/**
1090
* Duplicate the value of a string setting
1091
*
1092
* @param settings a settings object
1093
* @param name a setting's name
1094
* @param str Location to store pointer to allocated duplicate string
1095
* @return #FLUID_OK if the value exists and was successfully duplicated, #FLUID_FAILED otherwise
1096
*
1097
* Like fluid_settings_copystr() but allocates a new copy of the string. Caller
1098
* owns the string and should free it with fluid_free() when done using it.
1099
*
1100
* @since 1.1.0
1101
*/
1102
int
1103
fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str)
1104
{
1105
fluid_setting_node_t *node;
1106
int retval = FLUID_FAILED;
1107
1108
fluid_return_val_if_fail(settings != NULL, retval);
1109
fluid_return_val_if_fail(name != NULL, retval);
1110
fluid_return_val_if_fail(name[0] != '\0', retval);
1111
fluid_return_val_if_fail(str != NULL, retval);
1112
1113
fluid_rec_mutex_lock(settings->mutex);
1114
1115
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
1116
{
1117
if(node->type == FLUID_STR_TYPE)
1118
{
1119
fluid_str_setting_t *setting = &node->str;
1120
1121
if(setting->value)
1122
{
1123
*str = FLUID_STRDUP(setting->value);
1124
1125
if(!*str)
1126
{
1127
FLUID_LOG(FLUID_ERR, "Out of memory");
1128
}
1129
}
1130
1131
if(!setting->value || *str)
1132
{
1133
retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */
1134
}
1135
}
1136
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
1137
{
1138
fluid_int_setting_t *setting = &node->i;
1139
1140
if(setting->hints & FLUID_HINT_TOGGLED)
1141
{
1142
*str = FLUID_STRDUP(setting->value ? "yes" : "no");
1143
1144
if(!*str)
1145
{
1146
FLUID_LOG(FLUID_ERR, "Out of memory");
1147
}
1148
1149
if(!setting->value || *str)
1150
{
1151
retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */
1152
}
1153
}
1154
}
1155
}
1156
1157
fluid_rec_mutex_unlock(settings->mutex);
1158
1159
return retval;
1160
}
1161
1162
1163
/**
1164
* Test a string setting for some value.
1165
*
1166
* @param settings a settings object
1167
* @param name a setting's name
1168
* @param s a string to be tested
1169
* @return TRUE if the value exists and is equal to \c s, FALSE otherwise
1170
*/
1171
int
1172
fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *s)
1173
{
1174
fluid_setting_node_t *node;
1175
int retval = FALSE;
1176
1177
fluid_return_val_if_fail(settings != NULL, retval);
1178
fluid_return_val_if_fail(name != NULL, retval);
1179
fluid_return_val_if_fail(name[0] != '\0', retval);
1180
fluid_return_val_if_fail(s != NULL, retval);
1181
1182
fluid_rec_mutex_lock(settings->mutex);
1183
1184
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
1185
{
1186
if(node->type == FLUID_STR_TYPE)
1187
{
1188
fluid_str_setting_t *setting = &node->str;
1189
1190
if(setting->value)
1191
{
1192
retval = FLUID_STRCMP(setting->value, s) == 0;
1193
}
1194
}
1195
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
1196
{
1197
fluid_int_setting_t *setting = &node->i;
1198
1199
if(setting->hints & FLUID_HINT_TOGGLED)
1200
{
1201
retval = FLUID_STRCMP(setting->value ? "yes" : "no", s) == 0;
1202
}
1203
}
1204
}
1205
1206
fluid_rec_mutex_unlock(settings->mutex);
1207
1208
return retval;
1209
}
1210
1211
/**
1212
* Get the default value of a string setting.
1213
*
1214
* @param settings a settings object
1215
* @param name a setting's name
1216
* @param def the default string value of the setting if it exists
1217
* @return FLUID_OK if a default value exists, FLUID_FAILED otherwise
1218
*
1219
* @note The returned string is not owned by the caller and should not be modified or freed.
1220
*/
1221
int
1222
fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def)
1223
{
1224
fluid_setting_node_t *node;
1225
char *retval = NULL;
1226
1227
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
1228
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
1229
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
1230
1231
fluid_rec_mutex_lock(settings->mutex);
1232
1233
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
1234
{
1235
if(node->type == FLUID_STR_TYPE)
1236
{
1237
fluid_str_setting_t *setting = &node->str;
1238
retval = setting->def;
1239
}
1240
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
1241
{
1242
fluid_int_setting_t *setting = &node->i;
1243
1244
if(setting->hints & FLUID_HINT_TOGGLED)
1245
{
1246
retval = setting->def ? "yes" : "no";
1247
}
1248
}
1249
}
1250
1251
*def = retval;
1252
fluid_rec_mutex_unlock(settings->mutex);
1253
1254
return retval != NULL ? FLUID_OK : FLUID_FAILED;
1255
}
1256
1257
/**
1258
* Add an option to a string setting (like an enumeration value).
1259
*
1260
* @param settings a settings object
1261
* @param name a setting's name
1262
* @param s option string to add
1263
* @return #FLUID_OK if the setting exists and option was added, #FLUID_FAILED otherwise
1264
*
1265
* Causes the setting's #FLUID_HINT_OPTIONLIST hint to be set.
1266
*/
1267
int
1268
fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s)
1269
{
1270
fluid_setting_node_t *node;
1271
int retval = FLUID_FAILED;
1272
1273
fluid_return_val_if_fail(settings != NULL, retval);
1274
fluid_return_val_if_fail(name != NULL, retval);
1275
fluid_return_val_if_fail(name[0] != '\0', retval);
1276
fluid_return_val_if_fail(s != NULL, retval);
1277
1278
fluid_rec_mutex_lock(settings->mutex);
1279
1280
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1281
&& (node->type == FLUID_STR_TYPE))
1282
{
1283
fluid_str_setting_t *setting = &node->str;
1284
char *copy = FLUID_STRDUP(s);
1285
setting->options = fluid_list_append(setting->options, copy);
1286
setting->hints |= FLUID_HINT_OPTIONLIST;
1287
retval = FLUID_OK;
1288
}
1289
1290
fluid_rec_mutex_unlock(settings->mutex);
1291
1292
return retval;
1293
}
1294
1295
/**
1296
* Remove an option previously assigned by fluid_settings_add_option().
1297
*
1298
* @param settings a settings object
1299
* @param name a setting's name
1300
* @param s option string to remove
1301
* @return #FLUID_OK if the setting exists and option was removed, #FLUID_FAILED otherwise
1302
*/
1303
int
1304
fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s)
1305
{
1306
fluid_setting_node_t *node;
1307
int retval = FLUID_FAILED;
1308
1309
fluid_return_val_if_fail(settings != NULL, retval);
1310
fluid_return_val_if_fail(name != NULL, retval);
1311
fluid_return_val_if_fail(name[0] != '\0', retval);
1312
fluid_return_val_if_fail(s != NULL, retval);
1313
1314
fluid_rec_mutex_lock(settings->mutex);
1315
1316
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1317
&& (node->type == FLUID_STR_TYPE))
1318
{
1319
1320
fluid_str_setting_t *setting = &node->str;
1321
fluid_list_t *list = setting->options;
1322
1323
while(list)
1324
{
1325
char *option = (char *) fluid_list_get(list);
1326
1327
if(FLUID_STRCMP(s, option) == 0)
1328
{
1329
FLUID_FREE(option);
1330
setting->options = fluid_list_remove_link(setting->options, list);
1331
retval = FLUID_OK;
1332
break;
1333
}
1334
1335
list = fluid_list_next(list);
1336
}
1337
}
1338
1339
fluid_rec_mutex_unlock(settings->mutex);
1340
1341
return retval;
1342
}
1343
1344
/**
1345
* Set a numeric value for a named setting.
1346
*
1347
* @param settings a settings object
1348
* @param name a setting's name
1349
* @param val new setting's value
1350
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
1351
*/
1352
int
1353
fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val)
1354
{
1355
fluid_setting_node_t *node;
1356
fluid_num_setting_t *setting;
1357
fluid_num_update_t callback = NULL;
1358
void *data = NULL;
1359
1360
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
1361
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
1362
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
1363
1364
fluid_rec_mutex_lock(settings->mutex);
1365
1366
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
1367
|| (node->type != FLUID_NUM_TYPE))
1368
{
1369
FLUID_LOG(FLUID_ERR, "Unknown numeric setting '%s'", name);
1370
goto error_recovery;
1371
}
1372
1373
setting = &node->num;
1374
1375
if(val < setting->min || val > setting->max)
1376
{
1377
FLUID_LOG(FLUID_ERR, "requested set value for '%s' out of range", name);
1378
goto error_recovery;
1379
}
1380
1381
setting->value = val;
1382
1383
callback = setting->update;
1384
data = setting->data;
1385
1386
/* Release the mutex before calling the update callback, to avoid
1387
* possible deadlocks with FluidSynths API lock */
1388
fluid_rec_mutex_unlock(settings->mutex);
1389
1390
if(callback)
1391
{
1392
(*callback)(data, name, val);
1393
}
1394
1395
return FLUID_OK;
1396
1397
error_recovery:
1398
fluid_rec_mutex_unlock(settings->mutex);
1399
return FLUID_FAILED;
1400
}
1401
1402
/**
1403
* Get the numeric value of a named setting
1404
*
1405
* @param settings a settings object
1406
* @param name a setting's name
1407
* @param val variable pointer to receive the setting's numeric value
1408
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
1409
*/
1410
int
1411
fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val)
1412
{
1413
fluid_setting_node_t *node;
1414
int retval = FLUID_FAILED;
1415
1416
fluid_return_val_if_fail(settings != NULL, retval);
1417
fluid_return_val_if_fail(name != NULL, retval);
1418
fluid_return_val_if_fail(name[0] != '\0', retval);
1419
fluid_return_val_if_fail(val != NULL, retval);
1420
1421
fluid_rec_mutex_lock(settings->mutex);
1422
1423
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1424
&& (node->type == FLUID_NUM_TYPE))
1425
{
1426
fluid_num_setting_t *setting = &node->num;
1427
*val = setting->value;
1428
retval = FLUID_OK;
1429
}
1430
1431
fluid_rec_mutex_unlock(settings->mutex);
1432
1433
return retval;
1434
}
1435
1436
/**
1437
* float-typed wrapper for fluid_settings_getnum
1438
*
1439
* @param settings a settings object
1440
* @param name a setting's name
1441
* @param val variable pointer to receive the setting's float value
1442
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
1443
*/
1444
int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val)
1445
{
1446
double tmp;
1447
1448
if(fluid_settings_getnum(settings, name, &tmp) == FLUID_OK)
1449
{
1450
*val = tmp;
1451
return FLUID_OK;
1452
}
1453
1454
return FLUID_FAILED;
1455
}
1456
1457
/**
1458
* Get the range of values of a numeric setting
1459
*
1460
* @param settings a settings object
1461
* @param name a setting's name
1462
* @param min setting's range lower limit
1463
* @param max setting's range upper limit
1464
* @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise
1465
*/
1466
int
1467
fluid_settings_getnum_range(fluid_settings_t *settings, const char *name,
1468
double *min, double *max)
1469
{
1470
fluid_setting_node_t *node;
1471
int retval = FLUID_FAILED;
1472
1473
fluid_return_val_if_fail(settings != NULL, retval);
1474
fluid_return_val_if_fail(name != NULL, retval);
1475
fluid_return_val_if_fail(name[0] != '\0', retval);
1476
fluid_return_val_if_fail(min != NULL, retval);
1477
fluid_return_val_if_fail(max != NULL, retval);
1478
1479
fluid_rec_mutex_lock(settings->mutex);
1480
1481
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1482
&& (node->type == FLUID_NUM_TYPE))
1483
{
1484
fluid_num_setting_t *setting = &node->num;
1485
*min = setting->min;
1486
*max = setting->max;
1487
retval = FLUID_OK;
1488
}
1489
1490
fluid_rec_mutex_unlock(settings->mutex);
1491
1492
return retval;
1493
}
1494
1495
/**
1496
* Get the default value of a named numeric (double) setting
1497
*
1498
* @param settings a settings object
1499
* @param name a setting's name
1500
* @param val set to the default value if the named setting exists
1501
* @return #FLUID_OK if the default value of the named setting exists, #FLUID_FAILED otherwise
1502
*/
1503
int
1504
fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val)
1505
{
1506
fluid_setting_node_t *node;
1507
int retval = FLUID_FAILED;
1508
1509
fluid_return_val_if_fail(settings != NULL, retval);
1510
fluid_return_val_if_fail(name != NULL, retval);
1511
fluid_return_val_if_fail(name[0] != '\0', retval);
1512
fluid_return_val_if_fail(val != NULL, retval);
1513
1514
fluid_rec_mutex_lock(settings->mutex);
1515
1516
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1517
&& (node->type == FLUID_NUM_TYPE))
1518
{
1519
fluid_num_setting_t *setting = &node->num;
1520
*val = setting->def;
1521
retval = FLUID_OK;
1522
}
1523
1524
fluid_rec_mutex_unlock(settings->mutex);
1525
1526
return retval;
1527
}
1528
1529
/**
1530
* Set an integer value for a setting
1531
*
1532
* @param settings a settings object
1533
* @param name a setting's name
1534
* @param val new setting's integer value
1535
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
1536
*/
1537
int
1538
fluid_settings_setint(fluid_settings_t *settings, const char *name, int val)
1539
{
1540
fluid_setting_node_t *node;
1541
fluid_int_setting_t *setting;
1542
fluid_int_update_t callback = NULL;
1543
void *data = NULL;
1544
1545
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
1546
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
1547
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
1548
1549
fluid_rec_mutex_lock(settings->mutex);
1550
1551
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
1552
|| (node->type != FLUID_INT_TYPE))
1553
{
1554
FLUID_LOG(FLUID_ERR, "Unknown integer parameter '%s'", name);
1555
goto error_recovery;
1556
}
1557
1558
setting = &node->i;
1559
1560
if(val < setting->min || val > setting->max)
1561
{
1562
FLUID_LOG(FLUID_ERR, "requested set value for setting '%s' out of range", name);
1563
goto error_recovery;
1564
}
1565
1566
setting->value = val;
1567
1568
callback = setting->update;
1569
data = setting->data;
1570
1571
/* Release the mutex before calling the update callback, to avoid
1572
* possible deadlocks with FluidSynths API lock */
1573
fluid_rec_mutex_unlock(settings->mutex);
1574
1575
if(callback)
1576
{
1577
(*callback)(data, name, val);
1578
}
1579
1580
return FLUID_OK;
1581
1582
error_recovery:
1583
fluid_rec_mutex_unlock(settings->mutex);
1584
return FLUID_FAILED;
1585
}
1586
1587
/**
1588
* Get an integer value setting.
1589
*
1590
* @param settings a settings object
1591
* @param name a setting's name
1592
* @param val pointer to a variable to receive the setting's integer value
1593
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
1594
*/
1595
int
1596
fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val)
1597
{
1598
fluid_setting_node_t *node;
1599
int retval = FLUID_FAILED;
1600
1601
fluid_return_val_if_fail(settings != NULL, retval);
1602
fluid_return_val_if_fail(name != NULL, retval);
1603
fluid_return_val_if_fail(name[0] != '\0', retval);
1604
fluid_return_val_if_fail(val != NULL, retval);
1605
1606
fluid_rec_mutex_lock(settings->mutex);
1607
1608
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1609
&& (node->type == FLUID_INT_TYPE))
1610
{
1611
fluid_int_setting_t *setting = &node->i;
1612
*val = setting->value;
1613
retval = FLUID_OK;
1614
}
1615
1616
fluid_rec_mutex_unlock(settings->mutex);
1617
1618
return retval;
1619
}
1620
1621
/**
1622
* Get the range of values of an integer setting
1623
*
1624
* @param settings a settings object
1625
* @param name a setting's name
1626
* @param min setting's range lower limit
1627
* @param max setting's range upper limit
1628
* @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise
1629
*/
1630
int
1631
fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
1632
int *min, int *max)
1633
{
1634
fluid_setting_node_t *node;
1635
int retval = FLUID_FAILED;
1636
1637
fluid_return_val_if_fail(settings != NULL, retval);
1638
fluid_return_val_if_fail(name != NULL, retval);
1639
fluid_return_val_if_fail(name[0] != '\0', retval);
1640
fluid_return_val_if_fail(min != NULL, retval);
1641
fluid_return_val_if_fail(max != NULL, retval);
1642
1643
fluid_rec_mutex_lock(settings->mutex);
1644
1645
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1646
&& (node->type == FLUID_INT_TYPE))
1647
{
1648
fluid_int_setting_t *setting = &node->i;
1649
*min = setting->min;
1650
*max = setting->max;
1651
retval = FLUID_OK;
1652
}
1653
1654
fluid_rec_mutex_unlock(settings->mutex);
1655
1656
return retval;
1657
}
1658
1659
/**
1660
* Get the default value of an integer setting.
1661
*
1662
* @param settings a settings object
1663
* @param name a setting's name
1664
* @param val set to the setting's default integer value if it exists
1665
* @return #FLUID_OK if the setting's default integer value exists, #FLUID_FAILED otherwise
1666
*/
1667
int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val)
1668
{
1669
fluid_setting_node_t *node;
1670
int retval = FLUID_FAILED;
1671
1672
fluid_return_val_if_fail(settings != NULL, retval);
1673
fluid_return_val_if_fail(name != NULL, retval);
1674
fluid_return_val_if_fail(name[0] != '\0', retval);
1675
fluid_return_val_if_fail(val != NULL, retval);
1676
1677
fluid_rec_mutex_lock(settings->mutex);
1678
1679
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1680
&& (node->type == FLUID_INT_TYPE))
1681
{
1682
fluid_int_setting_t *setting = &node->i;
1683
*val = setting->def;
1684
retval = FLUID_OK;
1685
}
1686
1687
fluid_rec_mutex_unlock(settings->mutex);
1688
1689
return retval;
1690
}
1691
1692
/**
1693
* Iterate the available options for a named string setting, calling the provided
1694
* callback function for each existing option.
1695
*
1696
* @param settings a settings object
1697
* @param name a setting's name
1698
* @param data any user provided pointer
1699
* @param func callback function to be called on each iteration
1700
*
1701
* @note Starting with FluidSynth 1.1.0 the \p func callback is called for each
1702
* option in alphabetical order. Sort order was undefined in previous versions.
1703
*/
1704
void
1705
fluid_settings_foreach_option(fluid_settings_t *settings, const char *name,
1706
void *data, fluid_settings_foreach_option_t func)
1707
{
1708
fluid_setting_node_t *node;
1709
fluid_str_setting_t *setting;
1710
fluid_list_t *p, *newlist = NULL;
1711
1712
fluid_return_if_fail(settings != NULL);
1713
fluid_return_if_fail(name != NULL);
1714
fluid_return_if_fail(name[0] != '\0');
1715
fluid_return_if_fail(func != NULL);
1716
1717
fluid_rec_mutex_lock(settings->mutex); /* ++ lock */
1718
1719
if(fluid_settings_get(settings, name, &node) != FLUID_OK
1720
|| node->type != FLUID_STR_TYPE)
1721
{
1722
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
1723
return;
1724
}
1725
1726
setting = &node->str;
1727
1728
/* Duplicate option list */
1729
for(p = setting->options; p; p = p->next)
1730
{
1731
newlist = fluid_list_append(newlist, fluid_list_get(p));
1732
}
1733
1734
/* Sort by name */
1735
newlist = fluid_list_sort(newlist, fluid_list_str_compare_func);
1736
1737
for(p = newlist; p; p = p->next)
1738
{
1739
(*func)(data, name, (const char *)fluid_list_get(p));
1740
}
1741
1742
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
1743
1744
delete_fluid_list(newlist);
1745
}
1746
1747
/**
1748
* Count option string values for a string setting.
1749
*
1750
* @param settings a settings object
1751
* @param name Name of setting
1752
* @return Count of options for this string setting (0 if none, -1 if not found
1753
* or not a string setting)
1754
*
1755
* @since 1.1.0
1756
*/
1757
int
1758
fluid_settings_option_count(fluid_settings_t *settings, const char *name)
1759
{
1760
fluid_setting_node_t *node;
1761
int count = -1;
1762
1763
fluid_return_val_if_fail(settings != NULL, -1);
1764
fluid_return_val_if_fail(name != NULL, -1);
1765
fluid_return_val_if_fail(name[0] != '\0', -1);
1766
1767
fluid_rec_mutex_lock(settings->mutex);
1768
1769
if(fluid_settings_get(settings, name, &node) == FLUID_OK
1770
&& node->type == FLUID_STR_TYPE)
1771
{
1772
count = fluid_list_size(node->str.options);
1773
}
1774
1775
fluid_rec_mutex_unlock(settings->mutex);
1776
1777
return (count);
1778
}
1779
1780
/**
1781
* Concatenate options for a string setting together with a separator between.
1782
*
1783
* @param settings Settings object
1784
* @param name Settings name
1785
* @param separator String to use between options (NULL to use ", ")
1786
* @return Newly allocated string or NULL on error (out of memory, not a valid
1787
* setting \p name or not a string setting). Free the string when finished with it by using fluid_free().
1788
*
1789
* @since 1.1.0
1790
*/
1791
char *
1792
fluid_settings_option_concat(fluid_settings_t *settings, const char *name,
1793
const char *separator)
1794
{
1795
fluid_setting_node_t *node;
1796
fluid_list_t *p, *newlist = NULL;
1797
size_t count, len;
1798
char *str, *option;
1799
1800
fluid_return_val_if_fail(settings != NULL, NULL);
1801
fluid_return_val_if_fail(name != NULL, NULL);
1802
fluid_return_val_if_fail(name[0] != '\0', NULL);
1803
1804
if(!separator)
1805
{
1806
separator = ", ";
1807
}
1808
1809
fluid_rec_mutex_lock(settings->mutex); /* ++ lock */
1810
1811
if(fluid_settings_get(settings, name, &node) != FLUID_OK
1812
|| node->type != FLUID_STR_TYPE)
1813
{
1814
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
1815
return (NULL);
1816
}
1817
1818
/* Duplicate option list, count options and get total string length */
1819
for(p = node->str.options, count = 0, len = 0; p; p = p->next)
1820
{
1821
option = fluid_list_get(p);
1822
1823
if(option)
1824
{
1825
newlist = fluid_list_append(newlist, option);
1826
len += FLUID_STRLEN(option);
1827
count++;
1828
}
1829
}
1830
1831
if(count > 1)
1832
{
1833
len += (count - 1) * FLUID_STRLEN(separator);
1834
}
1835
1836
len++; /* For terminator */
1837
1838
/* Sort by name */
1839
newlist = fluid_list_sort(newlist, fluid_list_str_compare_func);
1840
1841
str = FLUID_MALLOC(len);
1842
1843
if(str)
1844
{
1845
str[0] = 0;
1846
1847
for(p = newlist; p; p = p->next)
1848
{
1849
option = fluid_list_get(p);
1850
strcat(str, option);
1851
1852
if(p->next)
1853
{
1854
strcat(str, separator);
1855
}
1856
}
1857
}
1858
1859
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
1860
1861
delete_fluid_list(newlist);
1862
1863
if(!str)
1864
{
1865
FLUID_LOG(FLUID_ERR, "Out of memory");
1866
}
1867
1868
return (str);
1869
}
1870
1871
/* Structure passed to fluid_settings_foreach_iter recursive function */
1872
typedef struct
1873
{
1874
char path[MAX_SETTINGS_LABEL + 1]; /* Maximum settings label length */
1875
fluid_list_t *names; /* For fluid_settings_foreach() */
1876
} fluid_settings_foreach_bag_t;
1877
1878
static int
1879
fluid_settings_foreach_iter(void *key, void *value, void *data)
1880
{
1881
fluid_settings_foreach_bag_t *bag = data;
1882
char *keystr = key;
1883
fluid_setting_node_t *node = value;
1884
size_t pathlen;
1885
char *s;
1886
1887
pathlen = FLUID_STRLEN(bag->path);
1888
1889
if(pathlen > 0)
1890
{
1891
bag->path[pathlen] = '.';
1892
bag->path[pathlen + 1] = 0;
1893
}
1894
1895
strcat(bag->path, keystr);
1896
1897
switch(node->type)
1898
{
1899
case FLUID_NUM_TYPE:
1900
case FLUID_INT_TYPE:
1901
case FLUID_STR_TYPE:
1902
s = FLUID_STRDUP(bag->path);
1903
1904
if(s)
1905
{
1906
bag->names = fluid_list_append(bag->names, s);
1907
}
1908
1909
break;
1910
1911
case FLUID_SET_TYPE:
1912
fluid_hashtable_foreach(node->set.hashtable,
1913
fluid_settings_foreach_iter, bag);
1914
break;
1915
}
1916
1917
bag->path[pathlen] = 0;
1918
1919
return 0;
1920
}
1921
1922
/**
1923
* Iterate the existing settings defined in a settings object, calling the
1924
* provided callback function for each setting.
1925
*
1926
* @param settings a settings object
1927
* @param data any user provided pointer
1928
* @param func callback function to be called on each iteration
1929
*
1930
* @note Starting with FluidSynth 1.1.0 the \p func callback is called for each
1931
* setting in alphabetical order. Sort order was undefined in previous versions.
1932
*/
1933
void
1934
fluid_settings_foreach(fluid_settings_t *settings, void *data,
1935
fluid_settings_foreach_t func)
1936
{
1937
fluid_settings_foreach_bag_t bag;
1938
fluid_setting_node_t *node;
1939
fluid_list_t *p;
1940
1941
fluid_return_if_fail(settings != NULL);
1942
fluid_return_if_fail(func != NULL);
1943
1944
bag.path[0] = 0;
1945
bag.names = NULL;
1946
1947
fluid_rec_mutex_lock(settings->mutex);
1948
1949
/* Add all node names to the bag.names list */
1950
fluid_hashtable_foreach(settings, fluid_settings_foreach_iter, &bag);
1951
1952
/* Sort names */
1953
bag.names = fluid_list_sort(bag.names, fluid_list_str_compare_func);
1954
1955
/* Loop over names and call the callback */
1956
for(p = bag.names; p; p = p->next)
1957
{
1958
if(fluid_settings_get(settings, (const char *)(p->data), &node) == FLUID_OK
1959
&& node)
1960
{
1961
(*func)(data, (const char *)(p->data), node->type);
1962
}
1963
1964
FLUID_FREE(p->data); /* -- Free name */
1965
}
1966
1967
fluid_rec_mutex_unlock(settings->mutex);
1968
1969
delete_fluid_list(bag.names); /* -- Free names list */
1970
}
1971
1972
/**
1973
* Split a comma-separated list of integers and fill the passed
1974
* in buffer with the parsed values.
1975
*
1976
* @param str the comma-separated string to split
1977
* @param buf user-supplied buffer to hold the parsed numbers
1978
* @param buf_len length of user-supplied buffer
1979
* @return number of parsed values or -1 on failure
1980
*/
1981
int fluid_settings_split_csv(const char *str, int *buf, int buf_len)
1982
{
1983
char *s;
1984
char *tok;
1985
char *tokstr;
1986
int n = 0;
1987
1988
s = tokstr = FLUID_STRDUP(str);
1989
1990
if(s == NULL)
1991
{
1992
FLUID_LOG(FLUID_ERR, "Out of memory");
1993
return -1;
1994
}
1995
1996
while((tok = fluid_strtok(&tokstr, ",")) && n < buf_len)
1997
{
1998
buf[n++] = atoi(tok);
1999
}
2000
2001
FLUID_FREE(s);
2002
2003
return n;
2004
}
2005
2006