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 <glib.h>
22
23 #include "fluidsynth_priv.h"
24 #include "fluid_cmd.h"
25 #include "fluid_synth.h"
26 #include "fluid_settings.h"
27 #include "fluid_hash.h"
28 #include "fluid_sys.h"
29 #include "fluid_midi_router.h"
30 #include "fluid_sfont.h"
31 #include "fluid_chan.h"
32
33 #if WITH_READLINE
34 #include <readline/readline.h>
35 #include <readline/history.h>
36 #endif
37
38 #define MAX_TOKENS 100 /* LADSPA plugins need lots of parameters */
39 #define MAX_COMMAND_LEN 1024 /* max command length accepted by fluid_command() */
40 #define FLUID_WORKLINELENGTH 1024 /* LADSPA plugins use long command lines */
41
42 struct _fluid_shell_t {
43 fluid_settings_t* settings;
44 fluid_cmd_handler_t* handler;
45 fluid_thread_t* thread;
46 fluid_istream_t in;
47 fluid_ostream_t out;
48 };
49
50 static int fluid_shell_run(fluid_shell_t* shell);
51 static void fluid_shell_init(fluid_shell_t* shell,
52 fluid_settings_t* settings, fluid_cmd_handler_t* handler,
53 fluid_istream_t in, fluid_ostream_t out);
54 static int fluid_handle_voice_count (fluid_synth_t *synth, int ac, char **av,
55 fluid_ostream_t out);
56
fluid_shell_settings(fluid_settings_t * settings)57 void fluid_shell_settings(fluid_settings_t* settings)
58 {
59 fluid_settings_register_str(settings, "shell.prompt", "", 0, NULL, NULL);
60 fluid_settings_register_int(settings, "shell.port", 9800, 1, 65535, 0, NULL, NULL);
61 }
62
63
64 /** the table of all handled commands */
65
66 fluid_cmd_t fluid_commands[] = {
67 { "help", "general", (fluid_cmd_func_t) fluid_handle_help, NULL,
68 "help Show help topics ('help TOPIC' for more info)" },
69 { "quit", "general", (fluid_cmd_func_t) fluid_handle_quit, NULL,
70 "quit Quit the synthesizer" },
71 { "noteon", "event", (fluid_cmd_func_t) fluid_handle_noteon, NULL,
72 "noteon chan key vel Send noteon" },
73 { "noteoff", "event", (fluid_cmd_func_t) fluid_handle_noteoff, NULL,
74 "noteoff chan key Send noteoff" },
75 { "pitch_bend", "event", (fluid_cmd_func_t) fluid_handle_pitch_bend, NULL,
76 "pitch_bend chan offset Bend pitch" },
77 { "pitch_bend_range", "event", (fluid_cmd_func_t) fluid_handle_pitch_bend_range, NULL,
78 "pitch_bend chan range Set bend pitch range" },
79 { "cc", "event", (fluid_cmd_func_t) fluid_handle_cc, NULL,
80 "cc chan ctrl value Send control-change message" },
81 { "prog", "event", (fluid_cmd_func_t) fluid_handle_prog, NULL,
82 "prog chan num Send program-change message" },
83 { "select", "event", (fluid_cmd_func_t) fluid_handle_select, NULL,
84 "select chan sfont bank prog Combination of bank-select and program-change" },
85 { "load", "general", (fluid_cmd_func_t) fluid_handle_load, NULL,
86 "load file [reset] [bankofs] Load SoundFont (reset=0|1, def 1; bankofs=n, def 0)" },
87 { "unload", "general", (fluid_cmd_func_t) fluid_handle_unload, NULL,
88 "unload id [reset] Unload SoundFont by ID (reset=0|1, default 1)"},
89 { "reload", "general", (fluid_cmd_func_t) fluid_handle_reload, NULL,
90 "reload id Reload the SoundFont with the specified ID" },
91 { "fonts", "general", (fluid_cmd_func_t) fluid_handle_fonts, NULL,
92 "fonts Display the list of loaded SoundFonts" },
93 { "inst", "general", (fluid_cmd_func_t) fluid_handle_inst, NULL,
94 "inst font Print out the available instruments for the font" },
95 { "channels", "general", (fluid_cmd_func_t) fluid_handle_channels, NULL,
96 "channels [-verbose] Print out preset of all channels" },
97 { "interp", "general", (fluid_cmd_func_t) fluid_handle_interp, NULL,
98 "interp num Choose interpolation method for all channels" },
99 { "interpc", "general", (fluid_cmd_func_t) fluid_handle_interpc, NULL,
100 "interpc chan num Choose interpolation method for one channel" },
101 { "rev_preset", "reverb", (fluid_cmd_func_t) fluid_handle_reverbpreset, NULL,
102 "rev_preset num Load preset num into the reverb unit" },
103 { "rev_setroomsize", "reverb", (fluid_cmd_func_t) fluid_handle_reverbsetroomsize, NULL,
104 "rev_setroomsize num Change reverb room size" },
105 { "rev_setdamp", "reverb", (fluid_cmd_func_t) fluid_handle_reverbsetdamp, NULL,
106 "rev_setdamp num Change reverb damping" },
107 { "rev_setwidth", "reverb", (fluid_cmd_func_t) fluid_handle_reverbsetwidth, NULL,
108 "rev_setwidth num Change reverb width" },
109 { "rev_setlevel", "reverb", (fluid_cmd_func_t) fluid_handle_reverbsetlevel, NULL,
110 "rev_setlevel num Change reverb level" },
111 { "reverb", "reverb", (fluid_cmd_func_t) fluid_handle_reverb, NULL,
112 "reverb [0|1|on|off] Turn the reverb on or off" },
113 { "cho_set_nr", "chorus", (fluid_cmd_func_t) fluid_handle_chorusnr, NULL,
114 "cho_set_nr n Use n delay lines (default 3)" },
115 { "cho_set_level", "chorus", (fluid_cmd_func_t) fluid_handle_choruslevel, NULL,
116 "cho_set_level num Set output level of each chorus line to num" },
117 { "cho_set_speed", "chorus", (fluid_cmd_func_t) fluid_handle_chorusspeed, NULL,
118 "cho_set_speed num Set mod speed of chorus to num (Hz)" },
119 { "cho_set_depth", "chorus", (fluid_cmd_func_t) fluid_handle_chorusdepth, NULL,
120 "cho_set_depth num Set chorus modulation depth to num (ms)" },
121 { "chorus", "chorus", (fluid_cmd_func_t) fluid_handle_chorus, NULL,
122 "chorus [0|1|on|off] Turn the chorus on or off" },
123 { "gain", "general", (fluid_cmd_func_t) fluid_handle_gain, NULL,
124 "gain value Set the master gain (0 < gain < 5)" },
125 { "voice_count", "general", (fluid_cmd_func_t) fluid_handle_voice_count, NULL,
126 "voice_count Get number of active synthesis voices" },
127 { "tuning", "tuning", (fluid_cmd_func_t) fluid_handle_tuning, NULL,
128 "tuning name bank prog Create a tuning with name, bank number, \n"
129 " and program number (0 <= bank,prog <= 127)" },
130 { "tune", "tuning", (fluid_cmd_func_t) fluid_handle_tune, NULL,
131 "tune bank prog key pitch Tune a key" },
132 { "settuning", "tuning", (fluid_cmd_func_t) fluid_handle_settuning, NULL,
133 "settuning chan bank prog Set the tuning for a MIDI channel" },
134 { "resettuning", "tuning", (fluid_cmd_func_t) fluid_handle_resettuning, NULL,
135 "resettuning chan Restore the default tuning of a MIDI channel" },
136 { "tunings", "tuning", (fluid_cmd_func_t) fluid_handle_tunings, NULL,
137 "tunings Print the list of available tunings" },
138 { "dumptuning", "tuning", (fluid_cmd_func_t) fluid_handle_dumptuning, NULL,
139 "dumptuning bank prog Print the pitch details of the tuning" },
140 { "reset", "general", (fluid_cmd_func_t) fluid_handle_reset, NULL,
141 "reset System reset (all notes off, reset controllers)" },
142 { "set", "settings", (fluid_cmd_func_t) fluid_handle_set, NULL,
143 "set name value Set the value of a controller or settings" },
144 { "get", "settings", (fluid_cmd_func_t) fluid_handle_get, NULL,
145 "get name Get the value of a controller or settings" },
146 { "info", "settings", (fluid_cmd_func_t) fluid_handle_info, NULL,
147 "info name Get information about a controller or settings" },
148 { "settings", "settings", (fluid_cmd_func_t) fluid_handle_settings, NULL,
149 "settings Print out all settings" },
150 { "echo", "general", (fluid_cmd_func_t) fluid_handle_echo, NULL,
151 "echo arg Print arg" },
152 /* LADSPA-related commands */
153 #ifdef LADSPA
154 { "ladspa_clear", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_clear, NULL,
155 "ladspa_clear Resets LADSPA effect unit to bypass state"},
156 { "ladspa_add", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_add, NULL,
157 "ladspa_add lib plugin n1 <- p1 n2 -> p2 ... Loads and connects LADSPA plugin"},
158 { "ladspa_start", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_start, NULL,
159 "ladspa_start Starts LADSPA effect unit"},
160 { "ladspa_declnode", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_declnode, NULL,
161 "ladspa_declnode node value Declares control node `node' with value `value'"},
162 { "ladspa_setnode", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_setnode, NULL,
163 "ladspa_setnode node value Assigns `value' to `node'"},
164 #endif
165 { "router_clear", "router", (fluid_cmd_func_t) fluid_midi_router_handle_clear, NULL,
166 "router_clear Clears all routing rules from the midi router"},
167 { "router_default", "router", (fluid_cmd_func_t) fluid_midi_router_handle_default, NULL,
168 "router_default Resets the midi router to default state"},
169 { "router_begin", "router", (fluid_cmd_func_t) fluid_midi_router_handle_begin, NULL,
170 "router_begin [note|cc|prog|pbend|cpress|kpress]: Starts a new routing rule"},
171 { "router_chan", "router", (fluid_cmd_func_t) fluid_midi_router_handle_chan, NULL,
172 "router_chan min max mul add filters and maps midi channels on current rule"},
173 { "router_par1", "router", (fluid_cmd_func_t) fluid_midi_router_handle_par1, NULL,
174 "router_par1 min max mul add filters and maps parameter 1 (key/ctrl nr)"},
175 { "router_par2", "router", (fluid_cmd_func_t) fluid_midi_router_handle_par2, NULL,
176 "router_par2 min max mul add filters and maps parameter 2 (vel/cc val)"},
177 { "router_end", "router", (fluid_cmd_func_t) fluid_midi_router_handle_end, NULL,
178 "router_end closes and commits the current routing rule"},
179 { NULL, NULL, NULL, NULL, NULL }
180 };
181
182 /**
183 * Process a string command.
184 * NOTE: FluidSynth 1.0.8 and above no longer modifies the 'cmd' string.
185 * @param handler FluidSynth command handler
186 * @param cmd Command string (NOTE: Gets modified by FluidSynth prior to 1.0.8)
187 * @param out Output stream to display command response to
188 * @return Integer value corresponding to: -1 on command error, 0 on success,
189 * 1 if 'cmd' is a comment or is empty and -2 if quit was issued
190 */
191 int
fluid_command(fluid_cmd_handler_t * handler,const char * cmd,fluid_ostream_t out)192 fluid_command(fluid_cmd_handler_t* handler, const char *cmd, fluid_ostream_t out)
193 {
194 int result, num_tokens = 0;
195 char** tokens = NULL;
196
197 if (cmd[0] == '#' || cmd[0] == '\0') {
198 return 1;
199 }
200
201 if (!g_shell_parse_argv(cmd, &num_tokens, &tokens, NULL)) {
202 fluid_ostream_printf(out, "Error parsing command\n");
203 return -1;
204 }
205
206 result = fluid_cmd_handler_handle(handler, num_tokens, &tokens[0], out);
207 g_strfreev(tokens);
208
209 return result;
210 }
211
212 /**
213 * Create a new FluidSynth command shell.
214 * @param settings Setting parameters to use with the shell
215 * @param handler Command handler
216 * @param in Input stream
217 * @param out Output stream
218 * @param thread TRUE if shell should be run in a separate thread, FALSE to run
219 * it in the current thread (function blocks until "quit")
220 * @return New shell instance or NULL on error
221 */
222 fluid_shell_t *
new_fluid_shell(fluid_settings_t * settings,fluid_cmd_handler_t * handler,fluid_istream_t in,fluid_ostream_t out,int thread)223 new_fluid_shell(fluid_settings_t* settings, fluid_cmd_handler_t* handler,
224 fluid_istream_t in, fluid_ostream_t out, int thread)
225 {
226 fluid_shell_t* shell = FLUID_NEW(fluid_shell_t);
227 if (shell == NULL) {
228 FLUID_LOG (FLUID_PANIC, "Out of memory");
229 return NULL;
230 }
231
232
233 fluid_shell_init(shell, settings, handler, in, out);
234
235 if (thread) {
236 shell->thread = new_fluid_thread("shell", (fluid_thread_func_t) fluid_shell_run, shell,
237 0, TRUE);
238 if (shell->thread == NULL) {
239 delete_fluid_shell(shell);
240 return NULL;
241 }
242 } else {
243 shell->thread = NULL;
244 fluid_shell_run(shell);
245 }
246
247 return shell;
248 }
249
250 static void
fluid_shell_init(fluid_shell_t * shell,fluid_settings_t * settings,fluid_cmd_handler_t * handler,fluid_istream_t in,fluid_ostream_t out)251 fluid_shell_init(fluid_shell_t* shell,
252 fluid_settings_t* settings, fluid_cmd_handler_t* handler,
253 fluid_istream_t in, fluid_ostream_t out)
254 {
255 shell->settings = settings;
256 shell->handler = handler;
257 shell->in = in;
258 shell->out = out;
259 }
260
261 /**
262 * Delete a FluidSynth command shell.
263 * @param shell Command shell instance
264 */
265 void
delete_fluid_shell(fluid_shell_t * shell)266 delete_fluid_shell(fluid_shell_t* shell)
267 {
268 if (shell->thread != NULL) {
269 delete_fluid_thread(shell->thread);
270 }
271
272 FLUID_FREE(shell);
273 }
274
275 static int
fluid_shell_run(fluid_shell_t * shell)276 fluid_shell_run(fluid_shell_t* shell)
277 {
278 char workline[FLUID_WORKLINELENGTH];
279 char* prompt = NULL;
280 int cont = 1;
281 int errors = 0;
282 int n;
283
284 if (shell->settings)
285 fluid_settings_dupstr(shell->settings, "shell.prompt", &prompt); /* ++ alloc prompt */
286
287 /* handle user input */
288 while (cont) {
289
290 n = fluid_istream_readline(shell->in, shell->out, prompt ? prompt : "", workline, FLUID_WORKLINELENGTH);
291
292 if (n < 0) {
293 break;
294 }
295
296 #if WITH_READLINE
297 if (shell->in == fluid_get_stdin()) {
298 add_history(workline);
299 }
300 #endif
301
302 /* handle the command */
303 switch (fluid_command(shell->handler, workline, shell->out)) {
304
305 case 1: /* empty line or comment */
306 break;
307
308 case -1: /* erronous command */
309 errors++;
310 case 0: /* valid command */
311 break;
312
313 case -2: /* quit */
314 cont = 0;
315 break;
316 }
317
318 if (n == 0) {
319 break;
320 }
321 }
322
323 if (prompt) FLUID_FREE (prompt); /* -- free prompt */
324
325 return errors;
326 }
327
328 /**
329 * A convenience function to create a shell interfacing to standard input/output
330 * console streams.
331 * @param settings Settings instance for the shell
332 * @param handler Command handler callback
333 */
334 void
fluid_usershell(fluid_settings_t * settings,fluid_cmd_handler_t * handler)335 fluid_usershell(fluid_settings_t* settings, fluid_cmd_handler_t* handler)
336 {
337 fluid_shell_t shell;
338 fluid_shell_init(&shell, settings, handler, fluid_get_stdin(), fluid_get_stdout());
339 fluid_shell_run(&shell);
340 }
341
342 /**
343 * Execute shell commands in a file.
344 * @param handler Command handler callback
345 * @param filename File name
346 * @return 0 on success, a value >1 on error
347 */
348 int
fluid_source(fluid_cmd_handler_t * handler,const char * filename)349 fluid_source(fluid_cmd_handler_t* handler, const char *filename)
350 {
351 int file;
352 fluid_shell_t shell;
353
354 #ifdef WIN32
355 file = _open(filename, _O_RDONLY);
356 #else
357 file = open(filename, O_RDONLY);
358 #endif
359 if (file < 0) {
360 return file;
361 }
362 fluid_shell_init(&shell, NULL, handler, file, fluid_get_stdout());
363 return fluid_shell_run(&shell);
364 }
365
366 /**
367 * Get the user specific FluidSynth command file name.
368 * @param buf Caller supplied string buffer to store file name to.
369 * @param len Length of \a buf
370 * @return Returns \a buf pointer or NULL if no user command file for this system type.
371 */
372 char*
fluid_get_userconf(char * buf,int len)373 fluid_get_userconf(char* buf, int len)
374 {
375 #if defined(WIN32) || defined(MACOS9)
376 return NULL;
377 #else
378 char* home = getenv("HOME");
379 if (home == NULL) {
380 return NULL;
381 } else {
382 snprintf(buf, len, "%s/.fluidsynth", home);
383 return buf;
384 }
385 #endif
386 }
387
388 /**
389 * Get the system FluidSynth command file name.
390 * @param buf Caller supplied string buffer to store file name to.
391 * @param len Length of \a buf
392 * @return Returns \a buf pointer or NULL if no system command file for this system type.
393 */
394 char*
fluid_get_sysconf(char * buf,int len)395 fluid_get_sysconf(char* buf, int len)
396 {
397 #if defined(WIN32) || defined(MACOS9)
398 return NULL;
399 #else
400 snprintf(buf, len, "/etc/fluidsynth.conf");
401 return buf;
402 #endif
403 }
404
405
406 /*
407 * handlers
408 */
409 int
fluid_handle_noteon(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)410 fluid_handle_noteon(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
411 {
412 if (ac < 3) {
413 fluid_ostream_printf(out, "noteon: too few arguments\n");
414 return -1;
415 }
416 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1]) || !fluid_is_number(av[2])) {
417 fluid_ostream_printf(out, "noteon: invalid argument\n");
418 return -1;
419 }
420 return fluid_synth_noteon(synth, atoi(av[0]), atoi(av[1]), atoi(av[2]));
421 }
422
423 int
fluid_handle_noteoff(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)424 fluid_handle_noteoff(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
425 {
426 if (ac < 2) {
427 fluid_ostream_printf(out, "noteoff: too few arguments\n");
428 return -1;
429 }
430 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1])) {
431 fluid_ostream_printf(out, "noteon: invalid argument\n");
432 return -1;
433 }
434 return fluid_synth_noteoff(synth, atoi(av[0]), atoi(av[1]));
435 }
436
437 int
fluid_handle_pitch_bend(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)438 fluid_handle_pitch_bend(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
439 {
440 if (ac < 2) {
441 fluid_ostream_printf(out, "pitch_bend: too few arguments\n");
442 return -1;
443 }
444 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1])) {
445 fluid_ostream_printf(out, "pitch_bend: invalid argument\n");
446 return -1;
447 }
448 return fluid_synth_pitch_bend(synth, atoi(av[0]), atoi(av[1]));
449 }
450
451 int
fluid_handle_pitch_bend_range(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)452 fluid_handle_pitch_bend_range(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
453 {
454 int channum;
455 int value;
456 if (ac < 2) {
457 fluid_ostream_printf(out, "pitch_bend_range: too few arguments\n");
458 return -1;
459 }
460 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1])) {
461 fluid_ostream_printf(out, "pitch_bend_range: invalid argument\n");
462 return -1;
463 }
464 channum = atoi(av[0]);
465 value = atoi(av[1]);
466 fluid_channel_set_pitch_wheel_sensitivity(synth->channel[channum], value);
467 return 0;
468 }
469
470 int
fluid_handle_cc(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)471 fluid_handle_cc(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
472 {
473 if (ac < 3) {
474 fluid_ostream_printf(out, "cc: too few arguments\n");
475 return -1;
476 }
477 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1]) || !fluid_is_number(av[2])) {
478 fluid_ostream_printf(out, "cc: invalid argument\n");
479 return -1;
480 }
481 return fluid_synth_cc(synth, atoi(av[0]), atoi(av[1]), atoi(av[2]));
482 }
483
484 int
fluid_handle_prog(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)485 fluid_handle_prog(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
486 {
487 if (ac < 2) {
488 fluid_ostream_printf(out, "prog: too few arguments\n");
489 return -1;
490 }
491 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1])) {
492 fluid_ostream_printf(out, "prog: invalid argument\n");
493 return -1;
494 }
495 return fluid_synth_program_change(synth, atoi(av[0]), atoi(av[1]));
496 }
497
498 int
fluid_handle_select(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)499 fluid_handle_select(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
500 {
501 int sfont_id;
502 int chan;
503 int bank;
504 int prog;
505
506 if (ac < 4) {
507 fluid_ostream_printf(out, "preset: too few arguments\n");
508 return -1;
509 }
510 if (!fluid_is_number(av[0]) || !fluid_is_number(av[1])
511 || !fluid_is_number(av[2]) || !fluid_is_number(av[3])) {
512 fluid_ostream_printf(out, "preset: invalid argument\n");
513 return -1;
514 }
515
516 chan = atoi(av[0]);
517 sfont_id = atoi(av[1]);
518 bank = atoi(av[2]);
519 prog = atoi(av[3]);
520
521 if (sfont_id != 0) {
522 return fluid_synth_program_select(synth, chan, sfont_id, bank, prog);
523 } else {
524 if (fluid_synth_bank_select(synth, chan, bank) == FLUID_OK) {
525 return fluid_synth_program_change(synth, chan, prog);
526 }
527 return FLUID_FAILED;
528 }
529 }
530
531 int
fluid_handle_inst(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)532 fluid_handle_inst(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
533 {
534 int font;
535 fluid_sfont_t* sfont;
536 fluid_preset_t preset;
537 int offset;
538
539 if (ac < 1) {
540 fluid_ostream_printf(out, "inst: too few arguments\n");
541 return -1;
542 }
543
544 if (!fluid_is_number(av[0])) {
545 fluid_ostream_printf(out, "inst: invalid argument\n");
546 return -1;
547 }
548
549 font = atoi(av[0]);
550
551 sfont = fluid_synth_get_sfont_by_id(synth, font);
552 offset = fluid_synth_get_bank_offset(synth, font);
553
554 if (sfont == NULL) {
555 fluid_ostream_printf(out, "inst: invalid font number\n");
556 return -1;
557 }
558
559 fluid_sfont_iteration_start(sfont);
560
561 while (fluid_sfont_iteration_next(sfont, &preset)) {
562 fluid_ostream_printf(out, "%03d-%03d %s\n",
563 fluid_preset_get_banknum(&preset) + offset,
564 fluid_preset_get_num(&preset),
565 fluid_preset_get_name(&preset));
566 }
567
568 return 0;
569 }
570
571
572 int
fluid_handle_channels(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)573 fluid_handle_channels(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
574 {
575 fluid_synth_channel_info_t info;
576 int verbose = 0;
577 int i;
578
579 if (ac > 0 && strcmp( av[0], "-verbose") == 0) verbose = 1;
580
581 for (i = 0; i < fluid_synth_count_midi_channels (synth); i++)
582 {
583 fluid_synth_get_channel_info (synth, i, &info);
584
585 if (!verbose)
586 fluid_ostream_printf (out, "chan %d, %s\n", i,
587 info.assigned ? info.name : "no preset");
588 else
589 fluid_ostream_printf (out, "chan %d, sfont %d, bank %d, preset %d, %s\n", i,
590 info.sfont_id, info.bank, info.program,
591 info.assigned ? info.name : "no preset");
592 }
593
594 return 0;
595 }
596
597 int
fluid_handle_load(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)598 fluid_handle_load(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
599 {
600 char buf[1024];
601 int id;
602 int reset = 1;
603 int offset = 0;
604
605 if (ac < 1) {
606 fluid_ostream_printf(out, "load: too few arguments\n");
607 return -1;
608 }
609 if (ac == 2) {
610 reset = atoi(av[1]);
611 }
612 if (ac == 3) {
613 offset = atoi(av[2]);
614 }
615
616 /* Load the SoundFont without resetting the programs. The reset will
617 * be done later (if requested). */
618 id = fluid_synth_sfload(synth, fluid_expand_path(av[0], buf, 1024), 0);
619
620 if (id == -1) {
621 fluid_ostream_printf(out, "failed to load the SoundFont\n");
622 return -1;
623 } else {
624 fluid_ostream_printf(out, "loaded SoundFont has ID %d\n", id);
625 }
626
627 if (offset) {
628 fluid_synth_set_bank_offset(synth, id, offset);
629 }
630
631 /* The reset should be done after the offset is set. */
632 if (reset) {
633 fluid_synth_program_reset(synth);
634 }
635
636 return 0;
637 }
638
639 int
fluid_handle_unload(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)640 fluid_handle_unload(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
641 {
642 int reset = 1;
643 if (ac < 1) {
644 fluid_ostream_printf(out, "unload: too few arguments\n");
645 return -1;
646 }
647 if (!fluid_is_number(av[0])) {
648 fluid_ostream_printf(out, "unload: expected a number as argument\n");
649 return -1;
650 }
651 if (ac == 2) {
652 reset = atoi(av[1]);
653 }
654 if (fluid_synth_sfunload(synth, atoi(av[0]), reset) != 0) {
655 fluid_ostream_printf(out, "failed to unload the SoundFont\n");
656 return -1;
657 }
658 return 0;
659 }
660
661 int
fluid_handle_reload(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)662 fluid_handle_reload(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
663 {
664 if (ac < 1) {
665 fluid_ostream_printf(out, "reload: too few arguments\n");
666 return -1;
667 }
668 if (!fluid_is_number(av[0])) {
669 fluid_ostream_printf(out, "reload: expected a number as argument\n");
670 return -1;
671 }
672 if (fluid_synth_sfreload(synth, atoi(av[0])) == -1) {
673 fluid_ostream_printf(out, "failed to reload the SoundFont\n");
674 return -1;
675 }
676 return 0;
677 }
678
679
680 int
fluid_handle_fonts(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)681 fluid_handle_fonts(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
682 {
683 int i;
684 fluid_sfont_t* sfont;
685 int num;
686
687 num = fluid_synth_sfcount(synth);
688
689 if (num == 0) {
690 fluid_ostream_printf(out, "no SoundFont loaded (try load)\n");
691 return 0;
692 }
693
694 fluid_ostream_printf(out, "ID Name\n");
695
696 for (i = 0; i < num; i++) {
697 sfont = fluid_synth_get_sfont(synth, i);
698 if (sfont) {
699 fluid_ostream_printf(out, "%2d %s\n",
700 fluid_sfont_get_id(sfont),
701 fluid_sfont_get_name(sfont));
702 }
703 else {
704 fluid_ostream_printf(out, "sfont is \"NULL\" for index %d\n", i);
705 }
706 }
707
708 return 0;
709 }
710
711 int
fluid_handle_mstat(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)712 fluid_handle_mstat(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
713 {
714 /* fluid_ostream_printf(out, "Dvr=%s, Dev=%s\n", */
715 /* fluid_midi_handler_get_driver_name(midi), */
716 /* fluid_midi_handler_get_device_name(midi)); */
717 /* fluid_ostream_printf(out, "Stat=%s, On=%d, Off=%d, Prog=%d, Pbend=%d, Err=%d\n", */
718 /* fluid_midi_handler_get_status(midi), */
719 /* fluid_midi_handler_get_event_count(midi, 0x90), */
720 /* fluid_midi_handler_get_event_count(midi, 0x80), */
721 /* fluid_midi_handler_get_event_count(midi, 0xc0), */
722 /* fluid_midi_handler_get_event_count(midi, 0xe0), */
723 /* fluid_midi_handler_get_event_count(midi, 0)); */
724 fluid_ostream_printf(out, "not yet implemented\n");
725 return -1;
726 }
727
728 /* Purpose:
729 * Response to 'rev_preset' command.
730 * Load the values from a reverb preset into the reverb unit. */
731 int
fluid_handle_reverbpreset(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)732 fluid_handle_reverbpreset(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
733 {
734 int reverb_preset_number;
735 if (ac < 1) {
736 fluid_ostream_printf(out, "rev_preset: too few arguments\n");
737 return -1;
738 }
739 reverb_preset_number = atoi(av[0]);
740 if (fluid_synth_set_reverb_preset(synth, reverb_preset_number)!=FLUID_OK){
741 fluid_ostream_printf(out, "rev_preset: Failed. Parameter out of range?\n");
742 return -1;
743 };
744 return 0;
745 }
746
747 /* Purpose:
748 * Response to 'rev_setroomsize' command.
749 * Load the new room size into the reverb unit. */
750 int
fluid_handle_reverbsetroomsize(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)751 fluid_handle_reverbsetroomsize(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
752 {
753 fluid_real_t room_size;
754 if (ac < 1) {
755 fluid_ostream_printf(out, "rev_setroomsize: too few arguments.\n");
756 return -1;
757 }
758 room_size = atof(av[0]);
759 if (room_size < 0){
760 fluid_ostream_printf(out, "rev_setroomsize: Room size must be positive!\n");
761 return -1;
762 }
763 if (room_size > 1.2){
764 fluid_ostream_printf(out, "rev_setroomsize: Room size too big!\n");
765 return -1;
766 }
767 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_ROOMSIZE,
768 room_size, 0.0, 0.0, 0.0);
769 return 0;
770 }
771
772 /* Purpose:
773 * Response to 'rev_setdamp' command.
774 * Load the new damp factor into the reverb unit. */
775 int
fluid_handle_reverbsetdamp(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)776 fluid_handle_reverbsetdamp(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
777 {
778 fluid_real_t damp;
779 if (ac < 1) {
780 fluid_ostream_printf(out, "rev_setdamp: too few arguments.\n");
781 return -1;
782 }
783 damp = atof(av[0]);
784 if ((damp < 0.0f) || (damp > 1)){
785 fluid_ostream_printf(out, "rev_setdamp: damp must be between 0 and 1!\n");
786 return -1;
787 }
788 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_DAMPING,
789 0.0, damp, 0.0, 0.0);
790 return 0;
791 }
792
793 /* Purpose:
794 * Response to 'rev_setwidth' command.
795 * Load the new width into the reverb unit. */
796 int
fluid_handle_reverbsetwidth(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)797 fluid_handle_reverbsetwidth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
798 {
799 fluid_real_t width;
800 if (ac < 1) {
801 fluid_ostream_printf(out, "rev_setwidth: too few arguments.\n");
802 return -1;
803 }
804 width = atof(av[0]);
805 if ((width < 0) || (width > 100)){
806 fluid_ostream_printf(out, "rev_setroomsize: Too wide! (0..100)\n");
807 return 0;
808 }
809 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_WIDTH,
810 0.0, 0.0, width, 0.0);
811 return 0;
812 }
813
814 /* Purpose:
815 * Response to 'rev_setlevel' command.
816 * Load the new level into the reverb unit. */
817 int
fluid_handle_reverbsetlevel(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)818 fluid_handle_reverbsetlevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
819 {
820 fluid_real_t level;
821 if (ac < 1) {
822 fluid_ostream_printf(out, "rev_setlevel: too few arguments.\n");
823 return -1;
824 }
825 level = atof(av[0]);
826 if (abs(level) > 30){
827 fluid_ostream_printf(out, "rev_setlevel: Value too high! (Value of 10 =+20 dB)\n");
828 return 0;
829 }
830 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_LEVEL,
831 0.0, 0.0, 0.0, level);
832 return 0;
833 }
834
835 /* Purpose:
836 * Response to 'reverb' command.
837 * Change the FLUID_REVERB flag in the synth */
838 int
fluid_handle_reverb(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)839 fluid_handle_reverb(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
840 {
841 if (ac < 1) {
842 fluid_ostream_printf(out, "reverb: too few arguments.\n");
843 return -1;
844 }
845
846 if ((strcmp(av[0], "0") == 0) || (strcmp(av[0], "off") == 0)) {
847 fluid_synth_set_reverb_on(synth,0);
848 } else if ((strcmp(av[0], "1") == 0) || (strcmp(av[0], "on") == 0)) {
849 fluid_synth_set_reverb_on(synth,1);
850 } else {
851 fluid_ostream_printf(out, "reverb: invalid arguments %s [0|1|on|off]", av[0]);
852 return -1;
853 }
854
855 return 0;
856 }
857
858
859 /* Purpose:
860 * Response to 'chorus_setnr' command */
861 int
fluid_handle_chorusnr(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)862 fluid_handle_chorusnr(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
863 {
864 int nr;
865 if (ac < 1) {
866 fluid_ostream_printf(out, "cho_set_nr: too few arguments.\n");
867 return -1;
868 }
869 nr = atoi(av[0]);
870 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_NR, nr, 0.0, 0.0, 0.0, 0);
871 }
872
873 /* Purpose:
874 * Response to 'chorus_setlevel' command */
875 int
fluid_handle_choruslevel(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)876 fluid_handle_choruslevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
877 {
878 fluid_real_t level;
879 if (ac < 1) {
880 fluid_ostream_printf(out, "cho_set_level: too few arguments.\n");
881 return -1;
882 }
883 level = atof(av[0]);
884 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_LEVEL, 0, level, 0.0, 0.0, 0);
885 }
886
887 /* Purpose:
888 * Response to 'chorus_setspeed' command */
889 int
fluid_handle_chorusspeed(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)890 fluid_handle_chorusspeed(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
891 {
892 fluid_real_t speed;
893 if (ac < 1) {
894 fluid_ostream_printf(out, "cho_set_speed: too few arguments.\n");
895 return -1;
896 }
897 speed = atof(av[0]);
898 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_SPEED, 0, 0.0, speed, 0.0, 0);
899 }
900
901 /* Purpose:
902 * Response to 'chorus_setdepth' command */
903 int
fluid_handle_chorusdepth(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)904 fluid_handle_chorusdepth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
905 {
906 fluid_real_t depth;
907 if (ac < 1) {
908 fluid_ostream_printf(out, "cho_set_depth: too few arguments.\n");
909 return -1;
910 }
911 depth = atof(av[0]);
912 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_DEPTH, 0, 0.0, 0.0, depth, 0);
913 }
914
915 int
fluid_handle_chorus(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)916 fluid_handle_chorus(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
917 {
918 if (ac < 1) {
919 fluid_ostream_printf(out, "chorus: too few arguments\n");
920 return -1;
921 }
922
923 if ((strcmp(av[0], "0") == 0) || (strcmp(av[0], "off") == 0)) {
924 fluid_synth_set_chorus_on(synth,0);
925 } else if ((strcmp(av[0], "1") == 0) || (strcmp(av[0], "on") == 0)) {
926 fluid_synth_set_chorus_on(synth,1);
927 } else {
928 fluid_ostream_printf(out, "chorus: invalid arguments %s [0|1|on|off]", av[0]);
929 return -1;
930 }
931
932 return 0;
933 }
934
935 /* Purpose:
936 * Response to the 'echo' command.
937 * The command itself is useful, when the synth is used via TCP/IP.
938 * It can signal for example, that a list of commands has been processed.
939 */
940 int
fluid_handle_echo(fluid_cmd_handler_t * handler,int ac,char ** av,fluid_ostream_t out)941 fluid_handle_echo(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
942 {
943 if (ac < 1) {
944 fluid_ostream_printf(out, "echo: too few arguments.\n");
945 return -1;
946 }
947
948 fluid_ostream_printf(out, "%s\n",av[0]);
949
950 return 0;
951 }
952
953 int
fluid_handle_source(fluid_cmd_handler_t * handler,int ac,char ** av,fluid_ostream_t out)954 fluid_handle_source(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
955 {
956 if (ac < 1) {
957 fluid_ostream_printf(out, "source: too few arguments.\n");
958 return -1;
959 }
960
961 fluid_source(handler, av[0]);
962
963 return 0;
964 }
965
966 /* Purpose:
967 * Response to 'gain' command. */
968 int
fluid_handle_gain(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)969 fluid_handle_gain(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
970 {
971 float gain;
972
973 if (ac < 1) {
974 fluid_ostream_printf(out, "gain: too few arguments.\n");
975 return -1;
976 }
977
978 gain = atof(av[0]);
979
980 if ((gain < 0.0f) || (gain > 5.0f)) {
981 fluid_ostream_printf(out, "gain: value should be between '0' and '5'.\n");
982 return -1;
983 };
984
985 fluid_synth_set_gain(synth, gain);
986
987 return 0;
988 }
989
990 /* Response to voice_count command */
991 static int
fluid_handle_voice_count(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)992 fluid_handle_voice_count (fluid_synth_t *synth, int ac, char **av,
993 fluid_ostream_t out)
994 {
995 fluid_ostream_printf (out, "voice_count: %d\n",
996 fluid_synth_get_active_voice_count (synth));
997 return FLUID_OK;
998 }
999
1000 /* Purpose:
1001 * Response to 'interp' command. */
1002 int
fluid_handle_interp(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1003 fluid_handle_interp(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1004 {
1005 int interp;
1006 int chan=-1; /* -1: Set all channels */
1007
1008 if (ac < 1) {
1009 fluid_ostream_printf(out, "interp: too few arguments.\n");
1010 return -1;
1011 }
1012
1013 interp = atoi(av[0]);
1014
1015 if ((interp < 0) || (interp > FLUID_INTERP_HIGHEST)) {
1016 fluid_ostream_printf(out, "interp: Bad value\n");
1017 return -1;
1018 };
1019
1020 fluid_synth_set_interp_method(synth, chan, interp);
1021
1022 return 0;
1023 }
1024
1025 /* Purpose:
1026 * Response to 'interp' command. */
1027 int
fluid_handle_interpc(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1028 fluid_handle_interpc(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1029 {
1030 int interp;
1031 int chan;
1032
1033 if (ac < 2) {
1034 fluid_ostream_printf(out, "interpc: too few arguments.\n");
1035 return -1;
1036 }
1037
1038 chan = atoi(av[0]);
1039 interp = atoi(av[1]);
1040
1041 if ((chan < 0) || (chan >= fluid_synth_count_midi_channels(synth))){
1042 fluid_ostream_printf(out, "interp: Bad value for channel number.\n");
1043 return -1;
1044 };
1045 if ((interp < 0) || (interp > FLUID_INTERP_HIGHEST)) {
1046 fluid_ostream_printf(out, "interp: Bad value for interpolation method.\n");
1047 return -1;
1048 };
1049
1050 fluid_synth_set_interp_method(synth, chan, interp);
1051
1052 return 0;
1053 }
1054
1055 int
fluid_handle_tuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1056 fluid_handle_tuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1057 {
1058 char *name;
1059 int bank, prog;
1060
1061 if (ac < 3) {
1062 fluid_ostream_printf(out, "tuning: too few arguments.\n");
1063 return -1;
1064 }
1065
1066 name = av[0];
1067
1068 if (!fluid_is_number(av[1])) {
1069 fluid_ostream_printf(out, "tuning: 2nd argument should be a number.\n");
1070 return -1;
1071 }
1072 bank = atoi(av[1]);
1073 if ((bank < 0) || (bank >= 128)){
1074 fluid_ostream_printf(out, "tuning: invalid bank number.\n");
1075 return -1;
1076 };
1077
1078 if (!fluid_is_number(av[2])) {
1079 fluid_ostream_printf(out, "tuning: 3rd argument should be a number.\n");
1080 return -1;
1081 }
1082 prog = atoi(av[2]);
1083 if ((prog < 0) || (prog >= 128)){
1084 fluid_ostream_printf(out, "tuning: invalid program number.\n");
1085 return -1;
1086 };
1087
1088 fluid_synth_create_key_tuning(synth, bank, prog, name, NULL);
1089
1090 return 0;
1091 }
1092
1093 int
fluid_handle_tune(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1094 fluid_handle_tune(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1095 {
1096 int bank, prog, key;
1097 double pitch;
1098
1099 if (ac < 4) {
1100 fluid_ostream_printf(out, "tune: too few arguments.\n");
1101 return -1;
1102 }
1103
1104 if (!fluid_is_number(av[0])) {
1105 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1106 return -1;
1107 }
1108 bank = atoi(av[0]);
1109 if ((bank < 0) || (bank >= 128)){
1110 fluid_ostream_printf(out, "tune: invalid bank number.\n");
1111 return -1;
1112 };
1113
1114 if (!fluid_is_number(av[1])) {
1115 fluid_ostream_printf(out, "tune: 2nd argument should be a number.\n");
1116 return -1;
1117 }
1118 prog = atoi(av[1]);
1119 if ((prog < 0) || (prog >= 128)){
1120 fluid_ostream_printf(out, "tune: invalid program number.\n");
1121 return -1;
1122 };
1123
1124 if (!fluid_is_number(av[2])) {
1125 fluid_ostream_printf(out, "tune: 3rd argument should be a number.\n");
1126 return -1;
1127 }
1128 key = atoi(av[2]);
1129 if ((key < 0) || (key >= 128)){
1130 fluid_ostream_printf(out, "tune: invalid key number.\n");
1131 return -1;
1132 };
1133
1134 pitch = atof(av[3]);
1135 if (pitch < 0.0f) {
1136 fluid_ostream_printf(out, "tune: invalid pitch.\n");
1137 return -1;
1138 };
1139
1140 fluid_synth_tune_notes(synth, bank, prog, 1, &key, &pitch, 0);
1141
1142 return 0;
1143 }
1144
1145 int
fluid_handle_settuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1146 fluid_handle_settuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1147 {
1148 int chan, bank, prog;
1149
1150 if (ac < 3) {
1151 fluid_ostream_printf(out, "settuning: too few arguments.\n");
1152 return -1;
1153 }
1154
1155 if (!fluid_is_number(av[0])) {
1156 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1157 return -1;
1158 }
1159 chan = atoi(av[0]);
1160 if ((chan < 0) || (chan >= fluid_synth_count_midi_channels(synth))){
1161 fluid_ostream_printf(out, "tune: invalid channel number.\n");
1162 return -1;
1163 };
1164
1165 if (!fluid_is_number(av[1])) {
1166 fluid_ostream_printf(out, "tuning: 2nd argument should be a number.\n");
1167 return -1;
1168 }
1169 bank = atoi(av[1]);
1170 if ((bank < 0) || (bank >= 128)){
1171 fluid_ostream_printf(out, "tuning: invalid bank number.\n");
1172 return -1;
1173 };
1174
1175 if (!fluid_is_number(av[2])) {
1176 fluid_ostream_printf(out, "tuning: 3rd argument should be a number.\n");
1177 return -1;
1178 }
1179 prog = atoi(av[2]);
1180 if ((prog < 0) || (prog >= 128)){
1181 fluid_ostream_printf(out, "tuning: invalid program number.\n");
1182 return -1;
1183 };
1184
1185 fluid_synth_select_tuning(synth, chan, bank, prog);
1186
1187 return 0;
1188 }
1189
1190 int
fluid_handle_resettuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1191 fluid_handle_resettuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1192 {
1193 int chan;
1194
1195 if (ac < 1) {
1196 fluid_ostream_printf(out, "resettuning: too few arguments.\n");
1197 return -1;
1198 }
1199
1200 if (!fluid_is_number(av[0])) {
1201 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1202 return -1;
1203 }
1204 chan = atoi(av[0]);
1205 if ((chan < 0) || (chan >= fluid_synth_count_midi_channels(synth))){
1206 fluid_ostream_printf(out, "tune: invalid channel number.\n");
1207 return -1;
1208 };
1209
1210 fluid_synth_reset_tuning(synth, chan);
1211
1212 return 0;
1213 }
1214
1215 int
fluid_handle_tunings(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1216 fluid_handle_tunings(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1217 {
1218 int bank, prog;
1219 char name[256];
1220 int count = 0;
1221
1222 fluid_synth_tuning_iteration_start(synth);
1223
1224 while (fluid_synth_tuning_iteration_next(synth, &bank, &prog)) {
1225 fluid_synth_tuning_dump(synth, bank, prog, name, 256, NULL);
1226 fluid_ostream_printf(out, "%03d-%03d %s\n", bank, prog, name);
1227 count++;
1228 }
1229
1230 if (count == 0) {
1231 fluid_ostream_printf(out, "No tunings available\n");
1232 }
1233
1234 return 0;
1235 }
1236
1237 int
fluid_handle_dumptuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1238 fluid_handle_dumptuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1239 {
1240 int bank, prog, i;
1241 double pitch[128];
1242 char name[256];
1243
1244 if (ac < 2) {
1245 fluid_ostream_printf(out, "dumptuning: too few arguments.\n");
1246 return -1;
1247 }
1248
1249 if (!fluid_is_number(av[0])) {
1250 fluid_ostream_printf(out, "dumptuning: 1st argument should be a number.\n");
1251 return -1;
1252 }
1253 bank = atoi(av[0]);
1254 if ((bank < 0) || (bank >= 128)){
1255 fluid_ostream_printf(out, "dumptuning: invalid bank number.\n");
1256 return -1;
1257 };
1258
1259 if (!fluid_is_number(av[1])) {
1260 fluid_ostream_printf(out, "dumptuning: 2nd argument should be a number.\n");
1261 return -1;
1262 }
1263 prog = atoi(av[1]);
1264 if ((prog < 0) || (prog >= 128)){
1265 fluid_ostream_printf(out, "dumptuning: invalid program number.\n");
1266 return -1;
1267 };
1268
1269 fluid_synth_tuning_dump(synth, bank, prog, name, 256, pitch);
1270
1271 fluid_ostream_printf(out, "%03d-%03d %s:\n", bank, prog, name);
1272
1273 for (i = 0; i < 128; i++) {
1274 fluid_ostream_printf(out, "key %03d, pitch %5.2f\n", i, pitch[i]);
1275 }
1276
1277 return 0;
1278 }
1279
1280 int
fluid_handle_set(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1281 fluid_handle_set(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1282 {
1283 int hints;
1284 int ival;
1285
1286 if (ac < 2) {
1287 fluid_ostream_printf(out, "set: Too few arguments.\n");
1288 return -1;
1289 }
1290
1291 switch (fluid_settings_get_type (synth->settings, av[0]))
1292 {
1293 case FLUID_NO_TYPE:
1294 fluid_ostream_printf (out, "set: Parameter '%s' not found.\n", av[0]);
1295 break;
1296 case FLUID_INT_TYPE:
1297 hints = fluid_settings_get_hints (synth->settings, av[0]);
1298
1299 if (hints & FLUID_HINT_TOGGLED)
1300 {
1301 if (FLUID_STRCMP (av[1], "yes") == 0 || FLUID_STRCMP (av[1], "True") == 0
1302 || FLUID_STRCMP (av[1], "TRUE") == 0 || FLUID_STRCMP (av[1], "true") == 0
1303 || FLUID_STRCMP (av[1], "T") == 0)
1304 ival = 1;
1305 else ival = atoi (av[1]);
1306 }
1307 else ival = atoi (av[1]);
1308
1309 fluid_synth_setint (synth, av[0], ival);
1310 break;
1311 case FLUID_NUM_TYPE:
1312 fluid_synth_setnum (synth, av[0], atof (av[1]));
1313 break;
1314 case FLUID_STR_TYPE:
1315 fluid_synth_setstr(synth, av[0], av[1]);
1316 break;
1317 case FLUID_SET_TYPE:
1318 fluid_ostream_printf (out, "set: Parameter '%s' is a node.\n", av[0]);
1319 break;
1320 }
1321
1322 return 0;
1323 }
1324
1325 int
fluid_handle_get(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1326 fluid_handle_get(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1327 {
1328 if (ac < 1) {
1329 fluid_ostream_printf(out, "get: too few arguments.\n");
1330 return -1;
1331 }
1332
1333 switch (fluid_settings_get_type(fluid_synth_get_settings(synth), av[0])) {
1334 case FLUID_NO_TYPE:
1335 fluid_ostream_printf(out, "get: no such setting '%s'.\n", av[0]);
1336 return -1;
1337
1338 case FLUID_NUM_TYPE: {
1339 double value;
1340 fluid_synth_getnum(synth, av[0], &value);
1341 fluid_ostream_printf(out, "%.3f", value);
1342 break;
1343 }
1344
1345 case FLUID_INT_TYPE: {
1346 int value;
1347 fluid_synth_getint(synth, av[0], &value);
1348 fluid_ostream_printf(out, "%d", value);
1349 break;
1350 }
1351
1352 case FLUID_STR_TYPE: {
1353 char* s;
1354 fluid_synth_dupstr(synth, av[0], &s); /* ++ alloc string */
1355 fluid_ostream_printf(out, "%s", s ? s : "NULL");
1356 if (s) FLUID_FREE (s); /* -- free string */
1357 break;
1358 }
1359
1360 case FLUID_SET_TYPE:
1361 fluid_ostream_printf(out, "%s is a node", av[0]);
1362 break;
1363 }
1364
1365 return 0;
1366 }
1367
1368 struct _fluid_handle_settings_data_t {
1369 int len;
1370 fluid_synth_t* synth;
1371 fluid_ostream_t out;
1372 };
1373
fluid_handle_settings_iter1(void * data,char * name,int type)1374 static void fluid_handle_settings_iter1(void* data, char* name, int type)
1375 {
1376 struct _fluid_handle_settings_data_t* d = (struct _fluid_handle_settings_data_t*) data;
1377
1378 int len = FLUID_STRLEN(name);
1379 if (len > d->len) {
1380 d->len = len;
1381 }
1382 }
1383
fluid_handle_settings_iter2(void * data,char * name,int type)1384 static void fluid_handle_settings_iter2(void* data, char* name, int type)
1385 {
1386 struct _fluid_handle_settings_data_t* d = (struct _fluid_handle_settings_data_t*) data;
1387
1388 int len = FLUID_STRLEN(name);
1389 fluid_ostream_printf(d->out, "%s", name);
1390 while (len++ < d->len) {
1391 fluid_ostream_printf(d->out, " ");
1392 }
1393 fluid_ostream_printf(d->out, " ");
1394
1395 switch (fluid_settings_get_type(fluid_synth_get_settings(d->synth), name)) {
1396 case FLUID_NUM_TYPE: {
1397 double value;
1398 fluid_synth_getnum(d->synth, name, &value);
1399 fluid_ostream_printf(d->out, "%.3f\n", value);
1400 break;
1401 }
1402
1403 case FLUID_INT_TYPE: {
1404 int value, hints;
1405 fluid_synth_getint(d->synth, name, &value);
1406 hints = fluid_settings_get_hints (d->synth->settings, name);
1407
1408 if (!(hints & FLUID_HINT_TOGGLED))
1409 fluid_ostream_printf(d->out, "%d\n", value);
1410 else fluid_ostream_printf(d->out, "%s\n", value ? "True" : "False");
1411 break;
1412 }
1413
1414 case FLUID_STR_TYPE: {
1415 char* s;
1416 fluid_synth_dupstr(d->synth, name, &s); /* ++ alloc string */
1417 fluid_ostream_printf(d->out, "%s\n", s ? s : "NULL");
1418 if (s) FLUID_FREE (s); /* -- free string */
1419 break;
1420 }
1421 }
1422 }
1423
1424 int
fluid_handle_settings(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1425 fluid_handle_settings(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1426 {
1427 struct _fluid_handle_settings_data_t data;
1428
1429 data.len = 0;
1430 data.synth = synth;
1431 data.out = out;
1432
1433 fluid_settings_foreach(fluid_synth_get_settings(synth), &data, fluid_handle_settings_iter1);
1434 fluid_settings_foreach(fluid_synth_get_settings(synth), &data, fluid_handle_settings_iter2);
1435 return 0;
1436 }
1437
1438
1439 struct _fluid_handle_option_data_t {
1440 int first;
1441 fluid_ostream_t out;
1442 };
1443
fluid_handle_print_option(void * data,char * name,char * option)1444 void fluid_handle_print_option(void* data, char* name, char* option)
1445 {
1446 struct _fluid_handle_option_data_t* d = (struct _fluid_handle_option_data_t*) data;
1447
1448 if (d->first) {
1449 fluid_ostream_printf(d->out, "%s", option);
1450 d->first = 0;
1451 } else {
1452 fluid_ostream_printf(d->out, ", %s", option);
1453 }
1454 }
1455
1456 int
fluid_handle_info(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1457 fluid_handle_info(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1458 {
1459 fluid_settings_t* settings = fluid_synth_get_settings(synth);
1460 struct _fluid_handle_option_data_t data;
1461
1462 if (ac < 1) {
1463 fluid_ostream_printf(out, "info: too few arguments.\n");
1464 return -1;
1465 }
1466
1467 switch (fluid_settings_get_type(settings, av[0])) {
1468 case FLUID_NO_TYPE:
1469 fluid_ostream_printf(out, "info: no such setting '%s'.\n", av[0]);
1470 return -1;
1471
1472 case FLUID_NUM_TYPE: {
1473 double value, min, max;
1474 fluid_settings_getnum_range(settings, av[0], &min, &max);
1475 fluid_settings_getnum(settings, av[0], &value);
1476 fluid_ostream_printf(out, "%s:\n", av[0]);
1477 fluid_ostream_printf(out, "Type: number\n");
1478 fluid_ostream_printf(out, "Value: %.3f\n", value);
1479 fluid_ostream_printf(out, "Minimum value: %.3f\n", min);
1480 fluid_ostream_printf(out, "Maximum value: %.3f\n", max);
1481 fluid_ostream_printf(out, "Default value: %.3f\n",
1482 fluid_settings_getnum_default(settings, av[0]));
1483 fluid_ostream_printf(out, "Real-time: %s\n",
1484 fluid_settings_is_realtime(settings, av[0])? "yes" : "no");
1485 break;
1486 }
1487
1488 case FLUID_INT_TYPE: {
1489 int value, min, max, def, hints;
1490
1491 fluid_settings_getint_range(settings, av[0], &min, &max);
1492 fluid_settings_getint(settings, av[0], &value);
1493 hints = fluid_settings_get_hints(settings, av[0]);
1494 def = fluid_settings_getint_default (settings, av[0]);
1495
1496 fluid_ostream_printf(out, "%s:\n", av[0]);
1497
1498 if (!(hints & FLUID_HINT_TOGGLED))
1499 {
1500 fluid_ostream_printf(out, "Type: integer\n");
1501 fluid_ostream_printf(out, "Value: %d\n", value);
1502 fluid_ostream_printf(out, "Minimum value: %d\n", min);
1503 fluid_ostream_printf(out, "Maximum value: %d\n", max);
1504 fluid_ostream_printf(out, "Default value: %d\n", def);
1505 }
1506 else
1507 {
1508 fluid_ostream_printf(out, "Type: boolean\n");
1509 fluid_ostream_printf(out, "Value: %s\n", value ? "True" : "False");
1510 fluid_ostream_printf(out, "Default value: %s\n", def ? "True" : "False");
1511 }
1512
1513 fluid_ostream_printf(out, "Real-time: %s\n",
1514 fluid_settings_is_realtime(settings, av[0])? "yes" : "no");
1515 break;
1516 }
1517
1518 case FLUID_STR_TYPE: {
1519 char *s;
1520 fluid_settings_dupstr(settings, av[0], &s); /* ++ alloc string */
1521 fluid_ostream_printf(out, "%s:\n", av[0]);
1522 fluid_ostream_printf(out, "Type: string\n");
1523 fluid_ostream_printf(out, "Value: %s\n", s ? s : "NULL");
1524 fluid_ostream_printf(out, "Default value: %s\n",
1525 fluid_settings_getstr_default(settings, av[0]));
1526
1527 if (s) FLUID_FREE (s);
1528
1529 data.out = out;
1530 data.first = 1;
1531 fluid_ostream_printf(out, "Options: ");
1532 fluid_settings_foreach_option (settings, av[0], &data, fluid_handle_print_option);
1533 fluid_ostream_printf(out, "\n");
1534
1535 fluid_ostream_printf(out, "Real-time: %s\n",
1536 fluid_settings_is_realtime(settings, av[0])? "yes" : "no");
1537 break;
1538 }
1539
1540 case FLUID_SET_TYPE:
1541 fluid_ostream_printf(out, "%s:\n", av[0]);
1542 fluid_ostream_printf(out, "Type: node\n");
1543 break;
1544 }
1545
1546 return 0;
1547 }
1548
1549 int
fluid_handle_reset(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1550 fluid_handle_reset(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1551 {
1552 fluid_synth_system_reset(synth);
1553 return 0;
1554 }
1555
1556 int
fluid_handle_quit(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1557 fluid_handle_quit(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1558 {
1559 fluid_ostream_printf(out, "cheers!\n");
1560 return -2;
1561 }
1562
1563 int
fluid_handle_help(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1564 fluid_handle_help(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1565 {
1566 /* Purpose:
1567 * Prints the help text for the command line commands.
1568 * Can be used as follows:
1569 * - help
1570 * - help (topic), where (topic) is 'general', 'chorus', etc.
1571 * - help all
1572 */
1573
1574 char* topic = "help"; /* default, if no topic is given */
1575 int count = 0;
1576 int i;
1577
1578 fluid_ostream_printf(out, "\n");
1579 /* 1st argument (optional): help topic */
1580 if (ac >= 1) {
1581 topic = av[0];
1582 }
1583 if (strcmp(topic,"help") == 0){
1584 /* "help help": Print a list of all topics */
1585 fluid_ostream_printf(out,
1586 "*** Help topics:***\n"
1587 "help all (prints all topics)\n");
1588 for (i = 0; fluid_commands[i].name != NULL; i++) {
1589 int listed_first_time = 1;
1590 int ii;
1591 for (ii = 0; ii < i; ii++){
1592 if (strcmp(fluid_commands[i].topic, fluid_commands[ii].topic) == 0){
1593 listed_first_time = 0;
1594 }; /* if topic has already been listed */
1595 }; /* for all topics (inner loop) */
1596 if (listed_first_time){
1597 fluid_ostream_printf(out, "help %s\n",fluid_commands[i].topic);
1598 };
1599 }; /* for all topics (outer loop) */
1600 } else {
1601 /* help (arbitrary topic or "all") */
1602 for (i = 0; fluid_commands[i].name != NULL; i++) {
1603 fluid_cmd_t cmd = fluid_commands[i];
1604 if (cmd.help != NULL) {
1605 if (strcmp(topic,"all") == 0 || strcmp(topic,cmd.topic) == 0){
1606 fluid_ostream_printf(out, "%s\n", fluid_commands[i].help);
1607 count++;
1608 }; /* if it matches the topic */
1609 }; /* if help text exists */
1610 }; /* foreach command */
1611 if (count == 0){
1612 fluid_ostream_printf(out, "Unknown help topic. Try 'help help'.\n");
1613 };
1614 };
1615 return 0;
1616 }
1617
1618 int
fluid_is_number(char * a)1619 fluid_is_number(char* a)
1620 {
1621 while (*a != 0) {
1622 if (((*a < '0') || (*a > '9')) && (*a != '-') && (*a != '+') && (*a != '.')) {
1623 return 0;
1624 }
1625 a++;
1626 }
1627 return 1;
1628 }
1629
1630 int
fluid_is_empty(char * a)1631 fluid_is_empty(char* a)
1632 {
1633 while (*a != 0) {
1634 if ((*a != ' ') && (*a != '\t') && (*a != '\n') && (*a != '\r')) {
1635 return 0;
1636 }
1637 a++;
1638 }
1639 return 1;
1640 }
1641
1642 char*
fluid_expand_path(char * path,char * new_path,int len)1643 fluid_expand_path(char* path, char* new_path, int len)
1644 {
1645 #if defined(WIN32) || defined(MACOS9)
1646 snprintf(new_path, len - 1, "%s", path);
1647 #else
1648 if ((path[0] == '~') && (path[1] == '/')) {
1649 char* home = getenv("HOME");
1650 if (home == NULL) {
1651 snprintf(new_path, len - 1, "%s", path);
1652 } else {
1653 snprintf(new_path, len - 1, "%s%s", home, &path[1]);
1654 }
1655 } else {
1656 snprintf(new_path, len - 1, "%s", path);
1657 }
1658 #endif
1659
1660 new_path[len - 1] = 0;
1661 return new_path;
1662 }
1663
1664
1665
1666 /*
1667 * Command
1668 */
1669
fluid_cmd_copy(fluid_cmd_t * cmd)1670 fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd)
1671 {
1672 fluid_cmd_t* copy = FLUID_NEW(fluid_cmd_t);
1673 if (copy == NULL) {
1674 FLUID_LOG (FLUID_PANIC, "Out of memory");
1675 return NULL;
1676 }
1677
1678 copy->name = FLUID_STRDUP(cmd->name);
1679 copy->topic = FLUID_STRDUP(cmd->topic);
1680 copy->help = FLUID_STRDUP(cmd->help);
1681 copy->handler = cmd->handler;
1682 copy->data = cmd->data;
1683 return copy;
1684 }
1685
delete_fluid_cmd(fluid_cmd_t * cmd)1686 void delete_fluid_cmd(fluid_cmd_t* cmd)
1687 {
1688 if (cmd->name) {
1689 FLUID_FREE(cmd->name);
1690 }
1691 if (cmd->topic) {
1692 FLUID_FREE(cmd->topic);
1693 }
1694 if (cmd->help) {
1695 FLUID_FREE(cmd->help);
1696 }
1697 FLUID_FREE(cmd);
1698 }
1699
1700 /*
1701 * Command handler
1702 */
1703
1704 static void
fluid_cmd_handler_destroy_hash_value(void * value)1705 fluid_cmd_handler_destroy_hash_value (void *value)
1706 {
1707 delete_fluid_cmd ((fluid_cmd_t *)value);
1708 }
1709
1710 /**
1711 * Create a new command handler.
1712 * @param synth If not NULL, all the default synthesizer commands will be
1713 * added to the new handler.
1714 * @return New command handler
1715 */
1716 fluid_cmd_handler_t *
new_fluid_cmd_handler(fluid_synth_t * synth)1717 new_fluid_cmd_handler(fluid_synth_t* synth)
1718 {
1719 int i;
1720 fluid_cmd_handler_t* handler;
1721
1722 fluid_cmd_t source = {
1723 "source", "general", (fluid_cmd_func_t) fluid_handle_source, NULL,
1724 "source filename Load a file and parse every line as a command"
1725 };
1726
1727 handler = new_fluid_hashtable_full (fluid_str_hash, fluid_str_equal,
1728 NULL, fluid_cmd_handler_destroy_hash_value);
1729 if (handler == NULL) {
1730 return NULL;
1731 }
1732
1733 if (synth != NULL) {
1734 for (i = 0; fluid_commands[i].name != NULL; i++) {
1735 fluid_commands[i].data = synth;
1736 fluid_cmd_handler_register(handler, &fluid_commands[i]);
1737 fluid_commands[i].data = NULL;
1738 }
1739 }
1740
1741 source.data = handler;
1742 fluid_cmd_handler_register(handler, &source);
1743
1744 return handler;
1745 }
1746
1747 /**
1748 * Delete a command handler.
1749 * @param handler Command handler to delete
1750 */
1751 void
delete_fluid_cmd_handler(fluid_cmd_handler_t * handler)1752 delete_fluid_cmd_handler(fluid_cmd_handler_t* handler)
1753 {
1754 delete_fluid_hashtable (handler);
1755 }
1756
1757 /**
1758 * Register a new command to the handler.
1759 * @param handler Command handler instance
1760 * @param cmd Command info (gets copied)
1761 * @return #FLUID_OK if command was inserted, #FLUID_FAILED otherwise
1762 */
1763 int
fluid_cmd_handler_register(fluid_cmd_handler_t * handler,fluid_cmd_t * cmd)1764 fluid_cmd_handler_register(fluid_cmd_handler_t* handler, fluid_cmd_t* cmd)
1765 {
1766 fluid_cmd_t* copy = fluid_cmd_copy(cmd);
1767 fluid_hashtable_insert(handler, copy->name, copy);
1768 return FLUID_OK;
1769 }
1770
1771 /**
1772 * Unregister a command from a command handler.
1773 * @param handler Command handler instance
1774 * @param cmd Name of the command
1775 * @return TRUE if command was found and unregistered, FALSE otherwise
1776 */
1777 int
fluid_cmd_handler_unregister(fluid_cmd_handler_t * handler,const char * cmd)1778 fluid_cmd_handler_unregister(fluid_cmd_handler_t* handler, const char *cmd)
1779 {
1780 return fluid_hashtable_remove(handler, cmd);
1781 }
1782
1783 int
fluid_cmd_handler_handle(fluid_cmd_handler_t * handler,int ac,char ** av,fluid_ostream_t out)1784 fluid_cmd_handler_handle(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
1785 {
1786 fluid_cmd_t* cmd;
1787
1788 cmd = fluid_hashtable_lookup(handler, av[0]);
1789
1790 if (cmd && cmd->handler)
1791 return (*cmd->handler)(cmd->data, ac - 1, av + 1, out);
1792
1793 fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
1794 return -1;
1795 }
1796