1 #include "test.h"
2 #include "fluidsynth.h"
3 #include "fluid_sfont.h"
4 #include "fluid_defsfont.h"
5 #include "fluid_sys.h"
6 
7 static void dump_sample(fluid_sample_t *sample);
8 static void dump_gens(const fluid_gen_t gen[]);
9 static void dump_mod(const fluid_mod_t *mod);
10 static void dump_preset_zone(fluid_preset_zone_t *zone);
11 static void dump_preset(fluid_preset_t *preset);
12 static void dump_inst_zone(fluid_inst_zone_t *zone);
13 static void dump_inst(fluid_inst_t *inst);
14 static void dump_defsfont(fluid_defsfont_t *defsfont);
15 static int inst_compare_func(const void *a, const void *b);
16 static fluid_list_t *collect_preset_insts(fluid_preset_t *preset, fluid_list_t *inst_list);
17 
18 #define FMT_BUFSIZE (4096)
19 static int indent_level = 0;
20 static FILE *output = NULL;
21 
22 static void fmt(const char *format, ...);
23 static void indent(void);
24 static void outdent(void);
25 
26 
main(int argc,char ** argv)27 int main(int argc, char **argv)
28 {
29     int ret = FLUID_FAILED;
30     int id;
31     fluid_sfont_t *sfont;
32     fluid_defsfont_t *defsfont;
33     fluid_settings_t *settings;
34     fluid_synth_t *synth;
35     const char *adrivers[1] = { NULL };
36 
37     if (argc < 2)
38     {
39         fprintf(stderr, "Usage:\n");
40         fprintf(stderr, "    dump_sfont <input_soundfont> [output_file]\n");
41         return FLUID_FAILED;
42     }
43 
44     fluid_audio_driver_register(adrivers);
45 
46     settings = new_fluid_settings();
47     if (settings == NULL)
48     {
49         return FLUID_FAILED;
50     }
51 
52     synth = new_fluid_synth(settings);
53     if (synth == NULL)
54     {
55         goto EXIT;
56     }
57 
58     id = fluid_synth_sfload(synth, argv[1], 1);
59     if (id < 0)
60     {
61         goto EXIT;
62     }
63 
64     sfont = fluid_synth_get_sfont_by_id(synth, id);
65     if (sfont == NULL)
66     {
67         goto EXIT;
68     }
69 
70     if (sfont->free != &fluid_defsfont_sfont_delete)
71     {
72         fprintf(stderr, "This tool only supports SoundFonts loaded by the default loader\n");
73         goto EXIT;
74     }
75 
76     defsfont = (fluid_defsfont_t *)fluid_sfont_get_data(sfont);
77     if (defsfont == NULL)
78     {
79         goto EXIT;
80     }
81 
82     if (argc < 3)
83     {
84         output = stdout;
85     }
86     else
87     {
88         output = fopen(argv[2], "w");
89         if (output == NULL)
90         {
91             fprintf(stderr, "Unable to open output file %s", argv[2]);
92             goto EXIT;
93         }
94     }
95 
96     dump_defsfont(defsfont);
97 
98     ret = FLUID_OK;
99 
100 EXIT:
101     if (output && output != stdout)
102     {
103         fclose(output);
104     }
105     delete_fluid_synth(synth);
106     delete_fluid_settings(settings);
107 
108     return ret;
109 }
110 
dump_sample(fluid_sample_t * sample)111 static void dump_sample(fluid_sample_t *sample)
112 {
113     fmt("name: %s", sample->name);
114     fmt("source_start: %u", sample->source_start);
115     fmt("source_end: %u", sample->source_end);
116     fmt("source_loopstart: %u", sample->source_loopstart);
117     fmt("source_loopend: %u", sample->source_loopend);
118 
119     fmt("start: %u", sample->start);
120     fmt("end: %u", sample->end);
121     fmt("loopstart: %u", sample->loopstart);
122     fmt("loopend: %u", sample->loopend);
123 
124     fmt("samplerate: %u", sample->samplerate);
125     fmt("origpitch: %u", sample->origpitch);
126     fmt("pitchadj: %u", sample->pitchadj);
127     fmt("sampletype: %u", sample->sampletype);
128 }
129 
dump_gens(const fluid_gen_t gen[])130 static void dump_gens(const fluid_gen_t gen[])
131 {
132     int i;
133 
134     /* only dump generators if at least one is set */
135     for (i = 0; i < GEN_LAST; i++)
136     {
137         if (gen[i].flags)
138         {
139             break;
140         }
141     }
142 
143     if (i == GEN_LAST)
144     {
145         return;
146     }
147 
148     fmt("generators:");
149     indent();
150     for (i = 0; i < GEN_LAST; i++)
151     {
152         if (gen[i].flags)
153         {
154             fmt("%s: %.2f", fluid_gen_name(i), gen[i].val);
155         }
156     }
157     outdent();
158 }
159 
dump_mod(const fluid_mod_t * mod)160 static void dump_mod(const fluid_mod_t *mod)
161 {
162     fmt("dest: %s", fluid_gen_name(mod->dest));
163     fmt("src1: %u", mod->src1);
164     fmt("flags1: %u", mod->flags1);
165     fmt("src2: %u", mod->src2);
166     fmt("flags2: %u", mod->flags2);
167     fmt("amount: %.2f", mod->amount);
168 }
169 
dump_preset_zone(fluid_preset_zone_t * zone)170 static void dump_preset_zone(fluid_preset_zone_t *zone)
171 {
172     int i;
173     fluid_mod_t *mod;
174 
175     fmt("name: %s", zone->name);
176     if (zone->inst)
177     {
178         fmt("instrument: %s (index %d)", zone->inst->name, zone->inst->source_idx);
179     }
180     fmt("key_range: %d - %d", zone->range.keylo, zone->range.keyhi);
181     fmt("vel_range: %d - %d", zone->range.vello, zone->range.velhi);
182     dump_gens(zone->gen);
183 
184     if (zone->mod)
185     {
186         fmt("modulators:");
187         for (i = 0, mod = zone->mod; mod; mod = mod->next, i++)
188         {
189             fmt("- modulator: %d", i);
190             indent();
191             dump_mod(mod);
192             outdent();
193         }
194     }
195 }
196 
dump_preset(fluid_preset_t * preset)197 static void dump_preset(fluid_preset_t *preset)
198 {
199     int i;
200     fluid_preset_zone_t *zone;
201 
202     fluid_defpreset_t *defpreset = fluid_preset_get_data(preset);
203     if (defpreset == NULL)
204     {
205         return;
206     }
207 
208     fmt("name: %s", defpreset->name);
209     fmt("bank: %u", defpreset->bank);
210     fmt("num: %u", defpreset->num);
211 
212     if (defpreset->global_zone)
213     {
214         fmt("global_zone:");
215         indent();
216         dump_preset_zone(defpreset->global_zone);
217         outdent();
218     }
219 
220     fmt("zones:");
221     for (i = 0, zone = defpreset->zone; zone; zone = fluid_preset_zone_next(zone), i++)
222     {
223         fmt("- zone: %d", i);
224         if (zone == NULL)
225         {
226             continue;
227         }
228 
229         indent();
230         dump_preset_zone(zone);
231         outdent();
232     }
233 }
234 
dump_inst_zone(fluid_inst_zone_t * zone)235 static void dump_inst_zone(fluid_inst_zone_t *zone)
236 {
237     int i;
238     fluid_mod_t *mod;
239 
240     fmt("name: %s", zone->name);
241     if (zone->sample)
242     {
243         fmt("sample: %s", zone->sample->name);
244     }
245     fmt("key_range: %d - %d", zone->range.keylo, zone->range.keyhi);
246     fmt("vel_range: %d - %d", zone->range.vello, zone->range.velhi);
247     dump_gens(zone->gen);
248     if (zone->mod)
249     {
250         fmt("modulators:");
251         for (i = 0, mod = zone->mod; mod; mod = mod->next, i++)
252         {
253             fmt("- modulator: %d", i);
254             indent();
255             dump_mod(mod);
256             outdent();
257         }
258     }
259 }
260 
dump_inst(fluid_inst_t * inst)261 static void dump_inst(fluid_inst_t *inst)
262 {
263     int i;
264     fluid_inst_zone_t *zone;
265 
266     fmt("name: %s", inst->name);
267 
268     if (inst->global_zone)
269     {
270         fmt("global_zone:");
271         indent();
272         dump_inst_zone(inst->global_zone);
273         outdent();
274     }
275 
276     fmt("zones:");
277     for (i = 0, zone = inst->zone; zone; zone = fluid_inst_zone_next(zone), i++)
278     {
279         fmt("- zone: %d", i);
280         if (zone == NULL)
281         {
282             continue;
283         }
284 
285         indent();
286         dump_inst_zone(zone);
287         outdent();
288     }
289 }
290 
inst_compare_func(const void * a,const void * b)291 static int inst_compare_func(const void *a, const void *b)
292 {
293     const fluid_inst_t *inst_a = a;
294     const fluid_inst_t *inst_b = b;
295 
296     return inst_a->source_idx - inst_b->source_idx;
297 }
298 
collect_preset_insts(fluid_preset_t * preset,fluid_list_t * inst_list)299 static fluid_list_t *collect_preset_insts(fluid_preset_t *preset, fluid_list_t *inst_list)
300 {
301     fluid_preset_zone_t *zone;
302     fluid_defpreset_t *defpreset = fluid_preset_get_data(preset);
303     if (defpreset == NULL)
304     {
305         return inst_list;
306     }
307 
308     if (defpreset->global_zone && defpreset->global_zone->inst &&
309         fluid_list_idx(inst_list, defpreset->global_zone->inst) == -1)
310     {
311         inst_list = fluid_list_prepend(inst_list, defpreset->global_zone->inst);
312     }
313 
314     for (zone = defpreset->zone; zone; zone = fluid_preset_zone_next(zone))
315     {
316         if (zone->inst && (fluid_list_idx(inst_list, zone->inst) == -1))
317         {
318             inst_list = fluid_list_prepend(inst_list, zone->inst);
319         }
320     }
321 
322     return inst_list;
323 }
324 
325 
dump_defsfont(fluid_defsfont_t * defsfont)326 static void dump_defsfont(fluid_defsfont_t *defsfont)
327 {
328     int i;
329     fluid_list_t *list;
330     fluid_sample_t *sample;
331     fluid_preset_t *preset;
332     fluid_inst_t *inst;
333     fluid_list_t *inst_list = NULL;
334 
335     fmt("samplepos: %u", defsfont->samplepos);
336     fmt("samplesize: %u", defsfont->samplesize);
337     fmt("sample24pos: %u", defsfont->sample24pos);
338     fmt("sample24size: %u", defsfont->sample24size);
339 
340     fmt("presets:");
341     for (i = 0, list = defsfont->preset; list; list = fluid_list_next(list), i++)
342     {
343         preset = (fluid_preset_t *)fluid_list_get(list);
344         fmt("- preset: %d", i);
345         if (preset == NULL)
346         {
347             continue;
348         }
349 
350         indent();
351         dump_preset(preset);
352         outdent();
353         fmt("");
354 
355         inst_list = collect_preset_insts(preset, inst_list);
356     }
357 
358     inst_list = fluid_list_sort(inst_list, inst_compare_func);
359 
360     fmt("instruments:");
361     for (list = inst_list; list; list = fluid_list_next(list))
362     {
363         inst = (fluid_inst_t *)fluid_list_get(list);
364         fmt("- instrument: %d", inst->source_idx);
365         indent();
366         dump_inst(inst);
367         outdent();
368         fmt("");
369     }
370 
371     delete_fluid_list(inst_list);
372 
373     fmt("samples:");
374     for (i = 0, list = defsfont->sample; list; list = fluid_list_next(list), i++)
375     {
376         sample = (fluid_sample_t *)fluid_list_get(list);
377         fmt("- sample: %d", i);
378         if (sample == NULL)
379         {
380             continue;
381         }
382 
383         indent();
384         dump_sample(sample);
385         outdent();
386         fmt("");
387     }
388 }
389 
390 
fmt(const char * format,...)391 static void fmt(const char *format, ...)
392 {
393     char buf[FMT_BUFSIZE];
394     va_list args;
395     int len;
396     int i;
397 
398     va_start(args, format);
399     len = FLUID_VSNPRINTF(buf, FMT_BUFSIZE, format, args);
400     va_end(args);
401 
402     if (len < 0)
403     {
404         FLUID_LOG(FLUID_ERR, "max buffer size exceeded");
405         return;
406     }
407 
408     buf[FMT_BUFSIZE - 1] = '\0';
409 
410     for (i = 0; i < indent_level; i++)
411     {
412         fprintf(output, "  ");
413     }
414 
415     fwrite(buf, 1, FLUID_STRLEN(buf), output);
416     fprintf(output, "\n");
417 }
418 
indent(void)419 static void indent(void)
420 {
421     indent_level += 1;
422 }
423 
outdent(void)424 static void outdent(void)
425 {
426     if (indent_level > 0)
427     {
428         indent_level -= 1;
429     }
430 }
431