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((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 fluid_ostream_printf(out, "%2d %s\n",
699 fluid_sfont_get_id(sfont),
700 fluid_sfont_get_name(sfont));
701 }
702
703 return 0;
704 }
705
706 int
fluid_handle_mstat(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)707 fluid_handle_mstat(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
708 {
709 /* fluid_ostream_printf(out, "Dvr=%s, Dev=%s\n", */
710 /* fluid_midi_handler_get_driver_name(midi), */
711 /* fluid_midi_handler_get_device_name(midi)); */
712 /* fluid_ostream_printf(out, "Stat=%s, On=%d, Off=%d, Prog=%d, Pbend=%d, Err=%d\n", */
713 /* fluid_midi_handler_get_status(midi), */
714 /* fluid_midi_handler_get_event_count(midi, 0x90), */
715 /* fluid_midi_handler_get_event_count(midi, 0x80), */
716 /* fluid_midi_handler_get_event_count(midi, 0xc0), */
717 /* fluid_midi_handler_get_event_count(midi, 0xe0), */
718 /* fluid_midi_handler_get_event_count(midi, 0)); */
719 fluid_ostream_printf(out, "not yet implemented\n");
720 return -1;
721 }
722
723 /* Purpose:
724 * Response to 'rev_preset' command.
725 * Load the values from a reverb preset into the reverb unit. */
726 int
fluid_handle_reverbpreset(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)727 fluid_handle_reverbpreset(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
728 {
729 int reverb_preset_number;
730 if (ac < 1) {
731 fluid_ostream_printf(out, "rev_preset: too few arguments\n");
732 return -1;
733 }
734 reverb_preset_number = atoi(av[0]);
735 if (fluid_synth_set_reverb_preset(synth, reverb_preset_number)!=FLUID_OK){
736 fluid_ostream_printf(out, "rev_preset: Failed. Parameter out of range?\n");
737 return -1;
738 };
739 return 0;
740 }
741
742 /* Purpose:
743 * Response to 'rev_setroomsize' command.
744 * Load the new room size into the reverb unit. */
745 int
fluid_handle_reverbsetroomsize(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)746 fluid_handle_reverbsetroomsize(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
747 {
748 fluid_real_t room_size;
749 if (ac < 1) {
750 fluid_ostream_printf(out, "rev_setroomsize: too few arguments.\n");
751 return -1;
752 }
753 room_size = atof(av[0]);
754 if (room_size < 0){
755 fluid_ostream_printf(out, "rev_setroomsize: Room size must be positive!\n");
756 return -1;
757 }
758 if (room_size > 1.2){
759 fluid_ostream_printf(out, "rev_setroomsize: Room size too big!\n");
760 return -1;
761 }
762 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_ROOMSIZE,
763 room_size, 0.0, 0.0, 0.0);
764 return 0;
765 }
766
767 /* Purpose:
768 * Response to 'rev_setdamp' command.
769 * Load the new damp factor into the reverb unit. */
770 int
fluid_handle_reverbsetdamp(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)771 fluid_handle_reverbsetdamp(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
772 {
773 fluid_real_t damp;
774 if (ac < 1) {
775 fluid_ostream_printf(out, "rev_setdamp: too few arguments.\n");
776 return -1;
777 }
778 damp = atof(av[0]);
779 if ((damp < 0.0f) || (damp > 1)){
780 fluid_ostream_printf(out, "rev_setdamp: damp must be between 0 and 1!\n");
781 return -1;
782 }
783 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_DAMPING,
784 0.0, damp, 0.0, 0.0);
785 return 0;
786 }
787
788 /* Purpose:
789 * Response to 'rev_setwidth' command.
790 * Load the new width into the reverb unit. */
791 int
fluid_handle_reverbsetwidth(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)792 fluid_handle_reverbsetwidth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
793 {
794 fluid_real_t width;
795 if (ac < 1) {
796 fluid_ostream_printf(out, "rev_setwidth: too few arguments.\n");
797 return -1;
798 }
799 width = atof(av[0]);
800 if ((width < 0) || (width > 100)){
801 fluid_ostream_printf(out, "rev_setroomsize: Too wide! (0..100)\n");
802 return 0;
803 }
804 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_WIDTH,
805 0.0, 0.0, width, 0.0);
806 return 0;
807 }
808
809 /* Purpose:
810 * Response to 'rev_setlevel' command.
811 * Load the new level into the reverb unit. */
812 int
fluid_handle_reverbsetlevel(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)813 fluid_handle_reverbsetlevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
814 {
815 fluid_real_t level;
816 if (ac < 1) {
817 fluid_ostream_printf(out, "rev_setlevel: too few arguments.\n");
818 return -1;
819 }
820 level = atof(av[0]);
821 if (fabsf(level) > 30){
822 fluid_ostream_printf(out, "rev_setlevel: Value too high! (Value of 10 =+20 dB)\n");
823 return 0;
824 }
825 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_LEVEL,
826 0.0, 0.0, 0.0, level);
827 return 0;
828 }
829
830 /* Purpose:
831 * Response to 'reverb' command.
832 * Change the FLUID_REVERB flag in the synth */
833 int
fluid_handle_reverb(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)834 fluid_handle_reverb(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
835 {
836 if (ac < 1) {
837 fluid_ostream_printf(out, "reverb: too few arguments.\n");
838 return -1;
839 }
840
841 if ((strcmp(av[0], "0") == 0) || (strcmp(av[0], "off") == 0)) {
842 fluid_synth_set_reverb_on(synth,0);
843 } else if ((strcmp(av[0], "1") == 0) || (strcmp(av[0], "on") == 0)) {
844 fluid_synth_set_reverb_on(synth,1);
845 } else {
846 fluid_ostream_printf(out, "reverb: invalid arguments %s [0|1|on|off]", av[0]);
847 return -1;
848 }
849
850 return 0;
851 }
852
853
854 /* Purpose:
855 * Response to 'chorus_setnr' command */
856 int
fluid_handle_chorusnr(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)857 fluid_handle_chorusnr(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
858 {
859 int nr;
860 if (ac < 1) {
861 fluid_ostream_printf(out, "cho_set_nr: too few arguments.\n");
862 return -1;
863 }
864 nr = atoi(av[0]);
865 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_NR, nr, 0.0, 0.0, 0.0, 0);
866 }
867
868 /* Purpose:
869 * Response to 'chorus_setlevel' command */
870 int
fluid_handle_choruslevel(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)871 fluid_handle_choruslevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
872 {
873 fluid_real_t level;
874 if (ac < 1) {
875 fluid_ostream_printf(out, "cho_set_level: too few arguments.\n");
876 return -1;
877 }
878 level = atof(av[0]);
879 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_LEVEL, 0, level, 0.0, 0.0, 0);
880 }
881
882 /* Purpose:
883 * Response to 'chorus_setspeed' command */
884 int
fluid_handle_chorusspeed(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)885 fluid_handle_chorusspeed(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
886 {
887 fluid_real_t speed;
888 if (ac < 1) {
889 fluid_ostream_printf(out, "cho_set_speed: too few arguments.\n");
890 return -1;
891 }
892 speed = atof(av[0]);
893 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_SPEED, 0, 0.0, speed, 0.0, 0);
894 }
895
896 /* Purpose:
897 * Response to 'chorus_setdepth' command */
898 int
fluid_handle_chorusdepth(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)899 fluid_handle_chorusdepth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
900 {
901 fluid_real_t depth;
902 if (ac < 1) {
903 fluid_ostream_printf(out, "cho_set_depth: too few arguments.\n");
904 return -1;
905 }
906 depth = atof(av[0]);
907 return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_DEPTH, 0, 0.0, 0.0, depth, 0);
908 }
909
910 int
fluid_handle_chorus(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)911 fluid_handle_chorus(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
912 {
913 if (ac < 1) {
914 fluid_ostream_printf(out, "chorus: too few arguments\n");
915 return -1;
916 }
917
918 if ((strcmp(av[0], "0") == 0) || (strcmp(av[0], "off") == 0)) {
919 fluid_synth_set_chorus_on(synth,0);
920 } else if ((strcmp(av[0], "1") == 0) || (strcmp(av[0], "on") == 0)) {
921 fluid_synth_set_chorus_on(synth,1);
922 } else {
923 fluid_ostream_printf(out, "chorus: invalid arguments %s [0|1|on|off]", av[0]);
924 return -1;
925 }
926
927 return 0;
928 }
929
930 /* Purpose:
931 * Response to the 'echo' command.
932 * The command itself is useful, when the synth is used via TCP/IP.
933 * It can signal for example, that a list of commands has been processed.
934 */
935 int
fluid_handle_echo(fluid_cmd_handler_t * handler,int ac,char ** av,fluid_ostream_t out)936 fluid_handle_echo(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
937 {
938 if (ac < 1) {
939 fluid_ostream_printf(out, "echo: too few arguments.\n");
940 return -1;
941 }
942
943 fluid_ostream_printf(out, "%s\n",av[0]);
944
945 return 0;
946 }
947
948 int
fluid_handle_source(fluid_cmd_handler_t * handler,int ac,char ** av,fluid_ostream_t out)949 fluid_handle_source(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
950 {
951 if (ac < 1) {
952 fluid_ostream_printf(out, "source: too few arguments.\n");
953 return -1;
954 }
955
956 fluid_source(handler, av[0]);
957
958 return 0;
959 }
960
961 /* Purpose:
962 * Response to 'gain' command. */
963 int
fluid_handle_gain(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)964 fluid_handle_gain(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
965 {
966 float gain;
967
968 if (ac < 1) {
969 fluid_ostream_printf(out, "gain: too few arguments.\n");
970 return -1;
971 }
972
973 gain = atof(av[0]);
974
975 if ((gain < 0.0f) || (gain > 5.0f)) {
976 fluid_ostream_printf(out, "gain: value should be between '0' and '5'.\n");
977 return -1;
978 };
979
980 fluid_synth_set_gain(synth, gain);
981
982 return 0;
983 }
984
985 /* Response to voice_count command */
986 static int
fluid_handle_voice_count(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)987 fluid_handle_voice_count (fluid_synth_t *synth, int ac, char **av,
988 fluid_ostream_t out)
989 {
990 fluid_ostream_printf (out, "voice_count: %d\n",
991 fluid_synth_get_active_voice_count (synth));
992 return FLUID_OK;
993 }
994
995 /* Purpose:
996 * Response to 'interp' command. */
997 int
fluid_handle_interp(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)998 fluid_handle_interp(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
999 {
1000 int interp;
1001 int chan=-1; /* -1: Set all channels */
1002
1003 if (ac < 1) {
1004 fluid_ostream_printf(out, "interp: too few arguments.\n");
1005 return -1;
1006 }
1007
1008 interp = atoi(av[0]);
1009
1010 if ((interp < 0) || (interp > FLUID_INTERP_HIGHEST)) {
1011 fluid_ostream_printf(out, "interp: Bad value\n");
1012 return -1;
1013 };
1014
1015 fluid_synth_set_interp_method(synth, chan, interp);
1016
1017 return 0;
1018 }
1019
1020 /* Purpose:
1021 * Response to 'interp' command. */
1022 int
fluid_handle_interpc(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1023 fluid_handle_interpc(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1024 {
1025 int interp;
1026 int chan;
1027
1028 if (ac < 2) {
1029 fluid_ostream_printf(out, "interpc: too few arguments.\n");
1030 return -1;
1031 }
1032
1033 chan = atoi(av[0]);
1034 interp = atoi(av[1]);
1035
1036 if ((chan < 0) || (chan >= fluid_synth_count_midi_channels(synth))){
1037 fluid_ostream_printf(out, "interp: Bad value for channel number.\n");
1038 return -1;
1039 };
1040 if ((interp < 0) || (interp > FLUID_INTERP_HIGHEST)) {
1041 fluid_ostream_printf(out, "interp: Bad value for interpolation method.\n");
1042 return -1;
1043 };
1044
1045 fluid_synth_set_interp_method(synth, chan, interp);
1046
1047 return 0;
1048 }
1049
1050 int
fluid_handle_tuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1051 fluid_handle_tuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1052 {
1053 char *name;
1054 int bank, prog;
1055
1056 if (ac < 3) {
1057 fluid_ostream_printf(out, "tuning: too few arguments.\n");
1058 return -1;
1059 }
1060
1061 name = av[0];
1062
1063 if (!fluid_is_number(av[1])) {
1064 fluid_ostream_printf(out, "tuning: 2nd argument should be a number.\n");
1065 return -1;
1066 }
1067 bank = atoi(av[1]);
1068 if ((bank < 0) || (bank >= 128)){
1069 fluid_ostream_printf(out, "tuning: invalid bank number.\n");
1070 return -1;
1071 };
1072
1073 if (!fluid_is_number(av[2])) {
1074 fluid_ostream_printf(out, "tuning: 3rd argument should be a number.\n");
1075 return -1;
1076 }
1077 prog = atoi(av[2]);
1078 if ((prog < 0) || (prog >= 128)){
1079 fluid_ostream_printf(out, "tuning: invalid program number.\n");
1080 return -1;
1081 };
1082
1083 fluid_synth_create_key_tuning(synth, bank, prog, name, NULL);
1084
1085 return 0;
1086 }
1087
1088 int
fluid_handle_tune(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1089 fluid_handle_tune(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1090 {
1091 int bank, prog, key;
1092 double pitch;
1093
1094 if (ac < 4) {
1095 fluid_ostream_printf(out, "tune: too few arguments.\n");
1096 return -1;
1097 }
1098
1099 if (!fluid_is_number(av[0])) {
1100 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1101 return -1;
1102 }
1103 bank = atoi(av[0]);
1104 if ((bank < 0) || (bank >= 128)){
1105 fluid_ostream_printf(out, "tune: invalid bank number.\n");
1106 return -1;
1107 };
1108
1109 if (!fluid_is_number(av[1])) {
1110 fluid_ostream_printf(out, "tune: 2nd argument should be a number.\n");
1111 return -1;
1112 }
1113 prog = atoi(av[1]);
1114 if ((prog < 0) || (prog >= 128)){
1115 fluid_ostream_printf(out, "tune: invalid program number.\n");
1116 return -1;
1117 };
1118
1119 if (!fluid_is_number(av[2])) {
1120 fluid_ostream_printf(out, "tune: 3rd argument should be a number.\n");
1121 return -1;
1122 }
1123 key = atoi(av[2]);
1124 if ((key < 0) || (key >= 128)){
1125 fluid_ostream_printf(out, "tune: invalid key number.\n");
1126 return -1;
1127 };
1128
1129 pitch = atof(av[3]);
1130 if (pitch < 0.0f) {
1131 fluid_ostream_printf(out, "tune: invalid pitch.\n");
1132 return -1;
1133 };
1134
1135 fluid_synth_tune_notes(synth, bank, prog, 1, &key, &pitch, 0);
1136
1137 return 0;
1138 }
1139
1140 int
fluid_handle_settuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1141 fluid_handle_settuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1142 {
1143 int chan, bank, prog;
1144
1145 if (ac < 3) {
1146 fluid_ostream_printf(out, "settuning: too few arguments.\n");
1147 return -1;
1148 }
1149
1150 if (!fluid_is_number(av[0])) {
1151 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1152 return -1;
1153 }
1154 chan = atoi(av[0]);
1155 if ((chan < 0) || (chan >= fluid_synth_count_midi_channels(synth))){
1156 fluid_ostream_printf(out, "tune: invalid channel number.\n");
1157 return -1;
1158 };
1159
1160 if (!fluid_is_number(av[1])) {
1161 fluid_ostream_printf(out, "tuning: 2nd argument should be a number.\n");
1162 return -1;
1163 }
1164 bank = atoi(av[1]);
1165 if ((bank < 0) || (bank >= 128)){
1166 fluid_ostream_printf(out, "tuning: invalid bank number.\n");
1167 return -1;
1168 };
1169
1170 if (!fluid_is_number(av[2])) {
1171 fluid_ostream_printf(out, "tuning: 3rd argument should be a number.\n");
1172 return -1;
1173 }
1174 prog = atoi(av[2]);
1175 if ((prog < 0) || (prog >= 128)){
1176 fluid_ostream_printf(out, "tuning: invalid program number.\n");
1177 return -1;
1178 };
1179
1180 fluid_synth_select_tuning(synth, chan, bank, prog);
1181
1182 return 0;
1183 }
1184
1185 int
fluid_handle_resettuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1186 fluid_handle_resettuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1187 {
1188 int chan;
1189
1190 if (ac < 1) {
1191 fluid_ostream_printf(out, "resettuning: too few arguments.\n");
1192 return -1;
1193 }
1194
1195 if (!fluid_is_number(av[0])) {
1196 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1197 return -1;
1198 }
1199 chan = atoi(av[0]);
1200 if ((chan < 0) || (chan >= fluid_synth_count_midi_channels(synth))){
1201 fluid_ostream_printf(out, "tune: invalid channel number.\n");
1202 return -1;
1203 };
1204
1205 fluid_synth_reset_tuning(synth, chan);
1206
1207 return 0;
1208 }
1209
1210 int
fluid_handle_tunings(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1211 fluid_handle_tunings(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1212 {
1213 int bank, prog;
1214 char name[256];
1215 int count = 0;
1216
1217 fluid_synth_tuning_iteration_start(synth);
1218
1219 while (fluid_synth_tuning_iteration_next(synth, &bank, &prog)) {
1220 fluid_synth_tuning_dump(synth, bank, prog, name, 256, NULL);
1221 fluid_ostream_printf(out, "%03d-%03d %s\n", bank, prog, name);
1222 count++;
1223 }
1224
1225 if (count == 0) {
1226 fluid_ostream_printf(out, "No tunings available\n");
1227 }
1228
1229 return 0;
1230 }
1231
1232 int
fluid_handle_dumptuning(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1233 fluid_handle_dumptuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1234 {
1235 int bank, prog, i;
1236 double pitch[128];
1237 char name[256];
1238
1239 if (ac < 2) {
1240 fluid_ostream_printf(out, "dumptuning: too few arguments.\n");
1241 return -1;
1242 }
1243
1244 if (!fluid_is_number(av[0])) {
1245 fluid_ostream_printf(out, "dumptuning: 1st argument should be a number.\n");
1246 return -1;
1247 }
1248 bank = atoi(av[0]);
1249 if ((bank < 0) || (bank >= 128)){
1250 fluid_ostream_printf(out, "dumptuning: invalid bank number.\n");
1251 return -1;
1252 };
1253
1254 if (!fluid_is_number(av[1])) {
1255 fluid_ostream_printf(out, "dumptuning: 2nd argument should be a number.\n");
1256 return -1;
1257 }
1258 prog = atoi(av[1]);
1259 if ((prog < 0) || (prog >= 128)){
1260 fluid_ostream_printf(out, "dumptuning: invalid program number.\n");
1261 return -1;
1262 };
1263
1264 fluid_synth_tuning_dump(synth, bank, prog, name, 256, pitch);
1265
1266 fluid_ostream_printf(out, "%03d-%03d %s:\n", bank, prog, name);
1267
1268 for (i = 0; i < 128; i++) {
1269 fluid_ostream_printf(out, "key %03d, pitch %5.2f\n", i, pitch[i]);
1270 }
1271
1272 return 0;
1273 }
1274
1275 int
fluid_handle_set(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1276 fluid_handle_set(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1277 {
1278 int hints;
1279 int ival;
1280
1281 if (ac < 2) {
1282 fluid_ostream_printf(out, "set: Too few arguments.\n");
1283 return -1;
1284 }
1285
1286 switch (fluid_settings_get_type (synth->settings, av[0]))
1287 {
1288 case FLUID_NO_TYPE:
1289 fluid_ostream_printf (out, "set: Parameter '%s' not found.\n", av[0]);
1290 break;
1291 case FLUID_INT_TYPE:
1292 hints = fluid_settings_get_hints (synth->settings, av[0]);
1293
1294 if (hints & FLUID_HINT_TOGGLED)
1295 {
1296 if (FLUID_STRCMP (av[1], "yes") == 0 || FLUID_STRCMP (av[1], "True") == 0
1297 || FLUID_STRCMP (av[1], "TRUE") == 0 || FLUID_STRCMP (av[1], "true") == 0
1298 || FLUID_STRCMP (av[1], "T") == 0)
1299 ival = 1;
1300 else ival = atoi (av[1]);
1301 }
1302 else ival = atoi (av[1]);
1303
1304 fluid_synth_setint (synth, av[0], ival);
1305 break;
1306 case FLUID_NUM_TYPE:
1307 fluid_synth_setnum (synth, av[0], atof (av[1]));
1308 break;
1309 case FLUID_STR_TYPE:
1310 fluid_synth_setstr(synth, av[0], av[1]);
1311 break;
1312 case FLUID_SET_TYPE:
1313 fluid_ostream_printf (out, "set: Parameter '%s' is a node.\n", av[0]);
1314 break;
1315 }
1316
1317 return 0;
1318 }
1319
1320 int
fluid_handle_get(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1321 fluid_handle_get(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1322 {
1323 if (ac < 1) {
1324 fluid_ostream_printf(out, "get: too few arguments.\n");
1325 return -1;
1326 }
1327
1328 switch (fluid_settings_get_type(fluid_synth_get_settings(synth), av[0])) {
1329 case FLUID_NO_TYPE:
1330 fluid_ostream_printf(out, "get: no such setting '%s'.\n", av[0]);
1331 return -1;
1332
1333 case FLUID_NUM_TYPE: {
1334 double value;
1335 fluid_synth_getnum(synth, av[0], &value);
1336 fluid_ostream_printf(out, "%.3f", value);
1337 break;
1338 }
1339
1340 case FLUID_INT_TYPE: {
1341 int value;
1342 fluid_synth_getint(synth, av[0], &value);
1343 fluid_ostream_printf(out, "%d", value);
1344 break;
1345 }
1346
1347 case FLUID_STR_TYPE: {
1348 char* s;
1349 fluid_synth_dupstr(synth, av[0], &s); /* ++ alloc string */
1350 fluid_ostream_printf(out, "%s", s ? s : "NULL");
1351 if (s) FLUID_FREE (s); /* -- free string */
1352 break;
1353 }
1354
1355 case FLUID_SET_TYPE:
1356 fluid_ostream_printf(out, "%s is a node", av[0]);
1357 break;
1358 }
1359
1360 return 0;
1361 }
1362
1363 struct _fluid_handle_settings_data_t {
1364 int len;
1365 fluid_synth_t* synth;
1366 fluid_ostream_t out;
1367 };
1368
fluid_handle_settings_iter1(void * data,char * name,int type)1369 static void fluid_handle_settings_iter1(void* data, char* name, int type)
1370 {
1371 struct _fluid_handle_settings_data_t* d = (struct _fluid_handle_settings_data_t*) data;
1372
1373 int len = FLUID_STRLEN(name);
1374 if (len > d->len) {
1375 d->len = len;
1376 }
1377 }
1378
fluid_handle_settings_iter2(void * data,char * name,int type)1379 static void fluid_handle_settings_iter2(void* data, char* name, int type)
1380 {
1381 struct _fluid_handle_settings_data_t* d = (struct _fluid_handle_settings_data_t*) data;
1382
1383 int len = FLUID_STRLEN(name);
1384 fluid_ostream_printf(d->out, "%s", name);
1385 while (len++ < d->len) {
1386 fluid_ostream_printf(d->out, " ");
1387 }
1388 fluid_ostream_printf(d->out, " ");
1389
1390 switch (fluid_settings_get_type(fluid_synth_get_settings(d->synth), name)) {
1391 case FLUID_NUM_TYPE: {
1392 double value;
1393 fluid_synth_getnum(d->synth, name, &value);
1394 fluid_ostream_printf(d->out, "%.3f\n", value);
1395 break;
1396 }
1397
1398 case FLUID_INT_TYPE: {
1399 int value, hints;
1400 fluid_synth_getint(d->synth, name, &value);
1401 hints = fluid_settings_get_hints (d->synth->settings, name);
1402
1403 if (!(hints & FLUID_HINT_TOGGLED))
1404 fluid_ostream_printf(d->out, "%d\n", value);
1405 else fluid_ostream_printf(d->out, "%s\n", value ? "True" : "False");
1406 break;
1407 }
1408
1409 case FLUID_STR_TYPE: {
1410 char* s;
1411 fluid_synth_dupstr(d->synth, name, &s); /* ++ alloc string */
1412 fluid_ostream_printf(d->out, "%s\n", s ? s : "NULL");
1413 if (s) FLUID_FREE (s); /* -- free string */
1414 break;
1415 }
1416 }
1417 }
1418
1419 int
fluid_handle_settings(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1420 fluid_handle_settings(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1421 {
1422 struct _fluid_handle_settings_data_t data;
1423
1424 data.len = 0;
1425 data.synth = synth;
1426 data.out = out;
1427
1428 fluid_settings_foreach(fluid_synth_get_settings(synth), &data, fluid_handle_settings_iter1);
1429 fluid_settings_foreach(fluid_synth_get_settings(synth), &data, fluid_handle_settings_iter2);
1430 return 0;
1431 }
1432
1433
1434 struct _fluid_handle_option_data_t {
1435 int first;
1436 fluid_ostream_t out;
1437 };
1438
fluid_handle_print_option(void * data,char * name,char * option)1439 void fluid_handle_print_option(void* data, char* name, char* option)
1440 {
1441 struct _fluid_handle_option_data_t* d = (struct _fluid_handle_option_data_t*) data;
1442
1443 if (d->first) {
1444 fluid_ostream_printf(d->out, "%s", option);
1445 d->first = 0;
1446 } else {
1447 fluid_ostream_printf(d->out, ", %s", option);
1448 }
1449 }
1450
1451 int
fluid_handle_info(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1452 fluid_handle_info(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1453 {
1454 fluid_settings_t* settings = fluid_synth_get_settings(synth);
1455 struct _fluid_handle_option_data_t data;
1456
1457 if (ac < 1) {
1458 fluid_ostream_printf(out, "info: too few arguments.\n");
1459 return -1;
1460 }
1461
1462 switch (fluid_settings_get_type(settings, av[0])) {
1463 case FLUID_NO_TYPE:
1464 fluid_ostream_printf(out, "info: no such setting '%s'.\n", av[0]);
1465 return -1;
1466
1467 case FLUID_NUM_TYPE: {
1468 double value, min, max;
1469 fluid_settings_getnum_range(settings, av[0], &min, &max);
1470 fluid_settings_getnum(settings, av[0], &value);
1471 fluid_ostream_printf(out, "%s:\n", av[0]);
1472 fluid_ostream_printf(out, "Type: number\n");
1473 fluid_ostream_printf(out, "Value: %.3f\n", value);
1474 fluid_ostream_printf(out, "Minimum value: %.3f\n", min);
1475 fluid_ostream_printf(out, "Maximum value: %.3f\n", max);
1476 fluid_ostream_printf(out, "Default value: %.3f\n",
1477 fluid_settings_getnum_default(settings, av[0]));
1478 fluid_ostream_printf(out, "Real-time: %s\n",
1479 fluid_settings_is_realtime(settings, av[0])? "yes" : "no");
1480 break;
1481 }
1482
1483 case FLUID_INT_TYPE: {
1484 int value, min, max, def, hints;
1485
1486 fluid_settings_getint_range(settings, av[0], &min, &max);
1487 fluid_settings_getint(settings, av[0], &value);
1488 hints = fluid_settings_get_hints(settings, av[0]);
1489 def = fluid_settings_getint_default (settings, av[0]);
1490
1491 fluid_ostream_printf(out, "%s:\n", av[0]);
1492
1493 if (!(hints & FLUID_HINT_TOGGLED))
1494 {
1495 fluid_ostream_printf(out, "Type: integer\n");
1496 fluid_ostream_printf(out, "Value: %d\n", value);
1497 fluid_ostream_printf(out, "Minimum value: %d\n", min);
1498 fluid_ostream_printf(out, "Maximum value: %d\n", max);
1499 fluid_ostream_printf(out, "Default value: %d\n", def);
1500 }
1501 else
1502 {
1503 fluid_ostream_printf(out, "Type: boolean\n");
1504 fluid_ostream_printf(out, "Value: %s\n", value ? "True" : "False");
1505 fluid_ostream_printf(out, "Default value: %s\n", def ? "True" : "False");
1506 }
1507
1508 fluid_ostream_printf(out, "Real-time: %s\n",
1509 fluid_settings_is_realtime(settings, av[0])? "yes" : "no");
1510 break;
1511 }
1512
1513 case FLUID_STR_TYPE: {
1514 char *s;
1515 fluid_settings_dupstr(settings, av[0], &s); /* ++ alloc string */
1516 fluid_ostream_printf(out, "%s:\n", av[0]);
1517 fluid_ostream_printf(out, "Type: string\n");
1518 fluid_ostream_printf(out, "Value: %s\n", s ? s : "NULL");
1519 fluid_ostream_printf(out, "Default value: %s\n",
1520 fluid_settings_getstr_default(settings, av[0]));
1521
1522 if (s) FLUID_FREE (s);
1523
1524 data.out = out;
1525 data.first = 1;
1526 fluid_ostream_printf(out, "Options: ");
1527 fluid_settings_foreach_option (settings, av[0], &data, fluid_handle_print_option);
1528 fluid_ostream_printf(out, "\n");
1529
1530 fluid_ostream_printf(out, "Real-time: %s\n",
1531 fluid_settings_is_realtime(settings, av[0])? "yes" : "no");
1532 break;
1533 }
1534
1535 case FLUID_SET_TYPE:
1536 fluid_ostream_printf(out, "%s:\n", av[0]);
1537 fluid_ostream_printf(out, "Type: node\n");
1538 break;
1539 }
1540
1541 return 0;
1542 }
1543
1544 int
fluid_handle_reset(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1545 fluid_handle_reset(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1546 {
1547 fluid_synth_system_reset(synth);
1548 return 0;
1549 }
1550
1551 int
fluid_handle_quit(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1552 fluid_handle_quit(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1553 {
1554 fluid_ostream_printf(out, "cheers!\n");
1555 return -2;
1556 }
1557
1558 int
fluid_handle_help(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)1559 fluid_handle_help(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
1560 {
1561 /* Purpose:
1562 * Prints the help text for the command line commands.
1563 * Can be used as follows:
1564 * - help
1565 * - help (topic), where (topic) is 'general', 'chorus', etc.
1566 * - help all
1567 */
1568
1569 char* topic = "help"; /* default, if no topic is given */
1570 int count = 0;
1571 int i;
1572
1573 fluid_ostream_printf(out, "\n");
1574 /* 1st argument (optional): help topic */
1575 if (ac >= 1) {
1576 topic = av[0];
1577 }
1578 if (strcmp(topic,"help") == 0){
1579 /* "help help": Print a list of all topics */
1580 fluid_ostream_printf(out,
1581 "*** Help topics:***\n"
1582 "help all (prints all topics)\n");
1583 for (i = 0; fluid_commands[i].name != NULL; i++) {
1584 int listed_first_time = 1;
1585 int ii;
1586 for (ii = 0; ii < i; ii++){
1587 if (strcmp(fluid_commands[i].topic, fluid_commands[ii].topic) == 0){
1588 listed_first_time = 0;
1589 }; /* if topic has already been listed */
1590 }; /* for all topics (inner loop) */
1591 if (listed_first_time){
1592 fluid_ostream_printf(out, "help %s\n",fluid_commands[i].topic);
1593 };
1594 }; /* for all topics (outer loop) */
1595 } else {
1596 /* help (arbitrary topic or "all") */
1597 for (i = 0; fluid_commands[i].name != NULL; i++) {
1598 fluid_cmd_t cmd = fluid_commands[i];
1599 if (cmd.help != NULL) {
1600 if (strcmp(topic,"all") == 0 || strcmp(topic,cmd.topic) == 0){
1601 fluid_ostream_printf(out, "%s\n", fluid_commands[i].help);
1602 count++;
1603 }; /* if it matches the topic */
1604 }; /* if help text exists */
1605 }; /* foreach command */
1606 if (count == 0){
1607 fluid_ostream_printf(out, "Unknown help topic. Try 'help help'.\n");
1608 };
1609 };
1610 return 0;
1611 }
1612
1613 int
fluid_is_number(char * a)1614 fluid_is_number(char* a)
1615 {
1616 while (*a != 0) {
1617 if (((*a < '0') || (*a > '9')) && (*a != '-') && (*a != '+') && (*a != '.')) {
1618 return 0;
1619 }
1620 a++;
1621 }
1622 return 1;
1623 }
1624
1625 int
fluid_is_empty(char * a)1626 fluid_is_empty(char* a)
1627 {
1628 while (*a != 0) {
1629 if ((*a != ' ') && (*a != '\t') && (*a != '\n') && (*a != '\r')) {
1630 return 0;
1631 }
1632 a++;
1633 }
1634 return 1;
1635 }
1636
1637 char*
fluid_expand_path(char * path,char * new_path,int len)1638 fluid_expand_path(char* path, char* new_path, int len)
1639 {
1640 #if defined(WIN32) || defined(MACOS9)
1641 snprintf(new_path, len - 1, "%s", path);
1642 #else
1643 if ((path[0] == '~') && (path[1] == '/')) {
1644 char* home = getenv("HOME");
1645 if (home == NULL) {
1646 snprintf(new_path, len - 1, "%s", path);
1647 } else {
1648 snprintf(new_path, len - 1, "%s%s", home, &path[1]);
1649 }
1650 } else {
1651 snprintf(new_path, len - 1, "%s", path);
1652 }
1653 #endif
1654
1655 new_path[len - 1] = 0;
1656 return new_path;
1657 }
1658
1659
1660
1661 /*
1662 * Command
1663 */
1664
fluid_cmd_copy(fluid_cmd_t * cmd)1665 fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd)
1666 {
1667 fluid_cmd_t* copy = FLUID_NEW(fluid_cmd_t);
1668 if (copy == NULL) {
1669 FLUID_LOG (FLUID_PANIC, "Out of memory");
1670 return NULL;
1671 }
1672
1673 copy->name = FLUID_STRDUP(cmd->name);
1674 copy->topic = FLUID_STRDUP(cmd->topic);
1675 copy->help = FLUID_STRDUP(cmd->help);
1676 copy->handler = cmd->handler;
1677 copy->data = cmd->data;
1678 return copy;
1679 }
1680
delete_fluid_cmd(fluid_cmd_t * cmd)1681 void delete_fluid_cmd(fluid_cmd_t* cmd)
1682 {
1683 if (cmd->name) {
1684 FLUID_FREE(cmd->name);
1685 }
1686 if (cmd->topic) {
1687 FLUID_FREE(cmd->topic);
1688 }
1689 if (cmd->help) {
1690 FLUID_FREE(cmd->help);
1691 }
1692 FLUID_FREE(cmd);
1693 }
1694
1695 /*
1696 * Command handler
1697 */
1698
1699 static void
fluid_cmd_handler_destroy_hash_value(void * value)1700 fluid_cmd_handler_destroy_hash_value (void *value)
1701 {
1702 delete_fluid_cmd ((fluid_cmd_t *)value);
1703 }
1704
1705 /**
1706 * Create a new command handler.
1707 * @param synth If not NULL, all the default synthesizer commands will be
1708 * added to the new handler.
1709 * @return New command handler
1710 */
1711 fluid_cmd_handler_t *
new_fluid_cmd_handler(fluid_synth_t * synth)1712 new_fluid_cmd_handler(fluid_synth_t* synth)
1713 {
1714 int i;
1715 fluid_cmd_handler_t* handler;
1716
1717 fluid_cmd_t source = {
1718 "source", "general", (fluid_cmd_func_t) fluid_handle_source, NULL,
1719 "source filename Load a file and parse every line as a command"
1720 };
1721
1722 handler = new_fluid_hashtable_full (fluid_str_hash, fluid_str_equal,
1723 NULL, fluid_cmd_handler_destroy_hash_value);
1724 if (handler == NULL) {
1725 return NULL;
1726 }
1727
1728 if (synth != NULL) {
1729 for (i = 0; fluid_commands[i].name != NULL; i++) {
1730 fluid_commands[i].data = synth;
1731 fluid_cmd_handler_register(handler, &fluid_commands[i]);
1732 fluid_commands[i].data = NULL;
1733 }
1734 }
1735
1736 source.data = handler;
1737 fluid_cmd_handler_register(handler, &source);
1738
1739 return handler;
1740 }
1741
1742 /**
1743 * Delete a command handler.
1744 * @param handler Command handler to delete
1745 */
1746 void
delete_fluid_cmd_handler(fluid_cmd_handler_t * handler)1747 delete_fluid_cmd_handler(fluid_cmd_handler_t* handler)
1748 {
1749 delete_fluid_hashtable (handler);
1750 }
1751
1752 /**
1753 * Register a new command to the handler.
1754 * @param handler Command handler instance
1755 * @param cmd Command info (gets copied)
1756 * @return #FLUID_OK if command was inserted, #FLUID_FAILED otherwise
1757 */
1758 int
fluid_cmd_handler_register(fluid_cmd_handler_t * handler,fluid_cmd_t * cmd)1759 fluid_cmd_handler_register(fluid_cmd_handler_t* handler, fluid_cmd_t* cmd)
1760 {
1761 fluid_cmd_t* copy = fluid_cmd_copy(cmd);
1762 fluid_hashtable_insert(handler, copy->name, copy);
1763 return FLUID_OK;
1764 }
1765
1766 /**
1767 * Unregister a command from a command handler.
1768 * @param handler Command handler instance
1769 * @param cmd Name of the command
1770 * @return TRUE if command was found and unregistered, FALSE otherwise
1771 */
1772 int
fluid_cmd_handler_unregister(fluid_cmd_handler_t * handler,const char * cmd)1773 fluid_cmd_handler_unregister(fluid_cmd_handler_t* handler, const char *cmd)
1774 {
1775 return fluid_hashtable_remove(handler, cmd);
1776 }
1777
1778 int
fluid_cmd_handler_handle(fluid_cmd_handler_t * handler,int ac,char ** av,fluid_ostream_t out)1779 fluid_cmd_handler_handle(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
1780 {
1781 fluid_cmd_t* cmd;
1782
1783 cmd = fluid_hashtable_lookup(handler, av[0]);
1784
1785 if (cmd && cmd->handler)
1786 return (*cmd->handler)(cmd->data, ac - 1, av + 1, out);
1787
1788 fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
1789 return -1;
1790 }
1791
1792
1793 #if !defined(WITHOUT_SERVER)
1794
1795
1796
1797 struct _fluid_server_t {
1798 fluid_server_socket_t* socket;
1799 fluid_settings_t* settings;
1800 fluid_server_newclient_func_t newclient;
1801 void* data;
1802 fluid_list_t* clients;
1803 fluid_mutex_t mutex;
1804 };
1805
1806 static void fluid_server_handle_connection(fluid_server_t* server,
1807 fluid_socket_t client_socket,
1808 char* addr);
1809 static void fluid_server_close(fluid_server_t* server);
1810
1811 /**
1812 * Create a new TCP/IP command shell server.
1813 * @param settings Settings instance to use for the shell
1814 * @param newclient Callback function to call for each new client connection
1815 * @param data User defined data to pass to \a newclient callback
1816 * @return New shell server instance or NULL on error
1817 */
1818 fluid_server_t*
new_fluid_server(fluid_settings_t * settings,fluid_server_newclient_func_t newclient,void * data)1819 new_fluid_server(fluid_settings_t* settings,
1820 fluid_server_newclient_func_t newclient,
1821 void* data)
1822 {
1823 fluid_server_t* server;
1824 int port;
1825
1826 server = FLUID_NEW(fluid_server_t);
1827 if (server == NULL) {
1828 FLUID_LOG(FLUID_ERR, "Out of memory");
1829 return NULL;
1830 }
1831
1832 server->settings = settings;
1833 server->clients = NULL;
1834 server->newclient = newclient;
1835 server->data = data;
1836
1837 fluid_mutex_init(server->mutex);
1838
1839 fluid_settings_getint(settings, "shell.port", &port);
1840
1841 server->socket = new_fluid_server_socket(port,
1842 (fluid_server_func_t) fluid_server_handle_connection,
1843 server);
1844 if (server->socket == NULL) {
1845 FLUID_FREE(server);
1846 return NULL;
1847 }
1848
1849 return server;
1850 }
1851
1852 /**
1853 * Delete a TCP/IP shell server.
1854 * @param server Shell server instance
1855 */
1856 void
delete_fluid_server(fluid_server_t * server)1857 delete_fluid_server(fluid_server_t* server)
1858 {
1859 if (server == NULL) {
1860 return;
1861 }
1862
1863 fluid_server_close(server);
1864
1865 FLUID_FREE(server);
1866 }
1867
fluid_server_close(fluid_server_t * server)1868 static void fluid_server_close(fluid_server_t* server)
1869 {
1870 fluid_list_t* list;
1871 fluid_list_t* clients;
1872 fluid_client_t* client;
1873
1874 if (server == NULL) {
1875 return;
1876 }
1877
1878 fluid_mutex_lock(server->mutex);
1879 clients = server->clients;
1880 server->clients = NULL;
1881 fluid_mutex_unlock(server->mutex);
1882
1883 list = clients;
1884
1885 while (list) {
1886 client = fluid_list_get(list);
1887 fluid_client_quit(client);
1888 list = fluid_list_next(list);
1889 }
1890
1891 delete_fluid_list(clients);
1892
1893 if (server->socket) {
1894 delete_fluid_server_socket(server->socket);
1895 server->socket = NULL;
1896 }
1897 }
1898
1899 static void
fluid_server_handle_connection(fluid_server_t * server,fluid_socket_t client_socket,char * addr)1900 fluid_server_handle_connection(fluid_server_t* server, fluid_socket_t client_socket, char* addr)
1901 {
1902 fluid_client_t* client;
1903 fluid_cmd_handler_t* handler;
1904
1905 handler = server->newclient(server->data, addr);
1906 if (handler == NULL) {
1907 return;
1908 }
1909
1910 client = new_fluid_client(server, server->settings, handler, client_socket);
1911 if (client == NULL) {
1912 return;
1913 }
1914 fluid_server_add_client(server, client);
1915 }
1916
fluid_server_add_client(fluid_server_t * server,fluid_client_t * client)1917 void fluid_server_add_client(fluid_server_t* server, fluid_client_t* client)
1918 {
1919 fluid_mutex_lock(server->mutex);
1920 server->clients = fluid_list_append(server->clients, client);
1921 fluid_mutex_unlock(server->mutex);
1922 }
1923
fluid_server_remove_client(fluid_server_t * server,fluid_client_t * client)1924 void fluid_server_remove_client(fluid_server_t* server, fluid_client_t* client)
1925 {
1926 fluid_mutex_lock(server->mutex);
1927 server->clients = fluid_list_remove(server->clients, client);
1928 fluid_mutex_unlock(server->mutex);
1929 }
1930
1931 /**
1932 * Join a shell server thread (wait until it quits).
1933 * @param server Shell server instance
1934 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
1935 */
fluid_server_join(fluid_server_t * server)1936 int fluid_server_join(fluid_server_t* server)
1937 {
1938 return fluid_server_socket_join(server->socket);
1939 }
1940
1941
1942
1943
1944 struct _fluid_client_t {
1945 fluid_server_t* server;
1946 fluid_settings_t* settings;
1947 fluid_cmd_handler_t* handler;
1948 fluid_socket_t socket;
1949 fluid_thread_t* thread;
1950 };
1951
1952
1953
fluid_client_run(fluid_client_t * client)1954 static void fluid_client_run(fluid_client_t* client)
1955 {
1956 fluid_shell_t shell;
1957 fluid_shell_init(&shell,
1958 client->settings,
1959 client->handler,
1960 fluid_socket_get_istream(client->socket),
1961 fluid_socket_get_ostream(client->socket));
1962 fluid_shell_run(&shell);
1963 fluid_server_remove_client(client->server, client);
1964 delete_fluid_client(client);
1965 }
1966
1967
1968 fluid_client_t*
new_fluid_client(fluid_server_t * server,fluid_settings_t * settings,fluid_cmd_handler_t * handler,fluid_socket_t sock)1969 new_fluid_client(fluid_server_t* server, fluid_settings_t* settings,
1970 fluid_cmd_handler_t* handler, fluid_socket_t sock)
1971 {
1972 fluid_client_t* client;
1973
1974 client = FLUID_NEW(fluid_client_t);
1975 if (client == NULL) {
1976 FLUID_LOG(FLUID_ERR, "Out of memory");
1977 return NULL;
1978 }
1979
1980 client->server = server;
1981 client->socket = sock;
1982 client->settings = settings;
1983 client->handler = handler;
1984
1985 client->thread = new_fluid_thread((fluid_thread_func_t) fluid_client_run, client,
1986 0, FALSE);
1987
1988 if (client->thread == NULL) {
1989 fluid_socket_close(sock);
1990 FLUID_FREE(client);
1991 return NULL;
1992 }
1993
1994 return client;
1995 }
1996
fluid_client_quit(fluid_client_t * client)1997 void fluid_client_quit(fluid_client_t* client)
1998 {
1999 if (client->socket != INVALID_SOCKET) {
2000 fluid_socket_close(client->socket);
2001 client->socket = INVALID_SOCKET;
2002 }
2003 FLUID_LOG(FLUID_DBG, "fluid_client_quit: joining");
2004 fluid_thread_join(client->thread);
2005 FLUID_LOG(FLUID_DBG, "fluid_client_quit: done");
2006 }
2007
delete_fluid_client(fluid_client_t * client)2008 void delete_fluid_client(fluid_client_t* client)
2009 {
2010 if (client->socket != INVALID_SOCKET) {
2011 fluid_socket_close(client->socket);
2012 client->socket = INVALID_SOCKET;
2013 }
2014 if (client->thread != NULL) {
2015 delete_fluid_thread(client->thread);
2016 client->thread = NULL;
2017 }
2018 FLUID_FREE(client);
2019 }
2020
2021
2022 #endif /* WITHOUT_SERVER */
2023