1 /* FluidSynth - A Software Synthesizer
2 *
3 * Copyright (C) 2003 Peter Hanappe and others.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 */
20
21 #include "fluid_cmd.h"
22 #include "fluid_synth.h"
23 #include "fluid_settings.h"
24 #include "fluid_hash.h"
25 #include "fluid_midi_router.h"
26 #include "fluid_sfont.h"
27 #include "fluid_chan.h"
28
29 /* FIXME: LADSPA used to need a lot of parameters on a single line. This is not
30 * necessary anymore, so the limits below could probably be reduced */
31 #define MAX_TOKENS 100
32 #define MAX_COMMAND_LEN 1024 /* max command length accepted by fluid_command() */
33 #define FLUID_WORKLINELENGTH 1024
34
35 #define FLUID_ENTRY_COMMAND(data) fluid_cmd_handler_t* handler=(fluid_cmd_handler_t*)(data)
36
37 /* the shell cmd handler struct */
38 struct _fluid_cmd_handler_t
39 {
40 fluid_settings_t *settings;
41 fluid_synth_t *synth;
42 fluid_midi_router_t *router;
43 fluid_player_t *player;
44 fluid_cmd_hash_t *commands;
45
46 fluid_midi_router_rule_t *cmd_rule; /* Rule currently being processed by shell command handler */
47 int cmd_rule_type; /* Type of the rule (#fluid_midi_router_rule_type) */
48 };
49
50
51 struct _fluid_shell_t
52 {
53 fluid_settings_t *settings;
54 fluid_cmd_handler_t *handler;
55 fluid_thread_t *thread;
56 fluid_istream_t in;
57 fluid_ostream_t out;
58 };
59
60
61 static fluid_thread_return_t fluid_shell_run(void *data);
62 static void fluid_shell_init(fluid_shell_t *shell,
63 fluid_settings_t *settings, fluid_cmd_handler_t *handler,
64 fluid_istream_t in, fluid_ostream_t out);
65 static int fluid_handle_voice_count(void *data, int ac, char **av,
66 fluid_ostream_t out);
67
fluid_shell_settings(fluid_settings_t * settings)68 void fluid_shell_settings(fluid_settings_t *settings)
69 {
70 fluid_settings_register_str(settings, "shell.prompt", "", 0);
71 fluid_settings_register_int(settings, "shell.port", 9800, 1, 65535, 0);
72 }
73
74
75 /** the table of all handled commands */
76
77 static const fluid_cmd_t fluid_commands[] =
78 {
79 /* general commands */
80 {
81 "help", "general", fluid_handle_help,
82 "help Shows help topics ('help TOPIC' for more info)"
83 },
84 {
85 "quit", "general", fluid_handle_quit,
86 "quit Quit the synthesizer"
87 },
88 {
89 "source", "general", fluid_handle_source,
90 "source filename Loads a file and parse every line as a command"
91 },
92 /* event commands */
93 {
94 "noteon", "event", fluid_handle_noteon,
95 "noteon chan key vel Sends noteon"
96 },
97 {
98 "noteoff", "event", fluid_handle_noteoff,
99 "noteoff chan key Sends noteoff"
100 },
101 {
102 "pitch_bend", "event", fluid_handle_pitch_bend,
103 "pitch_bend chan offset Bends pitch"
104 },
105 {
106 "pitch_bend_range", "event", fluid_handle_pitch_bend_range,
107 "pitch_bend_range chn range Sets pitch bend range for the given midi channel"
108 },
109 {
110 "cc", "event", fluid_handle_cc,
111 "cc chan ctrl value Sends control-change message"
112 },
113 {
114 "prog", "event", fluid_handle_prog,
115 "prog chan num Sends program-change message"
116 },
117 {
118 "select", "event", fluid_handle_select,
119 "select chan sfont bank prog Combination of bank-select and program-change"
120 },
121 {
122 "load", "general", fluid_handle_load,
123 "load file [reset] [bankofs] Loads SoundFont (reset=0|1, def 1; bankofs=n, def 0)"
124 },
125 {
126 "unload", "general", fluid_handle_unload,
127 "unload id [reset] Unloads SoundFont by ID (reset=0|1, default 1)"
128 },
129 {
130 "reload", "general", fluid_handle_reload,
131 "reload id Reload the SoundFont with the specified ID"
132 },
133 {
134 "fonts", "general", fluid_handle_fonts,
135 "fonts Display the list of loaded SoundFonts"
136 },
137 {
138 "inst", "general", fluid_handle_inst,
139 "inst font Print out the available instruments for the font"
140 },
141 {
142 "channels", "general", fluid_handle_channels,
143 "channels [-verbose] Print out preset of all channels"
144 },
145 {
146 "interp", "general", fluid_handle_interp,
147 "interp num Choose interpolation method for all channels"
148 },
149 {
150 "interpc", "general", fluid_handle_interpc,
151 "interpc chan num Choose interpolation method for one channel"
152 },
153 /* polymono commands */
154 {
155 "basicchannels", "polymono", fluid_handle_basicchannels,
156 "basicchannels Prints the list of basic channels"
157 },
158 {
159 "resetbasicchannels", "polymono", fluid_handle_resetbasicchannels,
160 "resetbasicchannels [chan1 chan2..] Resets all or some basic channels"
161 },
162 {
163 "setbasicchannels", "polymono", fluid_handle_setbasicchannels,
164 "setbasicchannels [chan mode val...] Sets default, adds basic channels"
165 },
166 {
167 "channelsmode", "polymono", fluid_handle_channelsmode,
168 "channelsmode [chan1 chan2..] Prints channels mode"
169 },
170 {
171 "legatomode", "polymono", fluid_handle_legatomode,
172 "legatomode [chan1 chan2..] Prints channels legato mode"
173 },
174 {
175 "setlegatomode", "polymono", fluid_handle_setlegatomode,
176 "setlegatomode chan mode [chan mode..] Sets legato mode"
177 },
178 {
179 "portamentomode", "polymono", fluid_handle_portamentomode,
180 "portamentomode [chan1 chan2..] Prints channels portamento mode"
181 },
182 {
183 "setportamentomode", "polymono", fluid_handle_setportamentomode,
184 "setportamentomode chan mode [chan mode..] Sets portamento mode"
185 },
186 {
187 "breathmode", "polymono", fluid_handle_breathmode,
188 "breathmode [chan1 chan2..] Prints channels breath mode"
189 },
190 {
191 "setbreathmode", "polymono", fluid_handle_setbreathmode,
192 "setbreathmode chan poly(1/0) mono(1/0) breath_sync(1/0) [..] Sets breath mode"
193 },
194 /* reverb commands */
195 {
196 "rev_preset", "reverb", fluid_handle_reverbpreset,
197 "rev_preset num Load preset num into all reverb unit"
198 },
199 {
200 "rev_setroomsize", "reverb", fluid_handle_reverbsetroomsize,
201 "rev_setroomsize [group] num Set room size of all or one reverb group to num"
202 },
203 {
204 "rev_setdamp", "reverb", fluid_handle_reverbsetdamp,
205 "rev_setdamp [group] num Set damping of all or one reverb group to num"
206 },
207 {
208 "rev_setwidth", "reverb", fluid_handle_reverbsetwidth,
209 "rev_setwidth [group] num Set width of all or one reverb group to num"
210 },
211 {
212 "rev_setlevel", "reverb", fluid_handle_reverbsetlevel,
213 "rev_setlevel [group] num Set output level of all or one reverb group to num"
214 },
215 {
216 "reverb", "reverb", fluid_handle_reverb,
217 "reverb [group] 0|1|on|off Turn all or one reverb group on or off"
218 },
219 /* chorus commands */
220 {
221 "cho_set_nr", "chorus", fluid_handle_chorusnr,
222 "cho_set_nr [group] n Set n delay lines (default 3) in all or one chorus group"
223 },
224 {
225 "cho_set_level", "chorus", fluid_handle_choruslevel,
226 "cho_set_level [group] num Set output level of all or one chorus group to num"
227 },
228 {
229 "cho_set_speed", "chorus", fluid_handle_chorusspeed,
230 "cho_set_speed [group] num Set mod speed of all or one chorus group to num (Hz)"
231 },
232 {
233 "cho_set_depth", "chorus", fluid_handle_chorusdepth,
234 "cho_set_depth [group] num Set modulation depth of all or one chorus group to num (ms)"
235 },
236 {
237 "chorus", "chorus", fluid_handle_chorus,
238 "chorus [group] 0|1|on|off Turn all or one chorus group on or off"
239 },
240 {
241 "gain", "general", fluid_handle_gain,
242 "gain value Set the master gain (0 < gain < 5)"
243 },
244 {
245 "voice_count", "general", fluid_handle_voice_count,
246 "voice_count Get number of active synthesis voices"
247 },
248 /* tuning commands */
249 {
250 "tuning", "tuning", fluid_handle_tuning,
251 "tuning name bank prog Create a tuning with name, bank number, \n"
252 " and program number (0 <= bank,prog <= 127)"
253 },
254 {
255 "tune", "tuning", fluid_handle_tune,
256 "tune bank prog key pitch Tune a key"
257 },
258 {
259 "settuning", "tuning", fluid_handle_settuning,
260 "settuning chan bank prog Set the tuning for a MIDI channel"
261 },
262 {
263 "resettuning", "tuning", fluid_handle_resettuning,
264 "resettuning chan Restore the default tuning of a MIDI channel"
265 },
266 {
267 "tunings", "tuning", fluid_handle_tunings,
268 "tunings Print the list of available tunings"
269 },
270 {
271 "dumptuning", "tuning", fluid_handle_dumptuning,
272 "dumptuning bank prog Print the pitch details of the tuning"
273 },
274 {
275 "reset", "general", fluid_handle_reset,
276 "reset System reset (all notes off, reset controllers)"
277 },
278 /* settings commands */
279 {
280 "set", "settings", fluid_handle_set,
281 "set name value Set the value of a setting (must be a real-time setting to take effect immediately)"
282 },
283 {
284 "get", "settings", fluid_handle_get,
285 "get name Get the value of a setting"
286 },
287 {
288 "info", "settings", fluid_handle_info,
289 "info name Get information about a setting"
290 },
291 {
292 "settings", "settings", fluid_handle_settings,
293 "settings Print out all settings"
294 },
295 {
296 "echo", "general", fluid_handle_echo,
297 "echo arg Print arg"
298 },
299 /* Sleep command, useful to insert a delay between commands */
300 {
301 "sleep", "general", fluid_handle_sleep,
302 "sleep duration sleep duration (in ms)"
303 },
304 /* LADSPA-related commands */
305 #ifdef LADSPA
306 {
307 "ladspa_effect", "ladspa", fluid_handle_ladspa_effect,
308 "ladspa_effect Create a new effect from a LADSPA plugin"
309 },
310 {
311 "ladspa_link", "ladspa", fluid_handle_ladspa_link,
312 "ladspa_link Connect an effect port to a host port or buffer"
313 },
314 {
315 "ladspa_buffer", "ladspa", fluid_handle_ladspa_buffer,
316 "ladspa_buffer Create a LADSPA buffer"
317 },
318 {
319 "ladspa_set", "ladspa", fluid_handle_ladspa_set,
320 "ladspa_set Set the value of an effect control port"
321 },
322 {
323 "ladspa_check", "ladspa", fluid_handle_ladspa_check,
324 "ladspa_check Check LADSPA configuration"
325 },
326 {
327 "ladspa_start", "ladspa", fluid_handle_ladspa_start,
328 "ladspa_start Start LADSPA effects"
329 },
330 {
331 "ladspa_stop", "ladspa", fluid_handle_ladspa_stop,
332 "ladspa_stop Stop LADSPA effect unit"
333 },
334 {
335 "ladspa_reset", "ladspa", fluid_handle_ladspa_reset,
336 "ladspa_reset Stop and reset LADSPA effects"
337 },
338 #endif
339 /* router commands */
340 {
341 "router_clear", "router", fluid_handle_router_clear,
342 "router_clear Clears all routing rules from the midi router"
343 },
344 {
345 "router_default", "router", fluid_handle_router_default,
346 "router_default Resets the midi router to default state"
347 },
348 {
349 "router_begin", "router", fluid_handle_router_begin,
350 "router_begin [note|cc|prog|pbend|cpress|kpress]: Starts a new routing rule"
351 },
352 {
353 "router_chan", "router", fluid_handle_router_chan,
354 "router_chan min max mul add filters and maps midi channels on current rule"
355 },
356 {
357 "router_par1", "router", fluid_handle_router_par1,
358 "router_par1 min max mul add filters and maps parameter 1 (key/ctrl nr)"
359 },
360 {
361 "router_par2", "router", fluid_handle_router_par2,
362 "router_par2 min max mul add filters and maps parameter 2 (vel/cc val)"
363 },
364 {
365 "router_end", "router", fluid_handle_router_end,
366 "router_end closes and commits the current routing rule"
367 },
368 /* Midi file player commands */
369 {
370 "player_start", "player", fluid_handle_player_start,
371 "player_start Start playing from the beginning of current song"
372 },
373 {
374 "player_stop", "player", fluid_handle_player_stop,
375 "player_stop Stop playing (cannot be executed in a user command file)"
376 },
377 {
378 "player_cont", "player", fluid_handle_player_continue,
379 "player_cont Continue playing (cannot be executed in a user command file)"
380 },
381 {
382 "player_seek", "player", fluid_handle_player_seek,
383 "player_seek num Move forward/backward in current song to +/-num ticks"
384 },
385 {
386 "player_next", "player", fluid_handle_player_next_song,
387 "player_next Move to next song (cannot be executed in a user command file)"
388 },
389 {
390 "player_loop", "player", fluid_handle_player_loop,
391 "player_loop num Set loop number to num (-1 = loop forever)"
392 },
393 {
394 "player_tempo_bpm", "player", fluid_handle_player_tempo_bpm,
395 "player_tempo_bpm num Set tempo to num beats per minute"
396 },
397 {
398 "player_tempo_int", "player", fluid_handle_player_tempo_int,
399 "player_tempo_int [mul] Set internal tempo multiplied by mul (default mul=1.0)"
400 },
401 #if WITH_PROFILING
402 /* Profiling commands */
403 {
404 "profile", "profile", fluid_handle_profile,
405 "profile Prints default parameters used by prof_start"
406 },
407 {
408 "prof_set_notes", "profile", fluid_handle_prof_set_notes,
409 "prof_set_notes nbr [bank prog] Sets notes number generated by prof_start"
410 },
411 {
412 "prof_set_print", "profile", fluid_handle_prof_set_print,
413 "prof_set_print mode Sets print mode (0:simple, 1:full infos)"
414 },
415 {
416 "prof_start", "profile", fluid_handle_prof_start,
417 "prof_start [n_prof [dur]] Starts n_prof measures of duration(ms) each"
418 }
419 #endif
420 };
421
422 /**
423 * Process a string command.
424 *
425 * @param handler FluidSynth command handler
426 * @param cmd Command string (NOTE: Gets modified by FluidSynth prior to 1.0.8)
427 * @param out Output stream to display command response to
428 * @return Integer value corresponding to: -1 on command error, 0 on success,
429 * 1 if 'cmd' is a comment or is empty and -2 if quit was issued
430 *
431 * @note FluidSynth 1.0.8 and above no longer modifies the 'cmd' string.
432 */
433 int
fluid_command(fluid_cmd_handler_t * handler,const char * cmd,fluid_ostream_t out)434 fluid_command(fluid_cmd_handler_t *handler, const char *cmd, fluid_ostream_t out)
435 {
436 int result, num_tokens = 0;
437 char **tokens = NULL;
438
439 if(cmd[0] == '#' || cmd[0] == '\0')
440 {
441 return 1;
442 }
443
444 if(!g_shell_parse_argv(cmd, &num_tokens, &tokens, NULL))
445 {
446 fluid_ostream_printf(out, "Error parsing command\n");
447 return FLUID_FAILED;
448 }
449
450 result = fluid_cmd_handler_handle(handler, num_tokens, &tokens[0], out);
451 g_strfreev(tokens);
452
453 return result;
454 }
455
456 /**
457 * Create a new FluidSynth command shell.
458 *
459 * @param settings Setting parameters to use with the shell
460 * @param handler Command handler
461 * @param in Input stream
462 * @param out Output stream
463 * @param thread TRUE if shell should be run in a separate thread, FALSE to run
464 * it in the current thread (function blocks until "quit")
465 * @return New shell instance or NULL on error
466 */
467 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)468 new_fluid_shell(fluid_settings_t *settings, fluid_cmd_handler_t *handler,
469 fluid_istream_t in, fluid_ostream_t out, int thread)
470 {
471 fluid_shell_t *shell = FLUID_NEW(fluid_shell_t);
472
473 if(shell == NULL)
474 {
475 FLUID_LOG(FLUID_PANIC, "Out of memory");
476 return NULL;
477 }
478
479
480 fluid_shell_init(shell, settings, handler, in, out);
481
482 if(thread)
483 {
484 shell->thread = new_fluid_thread("shell", fluid_shell_run, shell,
485 0, TRUE);
486
487 if(shell->thread == NULL)
488 {
489 delete_fluid_shell(shell);
490 return NULL;
491 }
492 }
493 else
494 {
495 shell->thread = NULL;
496 fluid_shell_run(shell);
497 }
498
499 return shell;
500 }
501
502 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)503 fluid_shell_init(fluid_shell_t *shell,
504 fluid_settings_t *settings, fluid_cmd_handler_t *handler,
505 fluid_istream_t in, fluid_ostream_t out)
506 {
507 shell->settings = settings;
508 shell->handler = handler;
509 shell->in = in;
510 shell->out = out;
511 }
512
513 /**
514 * Delete a FluidSynth command shell.
515 * @param shell Command shell instance
516 */
517 void
delete_fluid_shell(fluid_shell_t * shell)518 delete_fluid_shell(fluid_shell_t *shell)
519 {
520 fluid_return_if_fail(shell != NULL);
521
522 if(shell->thread != NULL)
523 {
524 delete_fluid_thread(shell->thread);
525 }
526
527 FLUID_FREE(shell);
528 }
529
530 static fluid_thread_return_t
fluid_shell_run(void * data)531 fluid_shell_run(void *data)
532 {
533 fluid_shell_t *shell = (fluid_shell_t *)data;
534 char workline[FLUID_WORKLINELENGTH];
535 char *prompt = NULL;
536 int cont = 1;
537 int errors = FALSE;
538 int n;
539
540 if(shell->settings)
541 {
542 fluid_settings_dupstr(shell->settings, "shell.prompt", &prompt); /* ++ alloc prompt */
543 }
544
545 /* handle user input */
546 while(cont)
547 {
548
549 n = fluid_istream_readline(shell->in, shell->out, prompt ? prompt : "", workline, FLUID_WORKLINELENGTH);
550
551 if(n < 0)
552 {
553 FLUID_LOG(FLUID_PANIC, "An error occurred while reading from stdin.");
554 break;
555 }
556
557 /* handle the command */
558 switch(fluid_command(shell->handler, workline, shell->out))
559 {
560
561 case 1: /* empty line or comment */
562 break;
563
564 case FLUID_FAILED: /* erroneous command */
565 errors = TRUE;
566
567 case FLUID_OK: /* valid command */
568 break;
569
570 case -2: /* quit */
571 cont = 0;
572 break;
573 }
574
575 if(n == 0)
576 {
577 if(shell->settings)
578 {
579 FLUID_LOG(FLUID_INFO, "Received EOF while reading commands, exiting the shell.");
580 }
581 break;
582 }
583 }
584
585 FLUID_FREE(prompt); /* -- free prompt */
586
587 /* return FLUID_THREAD_RETURN_VALUE on success, something else on failure */
588 return errors ? (fluid_thread_return_t)(-1) : FLUID_THREAD_RETURN_VALUE;
589 }
590
591 /**
592 * A convenience function to create a shell interfacing to standard input/output
593 * console streams.
594 *
595 * @param settings Settings instance for the shell
596 * @param handler Command handler callback
597 *
598 * The shell is run in the current thread, this function will only
599 * return after the \c quit command has been issued.
600 */
601 void
fluid_usershell(fluid_settings_t * settings,fluid_cmd_handler_t * handler)602 fluid_usershell(fluid_settings_t *settings, fluid_cmd_handler_t *handler)
603 {
604 fluid_shell_t shell;
605 fluid_shell_init(&shell, settings, handler, fluid_get_stdin(), fluid_get_stdout());
606 fluid_shell_run(&shell);
607 }
608
609 /**
610 * Execute shell commands in a file.
611 *
612 * @param handler Command handler callback
613 * @param filename File name
614 * @return 0 on success, a negative value on error
615 */
616 int
fluid_source(fluid_cmd_handler_t * handler,const char * filename)617 fluid_source(fluid_cmd_handler_t *handler, const char *filename)
618 {
619 int file;
620 fluid_shell_t shell;
621 int result;
622
623 #ifdef WIN32
624 file = _open(filename, _O_RDONLY);
625 #else
626 file = open(filename, O_RDONLY);
627 #endif
628
629 if(file < 0)
630 {
631 return file;
632 }
633
634 fluid_shell_init(&shell, NULL, handler, file, fluid_get_stdout());
635 result = (fluid_shell_run(&shell) == FLUID_THREAD_RETURN_VALUE) ? 0 : -1;
636
637 #ifdef WIN32
638 _close(file);
639 #else
640 close(file);
641 #endif
642
643 return result;
644 }
645
646 /**
647 * Get the user specific FluidSynth command file name.
648 *
649 * @param buf Caller supplied string buffer to store file name to.
650 * @param len Length of \a buf
651 * @return Returns \a buf pointer or NULL if no user command file for this system type.
652 *
653 * On Windows this is currently @c "%USERPROFILE%\fluidsynth.cfg".
654 * For anything else (except MACOS9) @c "$HOME/.fluidsynth".
655 */
656 char *
fluid_get_userconf(char * buf,int len)657 fluid_get_userconf(char *buf, int len)
658 {
659 const char *home = NULL;
660 const char *config_file;
661 #if defined(WIN32)
662 home = getenv("USERPROFILE");
663 config_file = "\\fluidsynth.cfg";
664
665 #elif !defined(MACOS9)
666 home = getenv("HOME");
667 config_file = "/.fluidsynth";
668
669 #endif
670
671 if(home == NULL)
672 {
673 return NULL;
674 }
675 else
676 {
677 FLUID_SNPRINTF(buf, len, "%s%s", home, config_file);
678 return buf;
679 }
680 }
681
682 /**
683 * Get the system FluidSynth command file name.
684 *
685 * @param buf Caller supplied string buffer to store file name to.
686 * @param len Length of \a buf
687 * @return Returns \a buf pointer or NULL if no system command file for this system type.
688 *
689 * Windows and MACOS9 do not have a system-wide config file currently. For anything else it
690 * returns @c "/etc/fluidsynth.conf".
691 */
692 char *
fluid_get_sysconf(char * buf,int len)693 fluid_get_sysconf(char *buf, int len)
694 {
695 #if defined(WIN32) || defined(MACOS9)
696 return NULL;
697 #else
698 FLUID_SNPRINTF(buf, len, "/etc/fluidsynth.conf");
699 return buf;
700 #endif
701 }
702
703
704 /*
705 * handlers
706 */
707 int
fluid_handle_noteon(void * data,int ac,char ** av,fluid_ostream_t out)708 fluid_handle_noteon(void *data, int ac, char **av, fluid_ostream_t out)
709 {
710 FLUID_ENTRY_COMMAND(data);
711
712 if(ac < 3)
713 {
714 fluid_ostream_printf(out, "noteon: too few arguments\n");
715 return FLUID_FAILED;
716 }
717
718 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1]) || !fluid_is_number(av[2]))
719 {
720 fluid_ostream_printf(out, "noteon: invalid argument\n");
721 return FLUID_FAILED;
722 }
723
724 return fluid_synth_noteon(handler->synth, atoi(av[0]), atoi(av[1]), atoi(av[2]));
725 }
726
727 int
fluid_handle_noteoff(void * data,int ac,char ** av,fluid_ostream_t out)728 fluid_handle_noteoff(void *data, int ac, char **av, fluid_ostream_t out)
729 {
730 FLUID_ENTRY_COMMAND(data);
731
732 if(ac < 2)
733 {
734 fluid_ostream_printf(out, "noteoff: too few arguments\n");
735 return FLUID_FAILED;
736 }
737
738 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1]))
739 {
740 fluid_ostream_printf(out, "noteon: invalid argument\n");
741 return FLUID_FAILED;
742 }
743
744 return fluid_synth_noteoff(handler->synth, atoi(av[0]), atoi(av[1]));
745 }
746
747 int
fluid_handle_pitch_bend(void * data,int ac,char ** av,fluid_ostream_t out)748 fluid_handle_pitch_bend(void *data, int ac, char **av, fluid_ostream_t out)
749 {
750 FLUID_ENTRY_COMMAND(data);
751
752 if(ac < 2)
753 {
754 fluid_ostream_printf(out, "pitch_bend: too few arguments\n");
755 return FLUID_FAILED;
756 }
757
758 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1]))
759 {
760 fluid_ostream_printf(out, "pitch_bend: invalid argument\n");
761 return FLUID_FAILED;
762 }
763
764 return fluid_synth_pitch_bend(handler->synth, atoi(av[0]), atoi(av[1]));
765 }
766
767 int
fluid_handle_pitch_bend_range(void * data,int ac,char ** av,fluid_ostream_t out)768 fluid_handle_pitch_bend_range(void *data, int ac, char **av, fluid_ostream_t out)
769 {
770 FLUID_ENTRY_COMMAND(data);
771 int channum;
772 int value;
773
774 if(ac < 2)
775 {
776 fluid_ostream_printf(out, "pitch_bend_range: too few arguments\n");
777 return FLUID_FAILED;
778 }
779
780 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1]))
781 {
782 fluid_ostream_printf(out, "pitch_bend_range: invalid argument\n");
783 return FLUID_FAILED;
784 }
785
786 channum = atoi(av[0]);
787 value = atoi(av[1]);
788 fluid_channel_set_pitch_wheel_sensitivity(handler->synth->channel[channum], value);
789 return FLUID_OK;
790 }
791
792 int
fluid_handle_cc(void * data,int ac,char ** av,fluid_ostream_t out)793 fluid_handle_cc(void *data, int ac, char **av, fluid_ostream_t out)
794 {
795 FLUID_ENTRY_COMMAND(data);
796
797 if(ac < 3)
798 {
799 fluid_ostream_printf(out, "cc: too few arguments\n");
800 return FLUID_FAILED;
801 }
802
803 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1]) || !fluid_is_number(av[2]))
804 {
805 fluid_ostream_printf(out, "cc: invalid argument\n");
806 return FLUID_FAILED;
807 }
808
809 return fluid_synth_cc(handler->synth, atoi(av[0]), atoi(av[1]), atoi(av[2]));
810 }
811
812 int
fluid_handle_prog(void * data,int ac,char ** av,fluid_ostream_t out)813 fluid_handle_prog(void *data, int ac, char **av, fluid_ostream_t out)
814 {
815 FLUID_ENTRY_COMMAND(data);
816
817 if(ac < 2)
818 {
819 fluid_ostream_printf(out, "prog: too few arguments\n");
820 return FLUID_FAILED;
821 }
822
823 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1]))
824 {
825 fluid_ostream_printf(out, "prog: invalid argument\n");
826 return FLUID_FAILED;
827 }
828
829 return fluid_synth_program_change(handler->synth, atoi(av[0]), atoi(av[1]));
830 }
831
832 int
fluid_handle_select(void * data,int ac,char ** av,fluid_ostream_t out)833 fluid_handle_select(void *data, int ac, char **av, fluid_ostream_t out)
834 {
835 FLUID_ENTRY_COMMAND(data);
836 int sfont_id;
837 int chan;
838 int bank;
839 int prog;
840
841 if(ac < 4)
842 {
843 fluid_ostream_printf(out, "preset: too few arguments\n");
844 return FLUID_FAILED;
845 }
846
847 if(!fluid_is_number(av[0]) || !fluid_is_number(av[1])
848 || !fluid_is_number(av[2]) || !fluid_is_number(av[3]))
849 {
850 fluid_ostream_printf(out, "preset: invalid argument\n");
851 return FLUID_FAILED;
852 }
853
854 chan = atoi(av[0]);
855 sfont_id = atoi(av[1]);
856 bank = atoi(av[2]);
857 prog = atoi(av[3]);
858
859 if(sfont_id != 0)
860 {
861 return fluid_synth_program_select(handler->synth, chan, sfont_id, bank, prog);
862 }
863 else
864 {
865 if(fluid_synth_bank_select(handler->synth, chan, bank) == FLUID_OK)
866 {
867 return fluid_synth_program_change(handler->synth, chan, prog);
868 }
869
870 return FLUID_FAILED;
871 }
872 }
873
874 int
fluid_handle_inst(void * data,int ac,char ** av,fluid_ostream_t out)875 fluid_handle_inst(void *data, int ac, char **av, fluid_ostream_t out)
876 {
877 FLUID_ENTRY_COMMAND(data);
878 int font;
879 fluid_sfont_t *sfont;
880 fluid_preset_t *preset;
881 int offset;
882
883 if(ac < 1)
884 {
885 fluid_ostream_printf(out, "inst: too few arguments\n");
886 return FLUID_FAILED;
887 }
888
889 if(!fluid_is_number(av[0]))
890 {
891 fluid_ostream_printf(out, "inst: invalid argument\n");
892 return FLUID_FAILED;
893 }
894
895 font = atoi(av[0]);
896
897 sfont = fluid_synth_get_sfont_by_id(handler->synth, font);
898 offset = fluid_synth_get_bank_offset(handler->synth, font);
899
900 if(sfont == NULL)
901 {
902 fluid_ostream_printf(out, "inst: invalid font number\n");
903 return FLUID_FAILED;
904 }
905
906 fluid_sfont_iteration_start(sfont);
907
908 while((preset = fluid_sfont_iteration_next(sfont)) != NULL)
909 {
910 fluid_ostream_printf(out, "%03d-%03d %s\n",
911 fluid_preset_get_banknum(preset) + offset,
912 fluid_preset_get_num(preset),
913 fluid_preset_get_name(preset));
914 }
915
916 return FLUID_OK;
917 }
918
919
920 int
fluid_handle_channels(void * data,int ac,char ** av,fluid_ostream_t out)921 fluid_handle_channels(void *data, int ac, char **av, fluid_ostream_t out)
922 {
923 FLUID_ENTRY_COMMAND(data);
924 fluid_preset_t *preset;
925 int verbose = 0;
926 int i;
927
928 if(ac > 0 && FLUID_STRCMP(av[0], "-verbose") == 0)
929 {
930 verbose = 1;
931 }
932
933 for(i = 0; i < fluid_synth_count_midi_channels(handler->synth); i++)
934 {
935 preset = fluid_synth_get_channel_preset(handler->synth, i);
936
937 if(preset == NULL)
938 {
939 fluid_ostream_printf(out, "chan %d, no preset\n", i);
940 }
941 else if(!verbose)
942 {
943 fluid_ostream_printf(out, "chan %d, %s\n", i, fluid_preset_get_name(preset));
944 }
945 else
946 {
947 fluid_ostream_printf(out,
948 "chan %d, sfont %d, bank %d, preset %d, %s\n",
949 i,
950 fluid_sfont_get_id(preset->sfont),
951 fluid_preset_get_banknum(preset),
952 fluid_preset_get_num(preset),
953 fluid_preset_get_name(preset));
954 }
955 }
956
957 return FLUID_OK;
958 }
959
960 int
fluid_handle_load(void * data,int ac,char ** av,fluid_ostream_t out)961 fluid_handle_load(void *data, int ac, char **av, fluid_ostream_t out)
962 {
963 FLUID_ENTRY_COMMAND(data);
964 char buf[1024];
965 int id;
966 int reset = 1;
967 int offset = 0;
968
969 if(ac < 1)
970 {
971 fluid_ostream_printf(out, "load: too few arguments\n");
972 return FLUID_FAILED;
973 }
974
975 if(ac == 2)
976 {
977 reset = atoi(av[1]);
978 }
979
980 if(ac == 3)
981 {
982 offset = atoi(av[2]);
983 }
984
985 /* Load the SoundFont without resetting the programs. The reset will
986 * be done later (if requested). */
987 id = fluid_synth_sfload(handler->synth, fluid_expand_path(av[0], buf, 1024), 0);
988
989 if(id == -1)
990 {
991 fluid_ostream_printf(out, "failed to load the SoundFont\n");
992 return FLUID_FAILED;
993 }
994 else
995 {
996 fluid_ostream_printf(out, "loaded SoundFont has ID %d\n", id);
997 }
998
999 if(offset)
1000 {
1001 fluid_synth_set_bank_offset(handler->synth, id, offset);
1002 }
1003
1004 /* The reset should be done after the offset is set. */
1005 if(reset)
1006 {
1007 fluid_synth_program_reset(handler->synth);
1008 }
1009
1010 return FLUID_OK;
1011 }
1012
1013 int
fluid_handle_unload(void * data,int ac,char ** av,fluid_ostream_t out)1014 fluid_handle_unload(void *data, int ac, char **av, fluid_ostream_t out)
1015 {
1016 FLUID_ENTRY_COMMAND(data);
1017 int reset = 1;
1018
1019 if(ac < 1)
1020 {
1021 fluid_ostream_printf(out, "unload: too few arguments\n");
1022 return FLUID_FAILED;
1023 }
1024
1025 if(!fluid_is_number(av[0]))
1026 {
1027 fluid_ostream_printf(out, "unload: expected a number as argument\n");
1028 return FLUID_FAILED;
1029 }
1030
1031 if(ac == 2)
1032 {
1033 reset = atoi(av[1]);
1034 }
1035
1036 if(fluid_synth_sfunload(handler->synth, atoi(av[0]), reset) != 0)
1037 {
1038 fluid_ostream_printf(out, "failed to unload the SoundFont\n");
1039 return FLUID_FAILED;
1040 }
1041
1042 return FLUID_OK;
1043 }
1044
1045 int
fluid_handle_reload(void * data,int ac,char ** av,fluid_ostream_t out)1046 fluid_handle_reload(void *data, int ac, char **av, fluid_ostream_t out)
1047 {
1048 FLUID_ENTRY_COMMAND(data);
1049
1050 if(ac < 1)
1051 {
1052 fluid_ostream_printf(out, "reload: too few arguments\n");
1053 return FLUID_FAILED;
1054 }
1055
1056 if(!fluid_is_number(av[0]))
1057 {
1058 fluid_ostream_printf(out, "reload: expected a number as argument\n");
1059 return FLUID_FAILED;
1060 }
1061
1062 if(fluid_synth_sfreload(handler->synth, atoi(av[0])) == -1)
1063 {
1064 fluid_ostream_printf(out, "failed to reload the SoundFont\n");
1065 return FLUID_FAILED;
1066 }
1067
1068 return FLUID_OK;
1069 }
1070
1071
1072 int
fluid_handle_fonts(void * data,int ac,char ** av,fluid_ostream_t out)1073 fluid_handle_fonts(void *data, int ac, char **av, fluid_ostream_t out)
1074 {
1075 FLUID_ENTRY_COMMAND(data);
1076 int i;
1077 fluid_sfont_t *sfont;
1078 int num;
1079
1080 num = fluid_synth_sfcount(handler->synth);
1081
1082 if(num == 0)
1083 {
1084 fluid_ostream_printf(out, "no SoundFont loaded (try load)\n");
1085 return FLUID_OK;
1086 }
1087
1088 fluid_ostream_printf(out, "ID Name\n");
1089
1090 for(i = 0; i < num; i++)
1091 {
1092 sfont = fluid_synth_get_sfont(handler->synth, i);
1093
1094 if(sfont)
1095 {
1096 fluid_ostream_printf(out, "%2d %s\n",
1097 fluid_sfont_get_id(sfont),
1098 fluid_sfont_get_name(sfont));
1099 }
1100 else
1101 {
1102 fluid_ostream_printf(out, "sfont is \"NULL\" for index %d\n", i);
1103 }
1104 }
1105
1106 return FLUID_OK;
1107 }
1108
1109 /* Purpose:
1110 * Response to 'rev_preset' command.
1111 * Load the values from a reverb preset into the reverb unit. */
1112 int
fluid_handle_reverbpreset(void * data,int ac,char ** av,fluid_ostream_t out)1113 fluid_handle_reverbpreset(void *data, int ac, char **av, fluid_ostream_t out)
1114 {
1115 FLUID_ENTRY_COMMAND(data);
1116 int reverb_preset_number;
1117
1118 fluid_ostream_printf(out, "rev_preset is deprecated and will be removed in a future release!\n");
1119
1120 if(ac < 1)
1121 {
1122 fluid_ostream_printf(out, "rev_preset: too few arguments\n");
1123 return FLUID_FAILED;
1124 }
1125
1126 reverb_preset_number = atoi(av[0]);
1127
1128 if(fluid_synth_set_reverb_preset(handler->synth, reverb_preset_number) != FLUID_OK)
1129 {
1130 fluid_ostream_printf(out, "rev_preset: Failed. Parameter out of range?\n");
1131 return FLUID_FAILED;
1132 };
1133
1134 return FLUID_OK;
1135 }
1136
1137 /*
1138 The function is useful for reverb and chorus commands which have
1139 1 or 2 parameters.
1140 The function checks that there is 1 or 2 arguments.
1141 When there is 2 parameters it checks the first argument that must be
1142 an fx group index in the range[0..synth->effects_groups-1].
1143
1144 return the group index:
1145 -1, when the command is for all fx groups.
1146 0 to synth->effects_groups-1, when the command is for this group index.
1147 -2 if error.
1148 */
check_fx_group_idx(int ac,char ** av,fluid_ostream_t out,fluid_synth_t * synth,const char * name_cde)1149 static int check_fx_group_idx(int ac, char **av, fluid_ostream_t out,
1150 fluid_synth_t *synth, const char *name_cde)
1151 {
1152 int fx_group; /* fx unit index */
1153 int ngroups; /* count of fx groups */
1154
1155 /* One or 2 arguments allowed */
1156 if(ac < 1 || ac > 2)
1157 {
1158 fluid_ostream_printf(out, "%s: needs 1 or 2 arguments\n", name_cde);
1159 return -2;
1160 }
1161
1162 /* check optional first argument which is a fx group index */
1163 fx_group = -1;
1164
1165 if(ac > 1)
1166 {
1167 fx_group = atoi(av[0]); /* get fx group index */
1168 ngroups = fluid_synth_count_effects_groups(synth);
1169
1170 if(!fluid_is_number(av[0]) || fx_group < 0 || fx_group >= ngroups)
1171 {
1172 fluid_ostream_printf(out, "%s: group index \"%s\" must be in range [%d..%d]\n",
1173 name_cde, av[0], 0, ngroups - 1);
1174 return -2;
1175 }
1176 }
1177
1178 return fx_group;
1179 }
1180
1181 /* parameter value */
1182 struct value
1183 {
1184 const char *name;
1185 double min;
1186 double max;
1187 };
1188
1189 /*
1190 check 2 arguments for reverb commands : fx group index , value
1191 - group index must be an integer in the range [-1..synth->effects_groups].
1192 - value must be a double in the range [min..max]
1193 @param param a pointer on a value to return the second value argument.
1194 return the fx group index:
1195 -1 when the command is for all fx group.
1196 0 to synth->effects_groups-1 when the command is for this group index.
1197 -2 if error.
1198 */
check_fx_reverb_param(int ac,char ** av,fluid_ostream_t out,fluid_synth_t * synth,const char * name_cde,const struct value * value,fluid_real_t * param)1199 static int check_fx_reverb_param(int ac, char **av, fluid_ostream_t out,
1200 fluid_synth_t *synth, const char *name_cde,
1201 const struct value *value,
1202 fluid_real_t *param)
1203 {
1204 /* get and check fx group index argument */
1205 int fx_group = check_fx_group_idx(ac, av, out, synth, name_cde);
1206
1207 if(fx_group >= -1)
1208 {
1209 fluid_real_t val;
1210
1211 /* get and check value argument */
1212 ac--;
1213 val = atof(av[ac]);
1214
1215 if(!fluid_is_number(av[ac]) || val < value->min || val > value->max)
1216 {
1217 fluid_ostream_printf(out, "%s: %s \"%s\" must be in range [%f..%f]\n",
1218 name_cde, value->name, av[ac], value->min, value->max);
1219 return -2;
1220 }
1221
1222 *param = val;
1223 }
1224
1225 return fx_group;
1226 }
1227
1228 /* Purpose:
1229 * Response to fluid_handle_reverbsetxxxx commands
1230 */
1231 static int
fluid_handle_reverb_command(void * data,int ac,char ** av,fluid_ostream_t out,int param)1232 fluid_handle_reverb_command(void *data, int ac, char **av, fluid_ostream_t out,
1233 int param)
1234 {
1235 int fx_group;
1236
1237 /* reverb commands name table */
1238 static const char *const name_cde[FLUID_REVERB_PARAM_LAST] =
1239 {"rev_setroomsize", "rev_setdamp", "rev_setwidth", "rev_setlevel"};
1240
1241 /* name and min/max values table */
1242 static struct value values[FLUID_REVERB_PARAM_LAST] =
1243 {
1244 {"room size", 0, 0},
1245 {"damp", 0, 0},
1246 {"width", 0, 0},
1247 {"level", 0, 0}
1248 };
1249
1250 FLUID_ENTRY_COMMAND(data);
1251 fluid_real_t value;
1252
1253 fluid_settings_getnum_range(handler->settings, "synth.reverb.room-size",
1254 &values[FLUID_REVERB_ROOMSIZE].min,
1255 &values[FLUID_REVERB_ROOMSIZE].max);
1256
1257 fluid_settings_getnum_range(handler->settings, "synth.reverb.damp",
1258 &values[FLUID_REVERB_DAMP].min,
1259 &values[FLUID_REVERB_DAMP].max);
1260
1261
1262 fluid_settings_getnum_range(handler->settings, "synth.reverb.width",
1263 &values[FLUID_REVERB_WIDTH].min,
1264 &values[FLUID_REVERB_WIDTH].max);
1265
1266 fluid_settings_getnum_range(handler->settings, "synth.reverb.level",
1267 &values[FLUID_REVERB_LEVEL].min,
1268 &values[FLUID_REVERB_LEVEL].max);
1269
1270 /* get and check command arguments */
1271 fx_group = check_fx_reverb_param(ac, av, out, handler->synth,
1272 name_cde[param], &values[param], &value);
1273
1274 if(fx_group >= -1)
1275 {
1276 /* run reverb function */
1277 fluid_synth_reverb_set_param(handler->synth, fx_group, param, value);
1278 return FLUID_OK;
1279 }
1280
1281 return FLUID_FAILED;
1282 }
1283
1284 /* Purpose:
1285 * Response to 'rev_setroomsize' command.
1286 * Load the new room size into the reverb fx group.
1287 * Example: rev_setroomzize 0 0.5
1288 * load roomsize 0.5 in the reverb fx group at index 0
1289 */
1290 int
fluid_handle_reverbsetroomsize(void * data,int ac,char ** av,fluid_ostream_t out)1291 fluid_handle_reverbsetroomsize(void *data, int ac, char **av, fluid_ostream_t out)
1292 {
1293 return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_ROOMSIZE);
1294 }
1295
1296 /* Purpose:
1297 * Response to 'rev_setdamp' command.
1298 * Load the new damp factor into the reverb fx group.
1299 * Example: rev_setdamp 1 0.5
1300 * load damp 0.5 in the reverb fx group at index 1
1301 */
1302 int
fluid_handle_reverbsetdamp(void * data,int ac,char ** av,fluid_ostream_t out)1303 fluid_handle_reverbsetdamp(void *data, int ac, char **av, fluid_ostream_t out)
1304 {
1305 return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_DAMP);
1306 }
1307
1308 /* Purpose:
1309 * Response to 'rev_setwidth' command.
1310 * Load the new width into the reverb fx group.
1311 * Example: rev_setwidth 1 0.5
1312 * load width 0.5 in the reverb fx group at index 1.
1313 */
1314 int
fluid_handle_reverbsetwidth(void * data,int ac,char ** av,fluid_ostream_t out)1315 fluid_handle_reverbsetwidth(void *data, int ac, char **av, fluid_ostream_t out)
1316 {
1317 return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_WIDTH);
1318 }
1319
1320 /* Purpose:
1321 * Response to 'rev_setlevel' command.
1322 * Load the new level into the reverb fx group.
1323 * Example: rev_setlevel 1 0.5
1324 * load level 0.5 in the reverb fx group at index 1.
1325 */
1326 int
fluid_handle_reverbsetlevel(void * data,int ac,char ** av,fluid_ostream_t out)1327 fluid_handle_reverbsetlevel(void *data, int ac, char **av, fluid_ostream_t out)
1328 {
1329 return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_LEVEL);
1330 }
1331
1332 /* reverb/chorus on/off commands enum */
1333 enum rev_chor_on_cde
1334 {
1335 REVERB_ON_CDE,
1336 CHORUS_ON_CDE,
1337 NBR_REV_CHOR_ON_CDE
1338 };
1339
1340 /* Purpose:
1341 * Set one or all reverb/chorus units on or off
1342 */
1343 static int
fluid_handle_reverb_chorus_on_command(void * data,int ac,char ** av,fluid_ostream_t out,enum rev_chor_on_cde cde)1344 fluid_handle_reverb_chorus_on_command(void *data, int ac, char **av, fluid_ostream_t out,
1345 enum rev_chor_on_cde cde)
1346 {
1347 /* commands name table */
1348 static const char *const name_cde[NBR_REV_CHOR_ON_CDE] = {"reverb", "chorus"};
1349 /* functions table */
1350 static int (*onoff_func[NBR_REV_CHOR_ON_CDE])(fluid_synth_t *, int, int) =
1351 {
1352 fluid_synth_reverb_on, fluid_synth_chorus_on
1353 };
1354
1355 FLUID_ENTRY_COMMAND(data);
1356 int onoff;
1357
1358 /* get and check fx group index argument */
1359 int fx_group = check_fx_group_idx(ac, av, out, handler->synth, name_cde[cde]);
1360
1361 if(fx_group >= -1)
1362 {
1363 ac--;
1364
1365 /* check argument value */
1366 if((FLUID_STRCMP(av[ac], "0") == 0) || (FLUID_STRCMP(av[ac], "off") == 0))
1367 {
1368 onoff = 0;
1369 }
1370 else if((FLUID_STRCMP(av[ac], "1") == 0) || (FLUID_STRCMP(av[ac], "on") == 0))
1371 {
1372 onoff = 1;
1373 }
1374 else
1375 {
1376 fluid_ostream_printf(out, "%s: invalid arguments %s [0|1|on|off]\n",
1377 name_cde[cde], av[ac]);
1378 return FLUID_FAILED;
1379 }
1380
1381 /* run on/off function */
1382 return onoff_func[cde](handler->synth, fx_group, onoff);
1383 }
1384
1385 return FLUID_FAILED;
1386 }
1387
1388 /* Purpose:
1389 * Response to: reverb [fx group] on command.
1390 * Examples:
1391 * reverb off ,disable all reverb groups.
1392 * reverb 1 on ,enable reverb group at index 1.
1393 */
1394 int
fluid_handle_reverb(void * data,int ac,char ** av,fluid_ostream_t out)1395 fluid_handle_reverb(void *data, int ac, char **av, fluid_ostream_t out)
1396 {
1397 return fluid_handle_reverb_chorus_on_command(data, ac, av, out, REVERB_ON_CDE);
1398 }
1399
1400 /* Purpose:
1401 * Response to fluid_handle_chorus_xxx commands
1402 */
1403 static int
fluid_handle_chorus_command(void * data,int ac,char ** av,fluid_ostream_t out,int param)1404 fluid_handle_chorus_command(void *data, int ac, char **av, fluid_ostream_t out,
1405 int param)
1406 {
1407 /* chorus commands name table */
1408 static const char *const name_cde[FLUID_CHORUS_PARAM_LAST - 1] =
1409 {"cho_set_nr", "cho_set_level", "cho_set_speed", "cho_set_depth"};
1410
1411 /* value name table */
1412 static const char *const name_value[FLUID_CHORUS_PARAM_LAST - 1] =
1413 {"nr", "level", "speed", "depth"};
1414
1415 /* setting name (except lfo waveform type) */
1416 static const char *name[FLUID_CHORUS_PARAM_LAST-1] =
1417 {
1418 "synth.chorus.nr", "synth.chorus.level",
1419 "synth.chorus.speed", "synth.chorus.depth"
1420 };
1421
1422 FLUID_ENTRY_COMMAND(data);
1423
1424 /* get and check index fx group index argument */
1425 int fx_group = check_fx_group_idx(ac, av, out, handler->synth, name_cde[param]);
1426
1427 if(fx_group >= -1)
1428 {
1429 double value;
1430 /* get and check value argument */
1431 ac--;
1432
1433 if(!fluid_is_number(av[ac]))
1434 {
1435 fluid_ostream_printf(out, "%s: %s \"%s\" must be a number\n",
1436 name_cde[param], name_value[param], av[ac]);
1437 return FLUID_FAILED;
1438 }
1439
1440 if(param == FLUID_CHORUS_NR) /* commands with integer parameter */
1441 {
1442 int min, max;
1443 int int_value = atoi(av[ac]);
1444
1445 fluid_settings_getint_range(handler->settings, name[param], &min, &max);
1446 if(int_value < min || int_value > max)
1447 {
1448 fluid_ostream_printf(out, "%s: %s \"%s\" must be in range [%d..%d]\n",
1449 name_cde[param], name_value[param], av[ac], min, max);
1450 return FLUID_FAILED;
1451 }
1452 value = (double)int_value;
1453 }
1454 else /* commands with float parameter */
1455 {
1456 double min, max;
1457 value = atof(av[ac]);
1458
1459 fluid_settings_getnum_range(handler->settings, name[param], &min, &max);
1460 if(value < min || value > max)
1461 {
1462 fluid_ostream_printf(out, "%s: %s \"%s\" must be in range [%f..%f]\n",
1463 name_cde[param], name_value[param], av[ac], min, max);
1464 return FLUID_FAILED;
1465 }
1466 }
1467
1468 /* run chorus function */
1469 fluid_synth_chorus_set_param(handler->synth, fx_group, param, value);
1470 return FLUID_OK;
1471 }
1472
1473 return FLUID_FAILED;
1474 }
1475
1476 /* Purpose:
1477 * Response to 'cho_set_nr' command
1478 * Load the new voice count into the chorus fx group.
1479 * Example: cho_set_nr 1 3
1480 * load 3 voices in the chorus fx group at index 1.
1481 */
1482 int
fluid_handle_chorusnr(void * data,int ac,char ** av,fluid_ostream_t out)1483 fluid_handle_chorusnr(void *data, int ac, char **av, fluid_ostream_t out)
1484 {
1485 return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_NR);
1486 }
1487
1488 /* Purpose:
1489 * Response to 'cho_setlevel' command
1490 * Example: cho_set_level 1 3
1491 * load level 3 in the chorus fx group at index 1.
1492 */
1493 int
fluid_handle_choruslevel(void * data,int ac,char ** av,fluid_ostream_t out)1494 fluid_handle_choruslevel(void *data, int ac, char **av, fluid_ostream_t out)
1495 {
1496 return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_LEVEL);
1497 }
1498
1499 /* Purpose:
1500 * Response to 'cho_setspeed' command
1501 * Example: cho_set_speed 1 0.1
1502 * load speed 0.1 in the chorus fx group at index 1.
1503 */
1504 int
fluid_handle_chorusspeed(void * data,int ac,char ** av,fluid_ostream_t out)1505 fluid_handle_chorusspeed(void *data, int ac, char **av, fluid_ostream_t out)
1506 {
1507 return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_SPEED);
1508 }
1509
1510 /* Purpose:
1511 * Response to 'cho_setdepth' command
1512 * Example: cho_set_depth 1 0.3
1513 * load depth 0.3 in the chorus fx group at index 1.
1514 */
1515 int
fluid_handle_chorusdepth(void * data,int ac,char ** av,fluid_ostream_t out)1516 fluid_handle_chorusdepth(void *data, int ac, char **av, fluid_ostream_t out)
1517 {
1518 return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_DEPTH);
1519 }
1520
1521 /* Purpose:
1522 * Response to: chorus [fx group] on command.
1523 * Examples:
1524 * chorus off ,disable all chorus groups.
1525 * chorus 1 on ,enable chorus group at index 1.
1526 */
1527 int
fluid_handle_chorus(void * data,int ac,char ** av,fluid_ostream_t out)1528 fluid_handle_chorus(void *data, int ac, char **av, fluid_ostream_t out)
1529 {
1530 return fluid_handle_reverb_chorus_on_command(data, ac, av, out, CHORUS_ON_CDE);
1531 }
1532
1533 /* Purpose:
1534 * Response to the 'echo' command.
1535 * The command itself is useful, when the synth is used via TCP/IP.
1536 * It can signal for example, that a list of commands has been processed.
1537 */
1538 int
fluid_handle_echo(void * data,int ac,char ** av,fluid_ostream_t out)1539 fluid_handle_echo(void *data, int ac, char **av, fluid_ostream_t out)
1540 {
1541 if(ac < 1)
1542 {
1543 fluid_ostream_printf(out, "echo: too few arguments.\n");
1544 return FLUID_FAILED;
1545 }
1546
1547 fluid_ostream_printf(out, "%s\n", av[0]);
1548
1549 return FLUID_OK;
1550 }
1551
1552 /* Purpose:
1553 * Sleep during a time in ms
1554 * The command itself is useful to insert a delay between commands.
1555 * It can help for example to build a small song using noteon/noteoff commands
1556 * in a command file.
1557 */
1558 int
fluid_handle_sleep(void * data,int ac,char ** av,fluid_ostream_t out)1559 fluid_handle_sleep(void *data, int ac, char **av, fluid_ostream_t out)
1560 {
1561 if(ac < 1)
1562 {
1563 fluid_ostream_printf(out, "sleep: too few arguments.\n");
1564 return -1;
1565 }
1566
1567 if(!fluid_is_number(av[0]))
1568 {
1569 fluid_ostream_printf(out, "sleep: argument should be a number in ms.\n");
1570 return -1;
1571 }
1572
1573 fluid_msleep(atoi(av[0])); /* delay in milliseconds */
1574
1575 return 0;
1576 }
1577
1578 int
fluid_handle_source(void * data,int ac,char ** av,fluid_ostream_t out)1579 fluid_handle_source(void *data, int ac, char **av, fluid_ostream_t out)
1580 {
1581 FLUID_ENTRY_COMMAND(data);
1582
1583 if(ac < 1)
1584 {
1585 fluid_ostream_printf(out, "source: too few arguments.\n");
1586 return FLUID_FAILED;
1587 }
1588
1589 fluid_source(handler, av[0]);
1590
1591 return FLUID_OK;
1592 }
1593
1594 /* Purpose:
1595 * Response to 'gain' command. */
1596 int
fluid_handle_gain(void * data,int ac,char ** av,fluid_ostream_t out)1597 fluid_handle_gain(void *data, int ac, char **av, fluid_ostream_t out)
1598 {
1599 FLUID_ENTRY_COMMAND(data);
1600 float gain;
1601
1602 if(ac < 1)
1603 {
1604 fluid_ostream_printf(out, "gain: too few arguments.\n");
1605 return FLUID_FAILED;
1606 }
1607
1608 gain = atof(av[0]);
1609
1610 if((gain < 0.0f) || (gain > 5.0f))
1611 {
1612 fluid_ostream_printf(out, "gain: value should be between '0' and '5'.\n");
1613 return FLUID_FAILED;
1614 };
1615
1616 fluid_synth_set_gain(handler->synth, gain);
1617
1618 return FLUID_OK;
1619 }
1620
1621 /* Response to voice_count command */
1622 static int
fluid_handle_voice_count(void * data,int ac,char ** av,fluid_ostream_t out)1623 fluid_handle_voice_count(void *data, int ac, char **av,
1624 fluid_ostream_t out)
1625 {
1626 FLUID_ENTRY_COMMAND(data);
1627 fluid_ostream_printf(out, "voice_count: %d\n",
1628 fluid_synth_get_active_voice_count(handler->synth));
1629 return FLUID_OK;
1630 }
1631
1632 /* Purpose:
1633 * Response to 'interp' command. */
1634 int
fluid_handle_interp(void * data,int ac,char ** av,fluid_ostream_t out)1635 fluid_handle_interp(void *data, int ac, char **av, fluid_ostream_t out)
1636 {
1637 FLUID_ENTRY_COMMAND(data);
1638 int interp;
1639 int chan = -1; /* -1: Set all channels */
1640
1641 if(ac < 1)
1642 {
1643 fluid_ostream_printf(out, "interp: too few arguments.\n");
1644 return FLUID_FAILED;
1645 }
1646
1647 interp = atoi(av[0]);
1648
1649 if((interp < 0) || (interp > FLUID_INTERP_HIGHEST))
1650 {
1651 fluid_ostream_printf(out, "interp: Bad value\n");
1652 return FLUID_FAILED;
1653 };
1654
1655 fluid_synth_set_interp_method(handler->synth, chan, interp);
1656
1657 return FLUID_OK;
1658 }
1659
1660 /* Purpose:
1661 * Response to 'interp' command. */
1662 int
fluid_handle_interpc(void * data,int ac,char ** av,fluid_ostream_t out)1663 fluid_handle_interpc(void *data, int ac, char **av, fluid_ostream_t out)
1664 {
1665 FLUID_ENTRY_COMMAND(data);
1666 int interp;
1667 int chan;
1668
1669 if(ac < 2)
1670 {
1671 fluid_ostream_printf(out, "interpc: too few arguments.\n");
1672 return FLUID_FAILED;
1673 }
1674
1675 chan = atoi(av[0]);
1676 interp = atoi(av[1]);
1677
1678 if((chan < 0) || (chan >= fluid_synth_count_midi_channels(handler->synth)))
1679 {
1680 fluid_ostream_printf(out, "interp: Bad value for channel number.\n");
1681 return FLUID_FAILED;
1682 };
1683
1684 if((interp < 0) || (interp > FLUID_INTERP_HIGHEST))
1685 {
1686 fluid_ostream_printf(out, "interp: Bad value for interpolation method.\n");
1687 return FLUID_FAILED;
1688 };
1689
1690 fluid_synth_set_interp_method(handler->synth, chan, interp);
1691
1692 return FLUID_OK;
1693 }
1694
1695 int
fluid_handle_tuning(void * data,int ac,char ** av,fluid_ostream_t out)1696 fluid_handle_tuning(void *data, int ac, char **av, fluid_ostream_t out)
1697 {
1698 FLUID_ENTRY_COMMAND(data);
1699 char *name;
1700 int bank, prog;
1701
1702 if(ac < 3)
1703 {
1704 fluid_ostream_printf(out, "tuning: too few arguments.\n");
1705 return FLUID_FAILED;
1706 }
1707
1708 name = av[0];
1709
1710 if(!fluid_is_number(av[1]))
1711 {
1712 fluid_ostream_printf(out, "tuning: 2nd argument should be a number.\n");
1713 return FLUID_FAILED;
1714 }
1715
1716 bank = atoi(av[1]);
1717
1718 if((bank < 0) || (bank >= 128))
1719 {
1720 fluid_ostream_printf(out, "tuning: invalid bank number.\n");
1721 return FLUID_FAILED;
1722 };
1723
1724 if(!fluid_is_number(av[2]))
1725 {
1726 fluid_ostream_printf(out, "tuning: 3rd argument should be a number.\n");
1727 return FLUID_FAILED;
1728 }
1729
1730 prog = atoi(av[2]);
1731
1732 if((prog < 0) || (prog >= 128))
1733 {
1734 fluid_ostream_printf(out, "tuning: invalid program number.\n");
1735 return FLUID_FAILED;
1736 };
1737
1738 fluid_synth_activate_key_tuning(handler->synth, bank, prog, name, NULL, FALSE);
1739
1740 return FLUID_OK;
1741 }
1742
1743 int
fluid_handle_tune(void * data,int ac,char ** av,fluid_ostream_t out)1744 fluid_handle_tune(void *data, int ac, char **av, fluid_ostream_t out)
1745 {
1746 FLUID_ENTRY_COMMAND(data);
1747 int bank, prog, key;
1748 double pitch;
1749
1750 if(ac < 4)
1751 {
1752 fluid_ostream_printf(out, "tune: too few arguments.\n");
1753 return FLUID_FAILED;
1754 }
1755
1756 if(!fluid_is_number(av[0]))
1757 {
1758 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1759 return FLUID_FAILED;
1760 }
1761
1762 bank = atoi(av[0]);
1763
1764 if((bank < 0) || (bank >= 128))
1765 {
1766 fluid_ostream_printf(out, "tune: invalid bank number.\n");
1767 return FLUID_FAILED;
1768 };
1769
1770 if(!fluid_is_number(av[1]))
1771 {
1772 fluid_ostream_printf(out, "tune: 2nd argument should be a number.\n");
1773 return FLUID_FAILED;
1774 }
1775
1776 prog = atoi(av[1]);
1777
1778 if((prog < 0) || (prog >= 128))
1779 {
1780 fluid_ostream_printf(out, "tune: invalid program number.\n");
1781 return FLUID_FAILED;
1782 };
1783
1784 if(!fluid_is_number(av[2]))
1785 {
1786 fluid_ostream_printf(out, "tune: 3rd argument should be a number.\n");
1787 return FLUID_FAILED;
1788 }
1789
1790 key = atoi(av[2]);
1791
1792 if((key < 0) || (key >= 128))
1793 {
1794 fluid_ostream_printf(out, "tune: invalid key number.\n");
1795 return FLUID_FAILED;
1796 };
1797
1798 pitch = atof(av[3]);
1799
1800 if(pitch < 0.0f)
1801 {
1802 fluid_ostream_printf(out, "tune: invalid pitch.\n");
1803 return FLUID_FAILED;
1804 };
1805
1806 fluid_synth_tune_notes(handler->synth, bank, prog, 1, &key, &pitch, 0);
1807
1808 return FLUID_OK;
1809 }
1810
1811 int
fluid_handle_settuning(void * data,int ac,char ** av,fluid_ostream_t out)1812 fluid_handle_settuning(void *data, int ac, char **av, fluid_ostream_t out)
1813 {
1814 FLUID_ENTRY_COMMAND(data);
1815 int chan, bank, prog;
1816
1817 if(ac < 3)
1818 {
1819 fluid_ostream_printf(out, "settuning: too few arguments.\n");
1820 return FLUID_FAILED;
1821 }
1822
1823 if(!fluid_is_number(av[0]))
1824 {
1825 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1826 return FLUID_FAILED;
1827 }
1828
1829 chan = atoi(av[0]);
1830
1831 if((chan < 0) || (chan >= fluid_synth_count_midi_channels(handler->synth)))
1832 {
1833 fluid_ostream_printf(out, "tune: invalid channel number.\n");
1834 return FLUID_FAILED;
1835 };
1836
1837 if(!fluid_is_number(av[1]))
1838 {
1839 fluid_ostream_printf(out, "tuning: 2nd argument should be a number.\n");
1840 return FLUID_FAILED;
1841 }
1842
1843 bank = atoi(av[1]);
1844
1845 if((bank < 0) || (bank >= 128))
1846 {
1847 fluid_ostream_printf(out, "tuning: invalid bank number.\n");
1848 return FLUID_FAILED;
1849 };
1850
1851 if(!fluid_is_number(av[2]))
1852 {
1853 fluid_ostream_printf(out, "tuning: 3rd argument should be a number.\n");
1854 return FLUID_FAILED;
1855 }
1856
1857 prog = atoi(av[2]);
1858
1859 if((prog < 0) || (prog >= 128))
1860 {
1861 fluid_ostream_printf(out, "tuning: invalid program number.\n");
1862 return FLUID_FAILED;
1863 };
1864
1865 fluid_synth_activate_tuning(handler->synth, chan, bank, prog, FALSE);
1866
1867 return FLUID_OK;
1868 }
1869
1870 int
fluid_handle_resettuning(void * data,int ac,char ** av,fluid_ostream_t out)1871 fluid_handle_resettuning(void *data, int ac, char **av, fluid_ostream_t out)
1872 {
1873 FLUID_ENTRY_COMMAND(data);
1874 int chan;
1875
1876 if(ac < 1)
1877 {
1878 fluid_ostream_printf(out, "resettuning: too few arguments.\n");
1879 return FLUID_FAILED;
1880 }
1881
1882 if(!fluid_is_number(av[0]))
1883 {
1884 fluid_ostream_printf(out, "tune: 1st argument should be a number.\n");
1885 return FLUID_FAILED;
1886 }
1887
1888 chan = atoi(av[0]);
1889
1890 if((chan < 0) || (chan >= fluid_synth_count_midi_channels(handler->synth)))
1891 {
1892 fluid_ostream_printf(out, "tune: invalid channel number.\n");
1893 return FLUID_FAILED;
1894 };
1895
1896 fluid_synth_deactivate_tuning(handler->synth, chan, FALSE);
1897
1898 return FLUID_OK;
1899 }
1900
1901 int
fluid_handle_tunings(void * data,int ac,char ** av,fluid_ostream_t out)1902 fluid_handle_tunings(void *data, int ac, char **av, fluid_ostream_t out)
1903 {
1904 FLUID_ENTRY_COMMAND(data);
1905 int bank, prog;
1906 char name[256];
1907 int count = 0;
1908
1909 fluid_synth_tuning_iteration_start(handler->synth);
1910
1911 while(fluid_synth_tuning_iteration_next(handler->synth, &bank, &prog))
1912 {
1913 fluid_synth_tuning_dump(handler->synth, bank, prog, name, 256, NULL);
1914 fluid_ostream_printf(out, "%03d-%03d %s\n", bank, prog, name);
1915 count++;
1916 }
1917
1918 if(count == 0)
1919 {
1920 fluid_ostream_printf(out, "No tunings available\n");
1921 }
1922
1923 return FLUID_OK;
1924 }
1925
1926 int
fluid_handle_dumptuning(void * data,int ac,char ** av,fluid_ostream_t out)1927 fluid_handle_dumptuning(void *data, int ac, char **av, fluid_ostream_t out)
1928 {
1929 FLUID_ENTRY_COMMAND(data);
1930 int bank, prog, i, res;
1931 double pitch[128];
1932 char name[256];
1933
1934 if(ac < 2)
1935 {
1936 fluid_ostream_printf(out, "dumptuning: too few arguments.\n");
1937 return FLUID_FAILED;
1938 }
1939
1940 if(!fluid_is_number(av[0]))
1941 {
1942 fluid_ostream_printf(out, "dumptuning: 1st argument should be a number.\n");
1943 return FLUID_FAILED;
1944 }
1945
1946 bank = atoi(av[0]);
1947
1948 if((bank < 0) || (bank >= 128))
1949 {
1950 fluid_ostream_printf(out, "dumptuning: invalid bank number.\n");
1951 return FLUID_FAILED;
1952 };
1953
1954 if(!fluid_is_number(av[1]))
1955 {
1956 fluid_ostream_printf(out, "dumptuning: 2nd argument should be a number.\n");
1957 return FLUID_FAILED;
1958 }
1959
1960 prog = atoi(av[1]);
1961
1962 if((prog < 0) || (prog >= 128))
1963 {
1964 fluid_ostream_printf(out, "dumptuning: invalid program number.\n");
1965 return FLUID_FAILED;
1966 };
1967
1968 res = fluid_synth_tuning_dump(handler->synth, bank, prog, name, 256, pitch);
1969
1970 if(FLUID_OK != res)
1971 {
1972 fluid_ostream_printf(out, "Tuning %03d-%03d does not exist.\n", bank, prog);
1973 return FLUID_FAILED;
1974 }
1975
1976 fluid_ostream_printf(out, "%03d-%03d %s:\n", bank, prog, name);
1977
1978 for(i = 0; i < 128; i++)
1979 {
1980 fluid_ostream_printf(out, "key %03d, pitch %5.2f\n", i, pitch[i]);
1981 }
1982
1983 return FLUID_OK;
1984 }
1985
1986 int
fluid_handle_set(void * data,int ac,char ** av,fluid_ostream_t out)1987 fluid_handle_set(void *data, int ac, char **av, fluid_ostream_t out)
1988 {
1989 FLUID_ENTRY_COMMAND(data);
1990 int hints;
1991 int ival, icur;
1992 double fval, fcur;
1993 char *scur;
1994 int ret = FLUID_FAILED;
1995
1996 if(ac < 2)
1997 {
1998 fluid_ostream_printf(out, "set: Too few arguments.\n");
1999 return ret;
2000 }
2001
2002 switch(fluid_settings_get_type(handler->settings, av[0]))
2003 {
2004 case FLUID_NO_TYPE:
2005 fluid_ostream_printf(out, "set: Parameter '%s' not found.\n", av[0]);
2006 return ret;
2007
2008 case FLUID_INT_TYPE:
2009 if(fluid_settings_get_hints(handler->settings, av[0], &hints) == FLUID_OK
2010 && hints & FLUID_HINT_TOGGLED)
2011 {
2012 if(FLUID_STRCASECMP(av[1], "yes") == 0
2013 || FLUID_STRCASECMP(av[1], "true") == 0
2014 || FLUID_STRCASECMP(av[1], "t") == 0)
2015 {
2016 ival = 1;
2017 }
2018 else
2019 {
2020 ival = atoi(av[1]);
2021 }
2022 }
2023 else
2024 {
2025 ival = atoi(av[1]);
2026 }
2027
2028 fluid_settings_getint(handler->settings, av[0], &icur);
2029 if (icur == ival)
2030 {
2031 return FLUID_OK;
2032 }
2033
2034 ret = fluid_settings_setint(handler->settings, av[0], ival);
2035 break;
2036
2037 case FLUID_NUM_TYPE:
2038 fval = atof(av[1]);
2039 fluid_settings_getnum(handler->settings, av[0], &fcur);
2040 if (fcur == fval)
2041 {
2042 return FLUID_OK;
2043 }
2044
2045 ret = fluid_settings_setnum(handler->settings, av[0], fval);
2046 break;
2047
2048 case FLUID_STR_TYPE:
2049 fluid_settings_dupstr(handler->settings, av[0], &scur);
2050
2051 if(scur && !FLUID_STRCMP(scur, av[1]))
2052 {
2053 FLUID_FREE(scur);
2054 return FLUID_OK;
2055 }
2056 ret = fluid_settings_setstr(handler->settings, av[0], av[1]);
2057 FLUID_FREE(scur);
2058 break;
2059
2060 case FLUID_SET_TYPE:
2061 fluid_ostream_printf(out, "set: Parameter '%s' is a node.\n", av[0]);
2062 return FLUID_FAILED;
2063
2064 default:
2065 fluid_ostream_printf(out, "Unhandled settings type.");
2066 return FLUID_FAILED;
2067 }
2068
2069 if(ret == FLUID_FAILED)
2070 {
2071 fluid_ostream_printf(out, "set: Value out of range. Try 'info %s' for valid ranges\n", av[0]);
2072 }
2073
2074 if((handler->synth != NULL || handler->router != NULL) && !fluid_settings_is_realtime(handler->settings, av[0]))
2075 {
2076 fluid_ostream_printf(out, "Warning: '%s' is not a realtime setting, changes won't take effect.\n", av[0]);
2077 }
2078
2079 return ret;
2080 }
2081
2082 int
fluid_handle_get(void * data,int ac,char ** av,fluid_ostream_t out)2083 fluid_handle_get(void *data, int ac, char **av, fluid_ostream_t out)
2084 {
2085 FLUID_ENTRY_COMMAND(data);
2086
2087 if(ac < 1)
2088 {
2089 fluid_ostream_printf(out, "get: too few arguments.\n");
2090 return FLUID_FAILED;
2091 }
2092
2093 switch(fluid_settings_get_type(handler->settings, av[0]))
2094 {
2095 case FLUID_NO_TYPE:
2096 fluid_ostream_printf(out, "get: no such setting '%s'.\n", av[0]);
2097 return FLUID_FAILED;
2098
2099 case FLUID_NUM_TYPE:
2100 {
2101 double value;
2102 fluid_settings_getnum(handler->settings, av[0], &value);
2103 fluid_ostream_printf(out, "%.3f\n", value);
2104 break;
2105 }
2106
2107 case FLUID_INT_TYPE:
2108 {
2109 int value;
2110 fluid_settings_getint(handler->settings, av[0], &value);
2111 fluid_ostream_printf(out, "%d\n", value);
2112 break;
2113 }
2114
2115 case FLUID_STR_TYPE:
2116 {
2117 char *s = NULL;
2118 fluid_settings_dupstr(handler->settings, av[0], &s); /* ++ alloc string */
2119 fluid_ostream_printf(out, "%s\n", s ? s : "NULL");
2120 FLUID_FREE(s); /* -- free string */
2121
2122 break;
2123 }
2124
2125 case FLUID_SET_TYPE:
2126 fluid_ostream_printf(out, "%s is a node\n", av[0]);
2127 break;
2128 }
2129
2130 return FLUID_OK;
2131 }
2132
2133 struct _fluid_handle_settings_data_t
2134 {
2135 size_t len;
2136 fluid_settings_t *settings;
2137 fluid_ostream_t out;
2138 };
2139
fluid_handle_settings_iter1(void * data,const char * name,int type)2140 static void fluid_handle_settings_iter1(void *data, const char *name, int type)
2141 {
2142 struct _fluid_handle_settings_data_t *d = (struct _fluid_handle_settings_data_t *) data;
2143
2144 size_t len = FLUID_STRLEN(name);
2145
2146 if(len > d->len)
2147 {
2148 d->len = len;
2149 }
2150 }
2151
fluid_handle_settings_iter2(void * data,const char * name,int type)2152 static void fluid_handle_settings_iter2(void *data, const char *name, int type)
2153 {
2154 struct _fluid_handle_settings_data_t *d = (struct _fluid_handle_settings_data_t *) data;
2155
2156 size_t len = FLUID_STRLEN(name);
2157 fluid_ostream_printf(d->out, "%s", name);
2158
2159 while(len++ < d->len)
2160 {
2161 fluid_ostream_printf(d->out, " ");
2162 }
2163
2164 fluid_ostream_printf(d->out, " ");
2165
2166 switch(fluid_settings_get_type(d->settings, name))
2167 {
2168 case FLUID_NUM_TYPE:
2169 {
2170 double value;
2171 fluid_settings_getnum(d->settings, name, &value);
2172 fluid_ostream_printf(d->out, "%.3f\n", value);
2173 break;
2174 }
2175
2176 case FLUID_INT_TYPE:
2177 {
2178 int value, hints;
2179 fluid_settings_getint(d->settings, name, &value);
2180
2181 if(fluid_settings_get_hints(d->settings, name, &hints) == FLUID_OK)
2182 {
2183 if(!(hints & FLUID_HINT_TOGGLED))
2184 {
2185 fluid_ostream_printf(d->out, "%d\n", value);
2186 }
2187 else
2188 {
2189 fluid_ostream_printf(d->out, "%s\n", value ? "True" : "False");
2190 }
2191 }
2192
2193 break;
2194 }
2195
2196 case FLUID_STR_TYPE:
2197 {
2198 char *s = NULL;
2199 fluid_settings_dupstr(d->settings, name, &s); /* ++ alloc string */
2200 fluid_ostream_printf(d->out, "%s\n", s ? s : "NULL");
2201 FLUID_FREE(s); /* -- free string */
2202
2203 break;
2204 }
2205 }
2206 }
2207
2208 int
fluid_handle_settings(void * d,int ac,char ** av,fluid_ostream_t out)2209 fluid_handle_settings(void *d, int ac, char **av, fluid_ostream_t out)
2210 {
2211 FLUID_ENTRY_COMMAND(d);
2212 struct _fluid_handle_settings_data_t data;
2213
2214 data.len = 0;
2215 data.settings = handler->settings;
2216 data.out = out;
2217
2218 fluid_settings_foreach(handler->settings, &data, fluid_handle_settings_iter1);
2219 fluid_settings_foreach(handler->settings, &data, fluid_handle_settings_iter2);
2220 return FLUID_OK;
2221 }
2222
2223
2224 struct _fluid_handle_option_data_t
2225 {
2226 int first;
2227 fluid_ostream_t out;
2228 };
2229
fluid_handle_print_option(void * data,const char * name,const char * option)2230 void fluid_handle_print_option(void *data, const char *name, const char *option)
2231 {
2232 struct _fluid_handle_option_data_t *d = (struct _fluid_handle_option_data_t *) data;
2233
2234 if(d->first)
2235 {
2236 fluid_ostream_printf(d->out, "%s", option);
2237 d->first = 0;
2238 }
2239 else
2240 {
2241 fluid_ostream_printf(d->out, ", %s", option);
2242 }
2243 }
2244
2245 int
fluid_handle_info(void * d,int ac,char ** av,fluid_ostream_t out)2246 fluid_handle_info(void *d, int ac, char **av, fluid_ostream_t out)
2247 {
2248 FLUID_ENTRY_COMMAND(d);
2249 fluid_settings_t *settings = handler->settings;
2250 struct _fluid_handle_option_data_t data;
2251
2252 if(ac < 1)
2253 {
2254 fluid_ostream_printf(out, "info: too few arguments.\n");
2255 return FLUID_FAILED;
2256 }
2257
2258 switch(fluid_settings_get_type(settings, av[0]))
2259 {
2260 case FLUID_NO_TYPE:
2261 fluid_ostream_printf(out, "info: no such setting '%s'.\n", av[0]);
2262 return FLUID_FAILED;
2263
2264 case FLUID_NUM_TYPE:
2265 {
2266 double value, min, max, def;
2267
2268 if(fluid_settings_getnum_range(settings, av[0], &min, &max) == FLUID_OK
2269 && fluid_settings_getnum(settings, av[0], &value) == FLUID_OK
2270 && fluid_settings_getnum_default(settings, av[0], &def) == FLUID_OK)
2271 {
2272 fluid_ostream_printf(out, "%s:\n", av[0]);
2273 fluid_ostream_printf(out, "Type: number\n");
2274 fluid_ostream_printf(out, "Value: %.3f\n", value);
2275 fluid_ostream_printf(out, "Minimum value: %.3f\n", min);
2276 fluid_ostream_printf(out, "Maximum value: %.3f\n", max);
2277 fluid_ostream_printf(out, "Default value: %.3f\n", def);
2278 fluid_ostream_printf(out, "Real-time: %s\n",
2279 fluid_settings_is_realtime(settings, av[0]) ? "yes" : "no");
2280 }
2281 else
2282 {
2283 fluid_ostream_printf(out, "An error occurred when processing %s\n", av[0]);
2284 }
2285
2286 break;
2287 }
2288
2289 case FLUID_INT_TYPE:
2290 {
2291 int value, min, max, def, hints;
2292
2293 if(fluid_settings_getint_range(settings, av[0], &min, &max) == FLUID_OK
2294 && fluid_settings_getint(settings, av[0], &value) == FLUID_OK
2295 && fluid_settings_get_hints(settings, av[0], &hints) == FLUID_OK
2296 && fluid_settings_getint_default(settings, av[0], &def) == FLUID_OK)
2297 {
2298 fluid_ostream_printf(out, "%s:\n", av[0]);
2299
2300 if(!(hints & FLUID_HINT_TOGGLED))
2301 {
2302 fluid_ostream_printf(out, "Type: integer\n");
2303 fluid_ostream_printf(out, "Value: %d\n", value);
2304 fluid_ostream_printf(out, "Minimum value: %d\n", min);
2305 fluid_ostream_printf(out, "Maximum value: %d\n", max);
2306 fluid_ostream_printf(out, "Default value: %d\n", def);
2307 }
2308 else
2309 {
2310 fluid_ostream_printf(out, "Type: boolean\n");
2311 fluid_ostream_printf(out, "Value: %s\n", value ? "True" : "False");
2312 fluid_ostream_printf(out, "Default value: %s\n", def ? "True" : "False");
2313 }
2314
2315 fluid_ostream_printf(out, "Real-time: %s\n",
2316 fluid_settings_is_realtime(settings, av[0]) ? "yes" : "no");
2317 }
2318 else
2319 {
2320 fluid_ostream_printf(out, "An error occurred when processing %s\n", av[0]);
2321 }
2322
2323 break;
2324 }
2325
2326 case FLUID_STR_TYPE:
2327 {
2328 char *s = NULL;
2329 fluid_settings_dupstr(settings, av[0], &s); /* ++ alloc string */
2330 fluid_ostream_printf(out, "%s:\n", av[0]);
2331 fluid_ostream_printf(out, "Type: string\n");
2332 fluid_ostream_printf(out, "Value: %s\n", s ? s : "NULL");
2333 FLUID_FREE(s); /* -- free string */
2334
2335 fluid_settings_getstr_default(settings, av[0], &s);
2336 fluid_ostream_printf(out, "Default value: %s\n", s);
2337
2338 data.out = out;
2339 data.first = 1;
2340 fluid_ostream_printf(out, "Options: ");
2341 fluid_settings_foreach_option(settings, av[0], &data, fluid_handle_print_option);
2342 fluid_ostream_printf(out, "\n");
2343
2344 fluid_ostream_printf(out, "Real-time: %s\n",
2345 fluid_settings_is_realtime(settings, av[0]) ? "yes" : "no");
2346 break;
2347 }
2348
2349 case FLUID_SET_TYPE:
2350 fluid_ostream_printf(out, "%s:\n", av[0]);
2351 fluid_ostream_printf(out, "Type: node\n");
2352 break;
2353 }
2354
2355 return FLUID_OK;
2356 }
2357
2358 int
fluid_handle_reset(void * data,int ac,char ** av,fluid_ostream_t out)2359 fluid_handle_reset(void *data, int ac, char **av, fluid_ostream_t out)
2360 {
2361 FLUID_ENTRY_COMMAND(data);
2362 fluid_synth_system_reset(handler->synth);
2363 return FLUID_OK;
2364 }
2365
2366 int
fluid_handle_quit(void * data,int ac,char ** av,fluid_ostream_t out)2367 fluid_handle_quit(void *data, int ac, char **av, fluid_ostream_t out)
2368 {
2369 fluid_ostream_printf(out, "cheers!\n");
2370 return -2;
2371 }
2372
2373 int
fluid_handle_help(void * data,int ac,char ** av,fluid_ostream_t out)2374 fluid_handle_help(void *data, int ac, char **av, fluid_ostream_t out)
2375 {
2376 /* Purpose:
2377 * Prints the help text for the command line commands.
2378 * Can be used as follows:
2379 * - help
2380 * - help (topic), where (topic) is 'general', 'chorus', etc.
2381 * - help all
2382 */
2383 char *topic = "help"; /* default, if no topic is given */
2384 int count = 0;
2385 unsigned int i;
2386
2387 fluid_ostream_printf(out, "\n");
2388
2389 /* 1st argument (optional): help topic */
2390 if(ac >= 1)
2391 {
2392 topic = av[0];
2393 }
2394
2395 if(FLUID_STRCMP(topic, "help") == 0)
2396 {
2397 /* "help help": Print a list of all topics */
2398 fluid_ostream_printf(out,
2399 "*** Help topics:***\n"
2400 "help all (prints all topics)\n");
2401
2402 for(i = 0; i < FLUID_N_ELEMENTS(fluid_commands); i++)
2403 {
2404 int listed_first_time = 1;
2405 unsigned int ii;
2406
2407 for(ii = 0; ii < i; ii++)
2408 {
2409 if(FLUID_STRCMP(fluid_commands[i].topic, fluid_commands[ii].topic) == 0)
2410 {
2411 listed_first_time = 0;
2412 }; /* if topic has already been listed */
2413 }; /* for all topics (inner loop) */
2414
2415 if(listed_first_time)
2416 {
2417 fluid_ostream_printf(out, "help %s\n", fluid_commands[i].topic);
2418 };
2419 }; /* for all topics (outer loop) */
2420 }
2421 else
2422 {
2423 /* help (arbitrary topic or "all") */
2424 for(i = 0; i < FLUID_N_ELEMENTS(fluid_commands); i++)
2425 {
2426 if(fluid_commands[i].help != NULL)
2427 {
2428 if(FLUID_STRCMP(topic, "all") == 0 || FLUID_STRCMP(topic, fluid_commands[i].topic) == 0)
2429 {
2430 fluid_ostream_printf(out, "%s\n", fluid_commands[i].help);
2431 count++;
2432 }; /* if it matches the topic */
2433 }; /* if help text exists */
2434 }; /* foreach command */
2435
2436 if(count == 0)
2437 {
2438 fluid_ostream_printf(out, "Unknown help topic. Try 'help help'.\n");
2439 };
2440 };
2441
2442 return FLUID_OK;
2443 }
2444
2445 #define CHECK_VALID_ROUTER(_router, _out) \
2446 if (router == NULL) { \
2447 fluid_ostream_printf(out, "cannot execute router command without a midi router.\n"); \
2448 return FLUID_FAILED; \
2449 }
2450
2451 /* Command handler for "router_clear" command */
fluid_handle_router_clear(void * data,int ac,char ** av,fluid_ostream_t out)2452 int fluid_handle_router_clear(void *data, int ac, char **av, fluid_ostream_t out)
2453 {
2454 FLUID_ENTRY_COMMAND(data);
2455 fluid_midi_router_t *router = handler->router;
2456
2457 if(ac != 0)
2458 {
2459 fluid_ostream_printf(out, "router_clear needs no arguments.\n");
2460 return FLUID_FAILED;
2461 }
2462
2463 CHECK_VALID_ROUTER(router, out);
2464
2465 fluid_midi_router_clear_rules(router);
2466
2467 return FLUID_OK;
2468 }
2469
2470 /* Command handler for "router_default" command */
fluid_handle_router_default(void * data,int ac,char ** av,fluid_ostream_t out)2471 int fluid_handle_router_default(void *data, int ac, char **av, fluid_ostream_t out)
2472 {
2473 FLUID_ENTRY_COMMAND(data);
2474 fluid_midi_router_t *router = handler->router;
2475
2476 if(ac != 0)
2477 {
2478 fluid_ostream_printf(out, "router_default needs no arguments.\n");
2479 return FLUID_FAILED;
2480 }
2481
2482 CHECK_VALID_ROUTER(router, out);
2483
2484 fluid_midi_router_set_default_rules(router);
2485
2486 return FLUID_OK;
2487 }
2488
2489 /* Command handler for "router_begin" command */
fluid_handle_router_begin(void * data,int ac,char ** av,fluid_ostream_t out)2490 int fluid_handle_router_begin(void *data, int ac, char **av, fluid_ostream_t out)
2491 {
2492 FLUID_ENTRY_COMMAND(data);
2493 fluid_midi_router_t *router = handler->router;
2494
2495 if(ac != 1)
2496 {
2497 fluid_ostream_printf(out, "router_begin requires [note|cc|prog|pbend|cpress|kpress]\n");
2498 return FLUID_FAILED;
2499 }
2500
2501 CHECK_VALID_ROUTER(router, out);
2502
2503 if(FLUID_STRCMP(av[0], "note") == 0)
2504 {
2505 handler->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_NOTE;
2506 }
2507 else if(FLUID_STRCMP(av[0], "cc") == 0)
2508 {
2509 handler->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_CC;
2510 }
2511 else if(FLUID_STRCMP(av[0], "prog") == 0)
2512 {
2513 handler->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_PROG_CHANGE;
2514 }
2515 else if(FLUID_STRCMP(av[0], "pbend") == 0)
2516 {
2517 handler->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_PITCH_BEND;
2518 }
2519 else if(FLUID_STRCMP(av[0], "cpress") == 0)
2520 {
2521 handler->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE;
2522 }
2523 else if(FLUID_STRCMP(av[0], "kpress") == 0)
2524 {
2525 handler->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE;
2526 }
2527 else
2528 {
2529 fluid_ostream_printf(out, "router_begin requires [note|cc|prog|pbend|cpress|kpress]\n");
2530 return FLUID_FAILED;
2531 }
2532
2533 if(handler->cmd_rule)
2534 {
2535 delete_fluid_midi_router_rule(handler->cmd_rule);
2536 }
2537
2538 handler->cmd_rule = new_fluid_midi_router_rule();
2539
2540 if(!handler->cmd_rule)
2541 {
2542 return FLUID_FAILED;
2543 }
2544
2545 return FLUID_OK;
2546 }
2547
2548 /* Command handler for "router_end" command */
fluid_handle_router_end(void * data,int ac,char ** av,fluid_ostream_t out)2549 int fluid_handle_router_end(void *data, int ac, char **av, fluid_ostream_t out)
2550 {
2551 FLUID_ENTRY_COMMAND(data);
2552 fluid_midi_router_t *router = handler->router;
2553
2554 if(ac != 0)
2555 {
2556 fluid_ostream_printf(out, "router_end needs no arguments.\n");
2557 return FLUID_FAILED;
2558 }
2559
2560 CHECK_VALID_ROUTER(router, out);
2561
2562 if(!handler->cmd_rule)
2563 {
2564 fluid_ostream_printf(out, "No active router_begin command.\n");
2565 return FLUID_FAILED;
2566 }
2567
2568 /* Add the rule */
2569 if(fluid_midi_router_add_rule(router, handler->cmd_rule, handler->cmd_rule_type) != FLUID_OK)
2570 {
2571 delete_fluid_midi_router_rule(handler->cmd_rule); /* Free on failure */
2572 }
2573
2574 handler->cmd_rule = NULL;
2575
2576 return FLUID_OK;
2577 }
2578
2579 /* Command handler for "router_chan" command */
fluid_handle_router_chan(void * data,int ac,char ** av,fluid_ostream_t out)2580 int fluid_handle_router_chan(void *data, int ac, char **av, fluid_ostream_t out)
2581 {
2582 FLUID_ENTRY_COMMAND(data);
2583 fluid_midi_router_t *router = handler->router;
2584
2585 if(ac != 4)
2586 {
2587 fluid_ostream_printf(out, "router_chan needs four args: min, max, mul, add.");
2588 return FLUID_FAILED;
2589 }
2590
2591 CHECK_VALID_ROUTER(router, out);
2592
2593 if(!handler->cmd_rule)
2594 {
2595 fluid_ostream_printf(out, "No active router_begin command.\n");
2596 return FLUID_FAILED;
2597 }
2598
2599 fluid_midi_router_rule_set_chan(handler->cmd_rule, atoi(av[0]), atoi(av[1]),
2600 atof(av[2]), atoi(av[3]));
2601 return FLUID_OK;
2602 }
2603
2604 /* Command handler for "router_par1" command */
fluid_handle_router_par1(void * data,int ac,char ** av,fluid_ostream_t out)2605 int fluid_handle_router_par1(void *data, int ac, char **av, fluid_ostream_t out)
2606 {
2607 FLUID_ENTRY_COMMAND(data);
2608 fluid_midi_router_t *router = handler->router;
2609
2610 if(ac != 4)
2611 {
2612 fluid_ostream_printf(out, "router_par1 needs four args: min, max, mul, add.");
2613 return FLUID_FAILED;
2614 }
2615
2616 CHECK_VALID_ROUTER(router, out);
2617
2618 if(!handler->cmd_rule)
2619 {
2620 fluid_ostream_printf(out, "No active router_begin command.\n");
2621 return FLUID_FAILED;
2622 }
2623
2624 fluid_midi_router_rule_set_param1(handler->cmd_rule, atoi(av[0]), atoi(av[1]),
2625 atof(av[2]), atoi(av[3]));
2626 return FLUID_OK;
2627 }
2628
2629 /* Command handler for "router_par2" command */
fluid_handle_router_par2(void * data,int ac,char ** av,fluid_ostream_t out)2630 int fluid_handle_router_par2(void *data, int ac, char **av, fluid_ostream_t out)
2631 {
2632 FLUID_ENTRY_COMMAND(data);
2633 fluid_midi_router_t *router = handler->router;
2634
2635 if(ac != 4)
2636 {
2637 fluid_ostream_printf(out, "router_par2 needs four args: min, max, mul, add.");
2638 return FLUID_FAILED;
2639 }
2640
2641 CHECK_VALID_ROUTER(router, out);
2642
2643 if(!handler->cmd_rule)
2644 {
2645 fluid_ostream_printf(out, "No active router_begin command.\n");
2646 return FLUID_FAILED;
2647 }
2648
2649 fluid_midi_router_rule_set_param2(handler->cmd_rule, atoi(av[0]), atoi(av[1]),
2650 atof(av[2]), atoi(av[3]));
2651 return FLUID_OK;
2652 }
2653
2654 /** commands Poly/mono mode *************************************************/
2655
2656 static const char *const mode_name[] =
2657 {
2658 "poly omni on (0)", "mono omni on (1)",
2659 "poly omni off(2)", "mono omni off(3)"
2660 };
2661
2662 /*
2663 Prints result message for commands: basicchannels, resetbasicchannels.
2664 Prints all basic channels and print a warning if there is no basic channel.
2665
2666 @param synth the synth instance.
2667 @param out output stream.
2668 */
print_basic_channels(fluid_synth_t * synth,fluid_ostream_t out)2669 static int print_basic_channels(fluid_synth_t *synth, fluid_ostream_t out)
2670 {
2671 static const char warning_msg[] = "Warning: no basic channels. All MIDI channels are disabled.\n"
2672 "Make use of setbasicchannels to set at least a default basic channel.\n";
2673
2674 int n_chan = synth->midi_channels;
2675 int i, n = 0;
2676
2677 /* prints all basic channels */
2678 for(i = 0; i < n_chan; i++)
2679 {
2680 int basic_chan, mode_chan, val;
2681
2682 if(fluid_synth_get_basic_channel(synth, i, &basic_chan, &mode_chan, &val) == FLUID_OK)
2683 {
2684 if(basic_chan == i)
2685 {
2686 n++;
2687 fluid_ostream_printf(out, "Basic channel:%3d, %s, nbr:%3d\n", i,
2688 mode_name[mode_chan & FLUID_CHANNEL_MODE_MASK ],
2689 val);
2690 }
2691 }
2692 else
2693 {
2694 return FLUID_FAILED; /* error */
2695 }
2696 }
2697
2698 /* prints a warning if there is no basic channel */
2699 if(n == 0)
2700 {
2701 fluid_ostream_printf(out, warning_msg);
2702 }
2703
2704 return FLUID_OK;
2705 }
2706
2707 /*-----------------------------------------------------------------------------
2708 basicchannels
2709 Prints the list of all MIDI basic channels information
2710 example:
2711
2712 Basic channel: 0, poly omni on (0), nbr: 3
2713 Basic channel: 3, poly omni off(2), nbr: 1
2714 Basic channel: 8, mono omni off(3), nbr: 2
2715 Basic channel: 13, mono omni on (1), nbr: 3
2716 */
fluid_handle_basicchannels(void * data,int ac,char ** av,fluid_ostream_t out)2717 int fluid_handle_basicchannels(void *data, int ac, char **av,
2718 fluid_ostream_t out)
2719 {
2720 FLUID_ENTRY_COMMAND(data);
2721 fluid_synth_t *synth = handler->synth;
2722 return print_basic_channels(synth, out);
2723 }
2724
2725 /*
2726 Searches a mode name and returns the channel mode number.
2727 name must be: poly_omnion, mono_omnion, poly_omnioff, mono_omnioff.
2728 @param name to search.
2729 @return channel mode number (0 to 3) if name is valid, -1 otherwise.
2730 */
get_channel_mode_num(char * name)2731 static int get_channel_mode_num(char *name)
2732 {
2733 /* argument names for channel mode parameter (see resetbasicchannels and
2734 setbasicchannels commands*/
2735 static const char *const name_channel_mode [FLUID_CHANNEL_MODE_LAST] =
2736 {"poly_omnion", "mono_omnion", "poly_omnioff", "mono_omnioff"};
2737 int i;
2738
2739 for(i = 0 ; i < FLUID_CHANNEL_MODE_LAST; i++)
2740 {
2741 if(! FLUID_STRCMP(name, name_channel_mode[i]))
2742 {
2743 return i;
2744 }
2745 }
2746
2747 return -1;
2748 }
2749
2750 static const char invalid_arg_msg[] = "invalid argument\n";
2751 /*
2752 checks basic channels arguments: chan1 mode1 val chan2 mode2 val2 ...
2753 All arguments can be numeric. mode parameter can be a name.
2754 Each group entry must have 3 parameters (chan,mode,val).
2755
2756 @param ac argument count.
2757 @param av argument table.
2758 @param out output stream.
2759 @param name_cde command name prefix.
2760 @return 0 if arguments are valid, -1 otherwise.
2761 */
check_basicchannels_arguments(int ac,char ** av,fluid_ostream_t out,char const * name_cde)2762 static int check_basicchannels_arguments(int ac, char **av,
2763 fluid_ostream_t out, char const *name_cde)
2764 {
2765 static const char too_few_arg_msg[] = "too few argument, chan mode val [chan mode val]...\n";
2766 int i;
2767
2768 for(i = 0; i < ac; i++)
2769 {
2770 /* checks parameters for list entries: chan1 mode1 val chan2 mode2 val2 ...*/
2771 /* all parameters can be numeric. mode parameter can be a name. */
2772 if(!fluid_is_number(av[i]) &&
2773 ((i % 3 != 1) || get_channel_mode_num(av[i]) < 0))
2774 {
2775 fluid_ostream_printf(out, "%s: %s", name_cde, invalid_arg_msg);
2776 return -1;
2777 }
2778 }
2779
2780 if(ac % 3)
2781 {
2782 /* each group entry needs 3 parameters: basicchan,mode,val */
2783 fluid_ostream_printf(out, "%s: channel %d, %s\n", name_cde,
2784 atoi(av[((ac / 3) * 3)]), too_few_arg_msg);
2785 return -1;
2786 }
2787
2788 return 0;
2789 }
2790
2791 /*
2792 checks channels arguments: chan1 chan2 ...
2793 all arguments must be numeric.
2794
2795 @param ac argument count.
2796 @param av argument table.
2797 @param out output stream.
2798 @param name_cde command name prefix.
2799 @return 0 if arguments are valid, -1 otherwise.
2800 */
check_channels_arguments(int ac,char ** av,fluid_ostream_t out,char const * name_cde)2801 static int check_channels_arguments(int ac, char **av,
2802 fluid_ostream_t out, char const *name_cde)
2803 {
2804 int i;
2805
2806 for(i = 0; i < ac; i++)
2807 {
2808 if(!fluid_is_number(av[i]))
2809 {
2810 fluid_ostream_printf(out, "%s: %s", name_cde, invalid_arg_msg);
2811 return -1;
2812 }
2813 }
2814
2815 return 0;
2816 }
2817
2818 /*-----------------------------------------------------------------------------
2819 resetbasicchannels
2820
2821 With no parameters the command resets all basic channels.
2822 Note: Be aware than when a synth instance has no basic channels, all channels
2823 are disabled.
2824 In the intend to get some MIDI channels enabled, use the command setbasicchannels.
2825
2826 resetbasicchannels chan1 [chan2 . . .]
2827 Resets basic channel group chan1, basic channel group chan2 . . .
2828 */
fluid_handle_resetbasicchannels(void * data,int ac,char ** av,fluid_ostream_t out)2829 int fluid_handle_resetbasicchannels(void *data, int ac, char **av,
2830 fluid_ostream_t out)
2831 {
2832 static const char name_cde[] = "resetbasicchannels";
2833 FLUID_ENTRY_COMMAND(data);
2834 fluid_synth_t *synth = handler->synth;
2835
2836 /* checks channels arguments: chan1 chan2 .... */
2837 if(check_channels_arguments(ac, av, out, name_cde) < 0)
2838 {
2839 return -1;
2840 }
2841
2842 if(ac)
2843 {
2844 /* resetbasicchannels chan1 [chan2 . . .] */
2845 int i;
2846
2847 for(i = 0; i < ac; i++)
2848 {
2849 int chan = atoi(av[i]);
2850 int result = fluid_synth_reset_basic_channel(synth, chan);
2851
2852 if(result == FLUID_FAILED)
2853 {
2854 fluid_ostream_printf(out, "%s: channel %3d, %s", name_cde, chan, invalid_arg_msg);
2855 }
2856 }
2857 }
2858 else
2859 {
2860 /* resets all basic channels */
2861 fluid_synth_reset_basic_channel(synth, -1);
2862 }
2863
2864 /* prints result */
2865 return print_basic_channels(synth, out);
2866 }
2867
2868 /*-----------------------------------------------------------------------------
2869 setbasicchannels
2870
2871 With no parameters the command sets one channel basic at basic channel 0 in
2872 Omni On Poly (i.e all the MIDI channels are polyphonic).
2873
2874 setbasicchannels chan1 mode1 nbr1 [chan2 mode2 nbr2] ... ...
2875
2876 Adds basic channel 1 and 2
2877
2878 The command fails if any channels overlaps any existing basic channel groups.
2879 To make room if necessary, existing basic channel groups can be cleared using
2880 resetbasicchannels command.
2881 Mode can be a numeric value or a name:
2882 numeric: 0 to 3 or
2883 name: poly_omnion , mono_omnion, poly_omnioff, mono_omnioff.
2884 */
fluid_handle_setbasicchannels(void * data,int ac,char ** av,fluid_ostream_t out)2885 int fluid_handle_setbasicchannels(void *data, int ac, char **av,
2886 fluid_ostream_t out)
2887 {
2888 static const char name_cde[] = "setbasicchannels";
2889 FLUID_ENTRY_COMMAND(data);
2890 fluid_synth_t *synth = handler->synth;
2891 int result;
2892 int i, n ;
2893
2894 if(!ac)
2895 {
2896 /* sets one default basic channel */
2897 fluid_synth_reset_basic_channel(synth, -1); /* reset all basic channels */
2898 /* sets one basic channel Omni On Poly (i.e all the MIDI channels are polyphonic) */
2899 fluid_synth_set_basic_channel(synth, 0, FLUID_CHANNEL_MODE_OMNION_POLY, 0);
2900 return 0;
2901 }
2902
2903 /* checks parameters: chan1 mode1 val1 chan2 mode2 val2 */
2904 if(check_basicchannels_arguments(ac, av, out, name_cde) < 0)
2905 {
2906 return -1;
2907 }
2908
2909 n = ac / 3; /* number of basic channel information */
2910
2911 for(i = 0; i < n; i++)
2912 {
2913 int basicchan, mode, val;
2914
2915 basicchan = atoi(av[(i * 3)]); /* chan is numeric */
2916
2917 if(fluid_is_number(av[(i * 3) + 1]))
2918 {
2919 /* chan is numeric */
2920 mode = atoi(av[(i * 3) + 1]);
2921 }
2922 else
2923 {
2924 /* mode is a name */
2925 mode = get_channel_mode_num(av[(i * 3) + 1]);
2926 }
2927
2928 val = atoi(av[(i * 3) + 2]); /* val is numeric */
2929
2930 /* changes or sets basic channels */
2931 result = fluid_synth_set_basic_channel(synth, basicchan, mode, val);
2932
2933 if(result == FLUID_FAILED)
2934 {
2935 fluid_ostream_printf(out, "%s: channel %3d, mode %3d, nbr %3d, %s",
2936 name_cde, basicchan, mode, val, invalid_arg_msg);
2937 }
2938 }
2939
2940 return 0;
2941 }
2942
2943 /*
2944 Print result message : "channel:x is outside MIDI channel count(y)"
2945 for commands: channelsmode, portamentomode, legatomode, breathmode,setbreathmode.
2946 @param out output stream.
2947 @param name_cde command name prefix.
2948 @param chan, MIDI channel number x.
2949 @param n_chan, number of MIDI channels y.
2950 */
print_channel_is_outside_count(fluid_ostream_t out,char const * name_cde,int chan,int n_chan)2951 static void print_channel_is_outside_count(fluid_ostream_t out, char const *name_cde,
2952 int chan, int n_chan)
2953 {
2954 fluid_ostream_printf(out, "%s: channel %3d is outside MIDI channel count(%d)\n",
2955 name_cde, chan, n_chan);
2956 }
2957
2958
2959 /*-----------------------------------------------------------------------------
2960 channelsmode
2961 Prints channel mode of all MIDI channels (Poly/mono, Enabled, Basic Channel)
2962 example
2963
2964 Channel , Status , Type , Mode , Nbr of channels
2965 channel: 0, disabled
2966 channel: 1, disabled
2967 channel: 2, disabled
2968 channel: 3, disabled
2969 channel: 4, disabled
2970 channel: 5, enabled, basic channel, mono omni off(3), nbr: 2
2971 channel: 6, enabled, -- , mono , --
2972 channel: 7, disabled
2973 channel: 8, disabled
2974 channel: 9, disabled
2975 channel: 10, enabled, basic channel, mono omni off(3), nbr: 4
2976 channel: 11, enabled, -- , mono , --
2977 channel: 12, enabled, -- , mono , --
2978 channel: 13, enabled, -- , mono , --
2979 channel: 14, disabled
2980 channel: 15, disabled
2981
2982 channelsmode chan1 chan2
2983 Prints only channel mode of MIDI channels chan1, chan2
2984 */
fluid_handle_channelsmode(void * data,int ac,char ** av,fluid_ostream_t out)2985 int fluid_handle_channelsmode(void *data, int ac, char **av,
2986 fluid_ostream_t out)
2987 {
2988 static const char header[] =
2989 "Channel , Status , Type , Mode , Nbr of channels\n";
2990 static const char name_cde[] = "channelsmode";
2991 FLUID_ENTRY_COMMAND(data);
2992 fluid_synth_t *synth = handler->synth;
2993
2994 int i, n, n_chan = synth->midi_channels;
2995
2996 /* checks parameters: chan1 chan2 .... */
2997 if(check_channels_arguments(ac, av, out, name_cde) < 0)
2998 {
2999 return -1;
3000 }
3001
3002 if(ac)
3003 {
3004 n = ac; /* prints ac MIDI channels number */
3005 }
3006 else
3007 {
3008 n = n_chan; /* prints all MIDI channels number */
3009 }
3010
3011 /* prints header */
3012 fluid_ostream_printf(out, header);
3013
3014 for(i = 0; i < n; i++)
3015 {
3016 int basic_chan, mode, val;
3017 int chan = ac ? atoi(av[i]) : i;
3018 int result = fluid_synth_get_basic_channel(synth, chan, &basic_chan, &mode, &val);
3019
3020 if(result == FLUID_OK)
3021 {
3022 if(basic_chan != FLUID_FAILED)
3023 {
3024 /* This channel is enabled */
3025 const char *p_basicchan; /* field basic channel */
3026 const char *p_mode; /* field mode */
3027 const char *p_nbr; /* field Nbr */
3028 static const char blank[] = "--"; /* field empty */
3029
3030 if(chan == basic_chan)
3031 {
3032 /* This channel is a basic channel */
3033 char nbr[10]; /* field Nbr */
3034 FLUID_SNPRINTF(nbr, sizeof(nbr), "nbr:%3d", val);
3035 p_nbr = nbr;
3036 p_mode = mode_name[mode];
3037 p_basicchan = "basic channel";
3038 }
3039 else
3040 {
3041 /* This channel is member of a basic channel group */
3042 p_basicchan = blank;
3043
3044 if(mode & FLUID_CHANNEL_POLY_OFF)
3045 {
3046 p_mode = "mono";
3047 }
3048 else
3049 {
3050 p_mode = "poly";
3051 }
3052
3053 p_nbr = blank;
3054 }
3055
3056 fluid_ostream_printf(out,
3057 "channel:%3d, enabled, %-13s, %-16s, %s\n",
3058 chan,
3059 p_basicchan,
3060 p_mode,
3061 p_nbr);
3062 }
3063 else
3064 {
3065 fluid_ostream_printf(out, "channel:%3d, disabled\n", chan);
3066 }
3067 }
3068 else
3069 {
3070 print_channel_is_outside_count(out, name_cde, chan, n_chan);
3071
3072 if(i < n - 1)
3073 {
3074 fluid_ostream_printf(out, header);
3075 }
3076 }
3077 }
3078
3079 return 0;
3080 }
3081
3082 /** commands mono legato mode ***********************************************/
3083 /*
3084 Prints result message for commands: legatomode, portamentomode.
3085 @param result result from the command (FLUID_OK,FLUID_FAILED).
3086 @param out output stream.
3087 @param name_cde command name prefix.
3088 @param chan MIDI channel number to display.
3089 @param name_mode name of the mode to display.
3090 @param n_chan, number of MIDI channels.
3091 */
print_result_get_channel_mode(int result,fluid_ostream_t out,char const * name_cde,int chan,char const * name_mode,int n_chan)3092 static void print_result_get_channel_mode(int result, fluid_ostream_t out,
3093 char const *name_cde, int chan,
3094 char const *name_mode, int n_chan)
3095 {
3096 if(result == FLUID_OK)
3097 {
3098 fluid_ostream_printf(out, "%s: channel %3d, %s\n", name_cde, chan, name_mode);
3099 }
3100 else
3101 {
3102 print_channel_is_outside_count(out, name_cde, chan, n_chan);
3103 }
3104 }
3105
3106 /*-----------------------------------------------------------------------------
3107 legatomode
3108 Prints legato mode of all MIDI channels
3109 example
3110
3111 channel: 0, (1)multi-retrigger
3112 channel: 1, (0)retrigger
3113 channel: 2, (1)multi-retrigger
3114 .....
3115
3116 legatomode chan1 chan2
3117 Prints only legato mode of MIDI channels chan1, chan2
3118 */
fluid_handle_legatomode(void * data,int ac,char ** av,fluid_ostream_t out)3119 int fluid_handle_legatomode(void *data, int ac, char **av,
3120 fluid_ostream_t out)
3121 {
3122 static const char name_cde[] = "legatomode";
3123 static const char *const name_legato_mode[FLUID_CHANNEL_LEGATO_MODE_LAST] =
3124 { "(0)retrigger", "(1)multi-retrigger" };
3125
3126 FLUID_ENTRY_COMMAND(data);
3127 fluid_synth_t *synth = handler->synth;
3128 int mode = 0;
3129 int i, n, n_chan = synth->midi_channels;
3130
3131 /* checks channels arguments: chan1 chan2 .... */
3132 if(check_channels_arguments(ac, av, out, name_cde) < 0)
3133 {
3134 return -1;
3135 }
3136
3137 if(ac)
3138 {
3139 n = ac; /* prints ac MIDI channels number */
3140 }
3141 else
3142 {
3143 n = n_chan; /* prints all MIDI channels number */
3144 }
3145
3146 /* prints header */
3147 fluid_ostream_printf(out, "Channel , legato mode\n");
3148
3149 for(i = 0; i < n; i++)
3150 {
3151 int chan = ac ? atoi(av[i]) : i;
3152 int result = fluid_synth_get_legato_mode(synth, chan, &mode);
3153 print_result_get_channel_mode(result, out, name_cde, chan, name_legato_mode[mode], n_chan);
3154 }
3155
3156 return 0;
3157 }
3158
3159 /*
3160 checks channels arguments by group:
3161 -example by group of 2 arguments: chan1 val1 chan2 val2 .. ..
3162 -example by group of 4 arguments: chan1 val1 val2 val3 chan2 val1 val2 val3 ....
3163
3164 all arguments must be numeric.
3165
3166 @param ac argument count.
3167 @param av argument table.
3168 @param nbr_arg_group number of arguments by group expected.
3169 @param out output stream.
3170 @param name_cde command name prefix.
3171 @param nbr_arg_group_msg message when the number of argument by group is invalid.
3172 @return 0 if arguments are valid, -1 otherwise.
3173 */
check_channels_group_arguments(int ac,char ** av,int nbr_arg_group,fluid_ostream_t out,char const * name_cde,char const * nbr_arg_group_msg)3174 static int check_channels_group_arguments(int ac, char **av, int nbr_arg_group,
3175 fluid_ostream_t out,
3176 char const *name_cde,
3177 char const *nbr_arg_group_msg
3178 )
3179 {
3180 if(ac)
3181 {
3182 /* checks channels numeric arguments */
3183 if(check_channels_arguments(ac, av, out, name_cde) < 0)
3184 {
3185 return -1;
3186 }
3187
3188 if(ac % nbr_arg_group)
3189 {
3190 /* each group entry needs nbr_arg_group parameters */
3191 fluid_ostream_printf(out, "%s: channel %d, %s\n", name_cde,
3192 atoi(av[((ac / nbr_arg_group) * nbr_arg_group)]),
3193 nbr_arg_group_msg);
3194 return -1;
3195 }
3196 }
3197 else
3198 {
3199 fluid_ostream_printf(out, "%s: %s", name_cde, nbr_arg_group_msg);
3200 return -1;
3201 }
3202
3203 return 0;
3204 }
3205
3206 /*
3207 Prints result message for commands: setlegatomode, setportamentomode.
3208 @param result result from the command (FLUID_FAILED).
3209 @param out output stream.
3210 @param name_cde command name prefix.
3211 @param chan, MIDI channel number to display.
3212 @param mode, mode value to display.
3213 */
print_result_set_channel_mode(int result,fluid_ostream_t out,char const * name_cde,int chan,int mode)3214 static void print_result_set_channel_mode(int result, fluid_ostream_t out,
3215 char const *name_cde,
3216 int chan, int mode)
3217 {
3218 if(result == FLUID_FAILED)
3219 {
3220 fluid_ostream_printf(out, "%s: channel %3d, mode %3d, %s", name_cde, chan, mode, invalid_arg_msg);
3221 }
3222 }
3223
3224 static const char too_few_arg_chan_mode_msg[] = "too few argument, chan mode [chan mode]...\n";
3225 /*-----------------------------------------------------------------------------
3226 setlegatomode chan0 mode1 [chan1 mode0] .. ..
3227
3228 Changes legato mode for channels chan0 and [chan1]
3229 */
fluid_handle_setlegatomode(void * data,int ac,char ** av,fluid_ostream_t out)3230 int fluid_handle_setlegatomode(void *data, int ac, char **av,
3231 fluid_ostream_t out)
3232 {
3233 static const char name_cde[] = "setlegatomode";
3234 FLUID_ENTRY_COMMAND(data);
3235 fluid_synth_t *synth = handler->synth;
3236 int i, n ;
3237
3238 /* checks channels arguments by group of 2: chan1 val1 chan2 val1 .. ..*/
3239 if(check_channels_group_arguments(ac, av, 2, out, name_cde, too_few_arg_chan_mode_msg) < 0)
3240 {
3241 return -1;
3242 }
3243
3244 n = ac / 2; /* number of legato groups information */
3245
3246 for(i = 0; i < n; i++)
3247 {
3248 int chan = atoi(av[(i * 2)]);
3249 int mode = atoi(av[(i * 2) + 1]);
3250 /* changes legato mode */
3251
3252 int result = fluid_synth_set_legato_mode(synth, chan, mode);
3253 print_result_set_channel_mode(result, out, name_cde, chan, mode);
3254 }
3255
3256 return 0;
3257 }
3258
3259 /** commands mono/poly portamento mode **************************************/
3260
3261 /*-----------------------------------------------------------------------------
3262 portamentomode
3263 Prints portamento mode of all MIDI channels
3264 example
3265
3266 channel: 0, (2)staccato only
3267 channel: 1, (1)legato only
3268 channel: 2, (0)each note
3269 channel: 3, (1)legato only
3270 .....
3271
3272 portamentomode chan1 chan2
3273 Prints only portamento mode of MIDI channels chan1, chan2
3274 */
fluid_handle_portamentomode(void * data,int ac,char ** av,fluid_ostream_t out)3275 int fluid_handle_portamentomode(void *data, int ac, char **av,
3276 fluid_ostream_t out)
3277 {
3278 static const char name_cde[] = "portamentomode";
3279 static const char *const name_portamento_mode[FLUID_CHANNEL_PORTAMENTO_MODE_LAST] =
3280 { "(0)each note", "(1)legato only", "(2)staccato only" };
3281
3282 FLUID_ENTRY_COMMAND(data);
3283 fluid_synth_t *synth = handler->synth;
3284 int mode = 0;
3285 int i, n, n_chan = synth->midi_channels;
3286
3287 /* checks channels arguments: chan1 chan2 . . . */
3288 if(check_channels_arguments(ac, av, out, name_cde) < 0)
3289 {
3290 return -1;
3291 }
3292
3293 if(ac)
3294 {
3295 n = ac; /* prints ac MIDI channels number */
3296 }
3297 else
3298 {
3299 n = n_chan; /* prints all MIDI channels number */
3300 }
3301
3302 /* prints header */
3303 fluid_ostream_printf(out, "Channel , portamento mode\n");
3304
3305 for(i = 0; i < n; i++)
3306 {
3307 int chan = ac ? atoi(av[i]) : i;
3308 int result = fluid_synth_get_portamento_mode(synth, chan, &mode);
3309 print_result_get_channel_mode(result, out, name_cde, chan, name_portamento_mode[mode], n_chan);
3310 }
3311
3312 return 0;
3313 }
3314
3315 /*-----------------------------------------------------------------------------
3316 setportamentomode chan1 mode1 [chan2 mode2] .. ..
3317
3318 Changes portamento mode for channels chan1 and [chan2]
3319 */
fluid_handle_setportamentomode(void * data,int ac,char ** av,fluid_ostream_t out)3320 int fluid_handle_setportamentomode(void *data, int ac, char **av,
3321 fluid_ostream_t out)
3322 {
3323 static const char name_cde[] = "setportamentomode";
3324 FLUID_ENTRY_COMMAND(data);
3325 fluid_synth_t *synth = handler->synth;
3326 int i, n ;
3327
3328 /* checks channels arguments by group of 2: chan1 val1 chan2 val1 .. .. */
3329 if(check_channels_group_arguments(ac, av, 2, out, name_cde, too_few_arg_chan_mode_msg) < 0)
3330 {
3331 return -1;
3332 }
3333
3334 n = ac / 2; /* number of portamento groups information */
3335
3336 for(i = 0; i < n; i++)
3337 {
3338 int chan = atoi(av[(i * 2)]);
3339 int mode = atoi(av[(i * 2) + 1]);
3340 /* changes portamento mode */
3341
3342 int result = fluid_synth_set_portamento_mode(synth, chan, mode);
3343 print_result_set_channel_mode(result, out, name_cde, chan, mode);
3344 }
3345
3346 return 0;
3347 }
3348
3349 /** commands mono/poly breath mode *******************************************/
3350 /*-----------------------------------------------------------------------------
3351 breathmode
3352 Prints breath options of all MIDI channels.
3353 poly breath on/off, mono breath on/off, breath sync on/off
3354
3355 example
3356
3357 Channel , poly breath , mono breath , breath sync
3358 channel: 0, off , off , off
3359 channel: 1, off , off , off
3360 channel: 2, off , off , off
3361 .....
3362
3363 breathmode chan1 chan2
3364 Prints only breath mode of MIDI channels chan1, chan2
3365 */
fluid_handle_breathmode(void * data,int ac,char ** av,fluid_ostream_t out)3366 int fluid_handle_breathmode(void *data, int ac, char **av,
3367 fluid_ostream_t out)
3368 {
3369 static const char name_cde[] = "breathmode";
3370 static const char *const header = "Channel , poly breath , mono breath , breath sync\n";
3371 FLUID_ENTRY_COMMAND(data);
3372 fluid_synth_t *synth = handler->synth;
3373 int breathmode;
3374 int i, n, n_chan = synth->midi_channels;
3375
3376 /* checks channels arguments: chan1 chan2 . . . */
3377 if(check_channels_arguments(ac, av, out, name_cde) < 0)
3378 {
3379 return -1;
3380 }
3381
3382 if(ac)
3383 {
3384 n = ac; /* prints ac MIDI channels number */
3385 }
3386 else
3387 {
3388 n = n_chan; /* prints all MIDI channels number */
3389 }
3390
3391 /* prints header */
3392 fluid_ostream_printf(out, header);
3393
3394 for(i = 0; i < n; i++)
3395 {
3396 int chan = ac ? atoi(av[i]) : i;
3397 int result = fluid_synth_get_breath_mode(synth, chan, &breathmode);
3398
3399 if(result == FLUID_OK)
3400 {
3401 static const char on_msg[] = "on";
3402 static const char off_msg[] = "off";
3403 const char *msg_poly_breath, * msg_mono_breath, * msg_breath_sync;
3404
3405 if(breathmode & FLUID_CHANNEL_BREATH_POLY)
3406 {
3407 msg_poly_breath = on_msg;
3408 }
3409 else
3410 {
3411 msg_poly_breath = off_msg;
3412 }
3413
3414 if(breathmode & FLUID_CHANNEL_BREATH_MONO)
3415 {
3416 msg_mono_breath = on_msg;
3417 }
3418 else
3419 {
3420 msg_mono_breath = off_msg;
3421 }
3422
3423 if(breathmode & FLUID_CHANNEL_BREATH_SYNC)
3424 {
3425 msg_breath_sync = on_msg;
3426 }
3427 else
3428 {
3429 msg_breath_sync = off_msg;
3430 }
3431
3432 fluid_ostream_printf(out, "channel:%3d, %-12s, %-12s, %-11s\n", chan,
3433 msg_poly_breath, msg_mono_breath, msg_breath_sync);
3434 }
3435 else
3436 {
3437 print_channel_is_outside_count(out, name_cde, chan, n_chan);
3438
3439 if(i < n - 1)
3440 {
3441 fluid_ostream_printf(out, header);
3442 }
3443 }
3444 }
3445
3446 return 0;
3447 }
3448
3449 /*-----------------------------------------------------------------------------
3450 setbreathmode chan1 poly_breath_mode(1/0) mono_breath_mode(1/0) mono_breath_sync(1/0)
3451
3452 Changes breath options for channels chan1 [chan2] .. ..
3453
3454 Example: setbreathmode 4 0 1 1
3455
3456 Parameter 1 is the channel number (i.e 4).
3457 Parameter 2 is the " Breath modulator " enable/disable for poly mode (i.e disabled).
3458 Parameter 3 is the " Breath modulator " enable/disable for mono mode (i.e enabled).
3459 Parameter 4 is "breath sync noteOn/Off" enable/disable for mono mode only (i.e enabled).
3460
3461 */
fluid_handle_setbreathmode(void * data,int ac,char ** av,fluid_ostream_t out)3462 int fluid_handle_setbreathmode(void *data, int ac, char **av,
3463 fluid_ostream_t out)
3464 {
3465 static const char name_cde[] = "setbreathmode";
3466 static const char too_few_arg_breath_msg[] =
3467 "too few argument:\nchan 1/0(breath poly) 1/0(breath mono) 1/0(breath sync mono)[..]\n";
3468
3469 FLUID_ENTRY_COMMAND(data);
3470 fluid_synth_t *synth = handler->synth;
3471 int i, n, n_chan = synth->midi_channels;
3472
3473 /* checks channels arguments by group of 4:
3474 chan1 val1 val2 val3 chan2 val1 val2 val3 .... ....*/
3475 if(check_channels_group_arguments(ac, av, 4, out, name_cde, too_few_arg_breath_msg) < 0)
3476 {
3477 return -1;
3478 }
3479
3480 n = ac / 4; /* number of breath groups information */
3481
3482 for(i = 0; i < n; i++)
3483 {
3484 int result;
3485 int chan = atoi(av[(i * 4)]);
3486 int poly_breath = atoi(av[(i * 4) + 1]);
3487 int mono_breath = atoi(av[(i * 4) + 2]);
3488 int breath_sync = atoi(av[(i * 4) + 3]);
3489 int breath_infos = 0;
3490
3491 /* changes breath infos */
3492 if(poly_breath)
3493 {
3494 breath_infos |= FLUID_CHANNEL_BREATH_POLY;
3495 }
3496
3497 if(mono_breath)
3498 {
3499 breath_infos |= FLUID_CHANNEL_BREATH_MONO;
3500 }
3501
3502 if(breath_sync)
3503 {
3504 breath_infos |= FLUID_CHANNEL_BREATH_SYNC;
3505 }
3506
3507 result = fluid_synth_set_breath_mode(synth, chan, breath_infos);
3508
3509 if(result == FLUID_FAILED)
3510 {
3511 print_channel_is_outside_count(out, name_cde, chan, n_chan);
3512 }
3513 }
3514
3515 return 0;
3516 }
3517
3518 /** commands for Midi file player ******************************************/
3519
3520 /* check player argument */
player_check_arg(const char * name_cde,int ac,char ** av,fluid_ostream_t out)3521 int player_check_arg(const char *name_cde, int ac, char **av, fluid_ostream_t out)
3522 {
3523 /* check if there is one argument that is a number */
3524 if(ac != 1 || !fluid_is_number(av[0]))
3525 {
3526 fluid_ostream_printf(out, "%s: %s", name_cde, invalid_arg_msg);
3527 return FLUID_FAILED;
3528 }
3529 return FLUID_OK;
3530 }
3531
3532 /* print current position, total ticks, and tempo
3533 * @current_tick position to display. if -1 the function displays the value
3534 * returned by fluid_player_get_current_tick().
3535 */
player_print_position(fluid_player_t * player,int current_tick,fluid_ostream_t out)3536 void player_print_position(fluid_player_t *player, int current_tick, fluid_ostream_t out)
3537 {
3538 int total_ticks = fluid_player_get_total_ticks(player);
3539 int tempo_bpm = fluid_player_get_bpm(player);
3540 if(current_tick == -1)
3541 {
3542 current_tick = fluid_player_get_current_tick(player);
3543 }
3544 fluid_ostream_printf(out, "player current pos:%d, end:%d, bpm:%d\n\n",
3545 current_tick, total_ticks, tempo_bpm);
3546 }
3547
3548 /* player commands enum */
3549 enum
3550 {
3551 PLAYER_LOOP_CDE, /* player_loop num,(Set loop number to num) */
3552 PLAYER_SEEK_CDE, /* player_seek num (Move forward/backward to +/-num ticks) */
3553 PLAYER_STOP_CDE, /* player_stop (Stop playing) */
3554 PLAYER_CONT_CDE, /* player_cont (Continue playing) */
3555 PLAYER_NEXT_CDE, /* player_next (Move to next song) */
3556 PLAYER_START_CDE /* player_start (Move to start of song) */
3557 };
3558
3559 /* Command handler: see player commands enum (above)
3560 * @cmd player commands enumeration value.
3561 */
fluid_handle_player_cde(void * data,int ac,char ** av,fluid_ostream_t out,int cmd)3562 int fluid_handle_player_cde(void *data, int ac, char **av, fluid_ostream_t out, int cmd)
3563 {
3564 FLUID_ENTRY_COMMAND(data);
3565 int arg = 0, was_running;
3566 int seek = -1; /* current seek position in tick */
3567
3568 /* commands name table */
3569 static const char *name_cde[] =
3570 {"player_loop", "player_seek"};
3571
3572 /* get argument for PLAYER_LOOP_CDE, PLAYER_SEEK_CDE */
3573 if(cmd <= PLAYER_SEEK_CDE)
3574 {
3575 /* check argument */
3576 if(player_check_arg(name_cde[cmd], ac, av, out) == FLUID_FAILED)
3577 {
3578 return FLUID_FAILED;
3579 }
3580
3581 arg = atoi(av[0]);
3582 }
3583
3584 if(cmd == PLAYER_LOOP_CDE) /* player_loop */
3585 {
3586 fluid_player_set_loop(handler->player, arg);
3587 return FLUID_OK;
3588 }
3589
3590 if(cmd == PLAYER_CONT_CDE) /* player_cont */
3591 {
3592 fluid_player_play(handler->player);
3593 return FLUID_OK;
3594 }
3595
3596 was_running = fluid_player_get_status(handler->player) == FLUID_PLAYER_PLAYING;
3597 if(was_running)
3598 {
3599 fluid_player_stop(handler->player); /* player_stop */
3600 }
3601
3602 if(cmd != PLAYER_STOP_CDE)
3603 {
3604 /* seek for player_next, player_seek, player_start */
3605 /* set seek to maximum position */
3606 seek = fluid_player_get_total_ticks(handler->player);
3607
3608 if(cmd == PLAYER_SEEK_CDE)
3609 {
3610 /* Move position forward/backward +/- num ticks*/
3611 arg += fluid_player_get_current_tick(handler->player);
3612
3613 /* keep seek between minimum and maximum in current song */
3614 if(arg < 0)
3615 {
3616 seek = 0; /* minimum position */
3617 }
3618 else if(!was_running || arg < seek)
3619 {
3620 seek = arg; /* seek < maximum position */
3621 }
3622 }
3623
3624 if(cmd == PLAYER_START_CDE) /* player_start */
3625 {
3626 seek = 0; /* beginning of the current song */
3627 }
3628
3629 fluid_player_seek(handler->player, seek);
3630 if(was_running)
3631 {
3632 fluid_player_play(handler->player);
3633 }
3634 }
3635 /* display position */
3636 player_print_position(handler->player, seek, out);
3637
3638 return FLUID_OK;
3639 }
3640
3641 /* Command handler for "player_start" command */
fluid_handle_player_start(void * data,int ac,char ** av,fluid_ostream_t out)3642 int fluid_handle_player_start(void *data, int ac, char **av, fluid_ostream_t out)
3643 {
3644 return fluid_handle_player_cde(data, ac, av, out, PLAYER_START_CDE);
3645 }
3646
3647 /* Command handler for "player_stop" command */
fluid_handle_player_stop(void * data,int ac,char ** av,fluid_ostream_t out)3648 int fluid_handle_player_stop(void *data, int ac, char **av, fluid_ostream_t out)
3649 {
3650 return fluid_handle_player_cde(data, ac, av, out, PLAYER_STOP_CDE);
3651 }
3652
3653 /* Command handler for "player_continue" command */
fluid_handle_player_continue(void * data,int ac,char ** av,fluid_ostream_t out)3654 int fluid_handle_player_continue(void *data, int ac, char **av, fluid_ostream_t out)
3655 {
3656 return fluid_handle_player_cde(data, ac, av, out, PLAYER_CONT_CDE);
3657 }
3658 /* Command handler for "player_seek" command */
fluid_handle_player_seek(void * data,int ac,char ** av,fluid_ostream_t out)3659 int fluid_handle_player_seek(void *data, int ac, char **av, fluid_ostream_t out)
3660 {
3661 return fluid_handle_player_cde(data, ac, av, out, PLAYER_SEEK_CDE);
3662 }
3663
3664 /* Command handler for "player_next" command */
fluid_handle_player_next_song(void * data,int ac,char ** av,fluid_ostream_t out)3665 int fluid_handle_player_next_song(void *data, int ac, char **av, fluid_ostream_t out)
3666 {
3667 return fluid_handle_player_cde(data, ac, av, out, PLAYER_NEXT_CDE);
3668 }
3669
3670 /* Command handler for "player_loop" command */
fluid_handle_player_loop(void * data,int ac,char ** av,fluid_ostream_t out)3671 int fluid_handle_player_loop(void *data, int ac, char **av, fluid_ostream_t out)
3672 {
3673 return fluid_handle_player_cde(data, ac, av, out, PLAYER_LOOP_CDE);
3674 }
3675
3676 /* Command handler for player tempo commands:
3677 player_tempo_int [mul], set the player to internal tempo multiplied by mul
3678 player_tempo_bpm bpm, set the player to external tempo in beat per minute.
3679 examples:
3680 player_tempo_int set the player to internal tempo with a default
3681 multiplier set to 1.0.
3682
3683 player_tempo_int 0.5 set the player to internal tempo divided by 2.
3684
3685 player_tempo_bpm 75, set the player to external tempo of 75 beats per minute.
3686 */
fluid_handle_player_tempo_cde(void * data,int ac,char ** av,fluid_ostream_t out,int cmd)3687 int fluid_handle_player_tempo_cde(void *data, int ac, char **av, fluid_ostream_t out, int cmd)
3688 {
3689 FLUID_ENTRY_COMMAND(data);
3690 /* default multiplier for player_tempo_int command without argument*/
3691 double arg = 1.0F;
3692
3693 /* commands name table */
3694 static const char *name_cde[] =
3695 {"player_tempo_int", "player_tempo_bpm"};
3696
3697 static const struct /* argument infos */
3698 {
3699 double min;
3700 double max;
3701 char *name;
3702 }argument[2] = {{0.1F, 10.F, "multiplier"}, {1.0F, 600.0F, "bpm"}};
3703
3704 /* get argument for: player_tempo_int [mul], player_tempo_bpm bpm */
3705 if((cmd == FLUID_PLAYER_TEMPO_EXTERNAL_BPM) || ac)
3706 {
3707 /* check argument presence */
3708 if(player_check_arg(name_cde[cmd], ac, av, out) == FLUID_FAILED)
3709 {
3710 return FLUID_FAILED;
3711 }
3712
3713 arg = atof(av[0]);
3714
3715 /* check if argument is in valid range */
3716 if(arg < argument[cmd].min || arg > argument[cmd].max)
3717 {
3718 fluid_ostream_printf(out, "%s: %s %f must be in range [%f..%f]\n",
3719 name_cde[cmd], argument[cmd].name, arg,
3720 argument[cmd].min, argument[cmd].max);
3721 return FLUID_FAILED;
3722 }
3723 }
3724
3725 fluid_player_set_tempo(handler->player, cmd, arg);
3726
3727 return FLUID_OK;
3728 }
3729
3730 /* Command handler for "player_tempo_int [mul]" command */
fluid_handle_player_tempo_int(void * data,int ac,char ** av,fluid_ostream_t out)3731 int fluid_handle_player_tempo_int(void *data, int ac, char **av, fluid_ostream_t out)
3732 {
3733 return fluid_handle_player_tempo_cde(data, ac, av, out, FLUID_PLAYER_TEMPO_INTERNAL);
3734 }
3735
3736 /* Command handler for "player_tempo_bpm bmp" command */
fluid_handle_player_tempo_bpm(void * data,int ac,char ** av,fluid_ostream_t out)3737 int fluid_handle_player_tempo_bpm(void *data, int ac, char **av, fluid_ostream_t out)
3738 {
3739 return fluid_handle_player_tempo_cde(data, ac, av, out, FLUID_PLAYER_TEMPO_EXTERNAL_BPM);
3740 }
3741
3742 #ifdef LADSPA
3743
3744 #define CHECK_LADSPA_ENABLED(_fx, _out) \
3745 if (_fx == NULL) \
3746 { \
3747 fluid_ostream_printf(_out, "LADSPA is not enabled.\n"); \
3748 return FLUID_FAILED; \
3749 }
3750
3751 #define CHECK_LADSPA_INACTIVE(_fx, _out) \
3752 if (fluid_ladspa_is_active(_fx)) \
3753 { \
3754 fluid_ostream_printf(_out, "LADSPA already started.\n"); \
3755 return FLUID_FAILED; \
3756 }
3757
3758 #define LADSPA_ERR_LEN (1024)
3759
3760 /**
3761 * ladspa_start
3762 */
fluid_handle_ladspa_start(void * data,int ac,char ** av,fluid_ostream_t out)3763 int fluid_handle_ladspa_start(void *data, int ac, char **av, fluid_ostream_t out)
3764 {
3765 FLUID_ENTRY_COMMAND(data);
3766 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3767 char error[LADSPA_ERR_LEN];
3768
3769 if(ac != 0)
3770 {
3771 fluid_ostream_printf(out, "ladspa_start does not accept any arguments\n");
3772 return FLUID_FAILED;
3773 }
3774
3775 CHECK_LADSPA_ENABLED(fx, out);
3776 CHECK_LADSPA_INACTIVE(fx, out);
3777
3778 if(fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
3779 {
3780 fluid_ostream_printf(out, "Unable to start LADSPA: %s", error);
3781 return FLUID_FAILED;
3782 }
3783
3784 if(fluid_ladspa_activate(fx) != FLUID_OK)
3785 {
3786 fluid_ostream_printf(out, "Unable to start LADSPA.\n");
3787 return FLUID_FAILED;
3788 }
3789
3790 return FLUID_OK;
3791 }
3792
3793 /**
3794 * ladspa_stop
3795 */
fluid_handle_ladspa_stop(void * data,int ac,char ** av,fluid_ostream_t out)3796 int fluid_handle_ladspa_stop(void *data, int ac, char **av, fluid_ostream_t out)
3797 {
3798 FLUID_ENTRY_COMMAND(data);
3799 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3800
3801 if(ac != 0)
3802 {
3803 fluid_ostream_printf(out, "ladspa_stop does not accept any arguments\n");
3804 return FLUID_FAILED;
3805 }
3806
3807 CHECK_LADSPA_ENABLED(fx, out);
3808
3809 if(!fluid_ladspa_is_active(fx))
3810 {
3811 fluid_ostream_printf(out, "LADSPA has not been started.\n");
3812 }
3813
3814 if(fluid_ladspa_deactivate(fx) != FLUID_OK)
3815 {
3816 fluid_ostream_printf(out, "Unable to stop LADSPA.\n");
3817 return FLUID_FAILED;
3818 }
3819
3820 return FLUID_OK;
3821 }
3822
3823 /**
3824 * ladspa_reset
3825 */
fluid_handle_ladspa_reset(void * data,int ac,char ** av,fluid_ostream_t out)3826 int fluid_handle_ladspa_reset(void *data, int ac, char **av, fluid_ostream_t out)
3827 {
3828 FLUID_ENTRY_COMMAND(data);
3829 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3830
3831 if(ac != 0)
3832 {
3833 fluid_ostream_printf(out, "ladspa_reset does not accept any arguments\n");
3834 return FLUID_FAILED;
3835 }
3836
3837 CHECK_LADSPA_ENABLED(fx, out);
3838
3839 fluid_ladspa_reset(fx);
3840
3841 return FLUID_OK;
3842 }
3843
3844 /**
3845 * ladspa_check
3846 */
fluid_handle_ladspa_check(void * data,int ac,char ** av,fluid_ostream_t out)3847 int fluid_handle_ladspa_check(void *data, int ac, char **av, fluid_ostream_t out)
3848 {
3849 FLUID_ENTRY_COMMAND(data);
3850 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3851 char error[LADSPA_ERR_LEN];
3852
3853 if(ac != 0)
3854 {
3855 fluid_ostream_printf(out, "ladspa_reset does not accept any arguments\n");
3856 return FLUID_FAILED;
3857 }
3858
3859 CHECK_LADSPA_ENABLED(fx, out);
3860
3861 if(fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
3862 {
3863 fluid_ostream_printf(out, "LADSPA check failed: %s", error);
3864 return FLUID_FAILED;
3865 }
3866
3867 fluid_ostream_printf(out, "LADSPA check ok\n");
3868
3869 return FLUID_OK;
3870 }
3871
3872 /**
3873 * ladspa_set <effect> <port> <value>
3874 */
fluid_handle_ladspa_set(void * data,int ac,char ** av,fluid_ostream_t out)3875 int fluid_handle_ladspa_set(void *data, int ac, char **av, fluid_ostream_t out)
3876 {
3877 FLUID_ENTRY_COMMAND(data);
3878 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3879
3880 if(ac != 3)
3881 {
3882 fluid_ostream_printf(out, "ladspa_set needs three arguments: <effect> <port> <value>\n");
3883 return FLUID_FAILED;
3884 };
3885
3886 CHECK_LADSPA_ENABLED(fx, out);
3887
3888 /* Redundant check, just here to give a more detailed error message */
3889 if(!fluid_ladspa_effect_port_exists(fx, av[0], av[1]))
3890 {
3891 fluid_ostream_printf(out, "Port '%s' not found on effect '%s'\n", av[1], av[0]);
3892 return FLUID_FAILED;
3893 }
3894
3895 if(fluid_ladspa_effect_set_control(fx, av[0], av[1], atof(av[2])) != FLUID_OK)
3896 {
3897 fluid_ostream_printf(out, "Failed to set port '%s' on effect '%s', "
3898 "maybe it is not a control port?\n", av[1], av[0]);
3899 return FLUID_FAILED;
3900 }
3901
3902 return FLUID_OK;
3903 };
3904
3905 /**
3906 * ladspa_buffer <name>
3907 */
fluid_handle_ladspa_buffer(void * data,int ac,char ** av,fluid_ostream_t out)3908 int fluid_handle_ladspa_buffer(void *data, int ac, char **av, fluid_ostream_t out)
3909 {
3910 FLUID_ENTRY_COMMAND(data);
3911 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3912
3913 if(ac != 1)
3914 {
3915 fluid_ostream_printf(out, "ladspa_buffer needs one argument: <name>\n");
3916 return FLUID_FAILED;
3917 };
3918
3919 CHECK_LADSPA_ENABLED(fx, out);
3920
3921 CHECK_LADSPA_INACTIVE(fx, out);
3922
3923 if(fluid_ladspa_add_buffer(fx, av[0]) != FLUID_OK)
3924 {
3925 fluid_ostream_printf(out, "Failed to add buffer\n");
3926 return FLUID_FAILED;
3927 }
3928
3929 return FLUID_OK;
3930 };
3931
3932 /**
3933 * ladspa_effect <name> <library> [plugin] [--mix [gain]]
3934 */
fluid_handle_ladspa_effect(void * data,int ac,char ** av,fluid_ostream_t out)3935 int fluid_handle_ladspa_effect(void *data, int ac, char **av, fluid_ostream_t out)
3936 {
3937 FLUID_ENTRY_COMMAND(data);
3938 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
3939 char *plugin_name = NULL;
3940 int pos;
3941 int mix = FALSE;
3942 float gain = 1.0f;
3943
3944 if(ac < 2 || ac > 5)
3945 {
3946 fluid_ostream_printf(out, "ladspa_effect invalid arguments: "
3947 "<name> <library> [plugin] [--mix [gain]]\n");
3948 return FLUID_FAILED;
3949 }
3950
3951 pos = 2;
3952
3953 /* If the first optional arg is not --mix, then it must be the plugin label */
3954 if((pos < ac) && (FLUID_STRCMP(av[pos], "--mix") != 0))
3955 {
3956 plugin_name = av[pos];
3957 pos++;
3958 }
3959
3960 /* If this optional arg is --mix and there's an argument after it, that that
3961 * must be the gain */
3962 if((pos < ac) && (FLUID_STRCMP(av[pos], "--mix") == 0))
3963 {
3964 mix = TRUE;
3965
3966 if(pos + 1 < ac)
3967 {
3968 gain = atof(av[pos + 1]);
3969 }
3970 }
3971
3972 CHECK_LADSPA_ENABLED(fx, out);
3973 CHECK_LADSPA_INACTIVE(fx, out);
3974
3975 if(fluid_ladspa_add_effect(fx, av[0], av[1], plugin_name) != FLUID_OK)
3976 {
3977 fluid_ostream_printf(out, "Failed to create effect\n");
3978 return FLUID_FAILED;
3979 }
3980
3981 if(mix)
3982 {
3983 if(!fluid_ladspa_effect_can_mix(fx, av[0]))
3984 {
3985 fluid_ostream_printf(out, "Effect '%s' does not support --mix mode\n", av[0]);
3986 return FLUID_FAILED;
3987 }
3988
3989 if(fluid_ladspa_effect_set_mix(fx, av[0], mix, gain) != FLUID_OK)
3990 {
3991 fluid_ostream_printf(out, "Failed to set --mix mode\n");
3992 return FLUID_FAILED;
3993 }
3994 }
3995
3996 return FLUID_OK;
3997 }
3998
3999 /*
4000 * ladspa_link <effect> <port> <buffer or host port>
4001 */
fluid_handle_ladspa_link(void * data,int ac,char ** av,fluid_ostream_t out)4002 int fluid_handle_ladspa_link(void *data, int ac, char **av, fluid_ostream_t out)
4003 {
4004 FLUID_ENTRY_COMMAND(data);
4005 fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
4006
4007 if(ac != 3)
4008 {
4009 fluid_ostream_printf(out, "ladspa_link needs 3 arguments: "
4010 "<effect> <port> <buffer or host name>\n");
4011 return FLUID_FAILED;
4012 }
4013
4014 CHECK_LADSPA_ENABLED(fx, out);
4015 CHECK_LADSPA_INACTIVE(fx, out);
4016
4017 if(!fluid_ladspa_effect_port_exists(fx, av[0], av[1]))
4018 {
4019 fluid_ostream_printf(out, "Port '%s' not found on effect '%s'\n", av[1], av[0]);
4020 return FLUID_FAILED;
4021 }
4022
4023 if(!fluid_ladspa_host_port_exists(fx, av[2]) && !fluid_ladspa_buffer_exists(fx, av[2]))
4024 {
4025 fluid_ostream_printf(out, "Host port or buffer '%s' not found.\n", av[2]);
4026 return FLUID_FAILED;
4027 }
4028
4029 if(fluid_ladspa_effect_link(fx, av[0], av[1], av[2]) != FLUID_OK)
4030 {
4031 fluid_ostream_printf(out, "Failed to link port\n");
4032 return FLUID_FAILED;
4033 }
4034
4035 return FLUID_OK;
4036 }
4037
4038 #endif /* LADSPA */
4039
4040 #if WITH_PROFILING
4041 /*
4042 * Locks profile command to prevent simultaneous changes by an other shell
4043 * (may be a server shell (tcp)).
4044 *
4045 * @return FLUID_OK if success , otherwise FLUID_FAILED.
4046 */
fluid_profile_lock_command(fluid_ostream_t out)4047 static int fluid_profile_lock_command(fluid_ostream_t out)
4048 {
4049 if(! fluid_atomic_int_compare_and_exchange(&fluid_profile_lock, 0, 1))
4050 {
4051 fluid_ostream_printf(out,
4052 "profile command in use in another shell. Try later!\n");
4053 return FLUID_FAILED;
4054 }
4055
4056 return FLUID_OK;
4057 }
4058
4059 /*
4060 * Unlocks profile command.
4061 */
fluid_profile_unlock_command(void)4062 static void fluid_profile_unlock_command(void)
4063 {
4064 fluid_atomic_int_set(&fluid_profile_lock, 0);
4065 }
4066
4067 /*
4068 * command: profile
4069 *
4070 * Prints default parameters used by prof_start command.
4071 *
4072 * Notes:0, bank:0, prog:16, print:0, n_prof:1, dur:500 ms.
4073 *
4074 * @return FLUID_OK if success , otherwise FLUID_FAILED.
4075 */
4076 int
fluid_handle_profile(void * data,int ac,char ** av,fluid_ostream_t out)4077 fluid_handle_profile(void *data, int ac, char **av, fluid_ostream_t out)
4078 {
4079 /* locks to prevent simultaneous changes by an other shell */
4080 /* (may be a server shell (tcp)) */
4081 if(fluid_profile_lock_command(out) == FLUID_FAILED)
4082 {
4083 return FLUID_FAILED;
4084 }
4085
4086 /* prints default parameters */
4087 fluid_ostream_printf(out,
4088 " Notes:%d, bank:%d, prog:%d, print:%d, n_prof:%d, dur:%d ms\n",
4089 fluid_profile_notes, fluid_profile_bank, fluid_profile_prog,
4090 fluid_profile_print,
4091 fluid_profile_n_prof, fluid_profile_dur);
4092
4093 /* unlocks */
4094 fluid_profile_unlock_command();
4095 return FLUID_OK;
4096 }
4097
4098 /*
4099 * command: prof_set_notes nbr [bank prog]
4100 *
4101 * Sets notes number generated by prof_start command.
4102 *
4103 * nbr: notes numbers (generated during command "prof_start").
4104 * bank, prog: preset bank and program number (default value if not specified).
4105 *
4106 * @return FLUID_OK if success , otherwise FLUID_FAILED.
4107 */
4108 int
fluid_handle_prof_set_notes(void * data,int ac,char ** av,fluid_ostream_t out)4109 fluid_handle_prof_set_notes(void *data, int ac, char **av, fluid_ostream_t out)
4110 {
4111 unsigned short nbr; /* previous parameters */
4112 unsigned char bank, prog; /* previous parameters */
4113 int r; /* return */
4114
4115 /* locks to prevent simultaneous changes by an other shell */
4116 if(fluid_profile_lock_command(out) == FLUID_FAILED)
4117 {
4118 return FLUID_FAILED;
4119 }
4120
4121 /* checks parameters */
4122 if(ac < 1)
4123 {
4124 fluid_ostream_printf(out, "profile_notes: too few arguments\n");
4125 fluid_profile_unlock_command();
4126 return FLUID_FAILED;
4127 }
4128
4129 /* gets default parameters */
4130 nbr = fluid_profile_notes, bank = fluid_profile_bank;
4131 prog = fluid_profile_prog;
4132
4133 r = fluid_is_number(av[0]);
4134
4135 if(r)
4136 {
4137 /* checks nbr */
4138 nbr = atoi(av[0]); /* get nbr parameter */
4139
4140 if(ac >= 2)
4141 {
4142 /* [bank prog] are optional */
4143 if(ac >= 3)
4144 {
4145 r = fluid_is_number(av[1]) && fluid_is_number(av[2]);
4146
4147 if(r)
4148 {
4149 bank = atoi(av[1]); /* gets bank parameter */
4150 prog = atoi(av[2]); /* gets prog parameter */
4151 }
4152 }
4153 else
4154 {
4155 /* prog is needed */
4156 fluid_ostream_printf(out, "profile_set_notes: too few arguments\n");
4157 fluid_profile_unlock_command();
4158 return FLUID_FAILED;
4159 }
4160 }
4161 }
4162
4163 if(!r)
4164 {
4165 fluid_ostream_printf(out, "profile_set_notes: invalid argument\n");
4166 fluid_profile_unlock_command();
4167 return FLUID_FAILED;
4168 }
4169
4170 /* Saves new parameters */
4171 fluid_profile_notes = nbr;
4172 fluid_profile_bank = bank;
4173 fluid_profile_prog = prog;
4174
4175 /* unlocks */
4176 fluid_profile_unlock_command();
4177 return FLUID_OK;
4178 }
4179
4180 /*
4181 * command: prof_set_print mode
4182 *
4183 * The command sets the print mode.
4184 *
4185 * mode: result print mode(used by prof_start").
4186 * 0: simple printing, >0: full printing
4187 *
4188 * @return FLUID_OK if success , otherwise FLUID_FAILED.
4189 */
4190 int
fluid_handle_prof_set_print(void * data,int ac,char ** av,fluid_ostream_t out)4191 fluid_handle_prof_set_print(void *data, int ac, char **av, fluid_ostream_t out)
4192 {
4193 int r;
4194
4195 /* locks to prevent simultaneous changes by an other shell */
4196 if(fluid_profile_lock_command(out) == FLUID_FAILED)
4197 {
4198 return FLUID_FAILED;
4199 }
4200
4201 /* checks parameters */
4202 if(ac < 1)
4203 {
4204 fluid_ostream_printf(out, "profile_set_print: too few arguments\n");
4205 fluid_profile_unlock_command();
4206 return FLUID_FAILED;
4207 }
4208
4209 /* gets parameters */
4210 if(fluid_is_number(av[0]))
4211 {
4212 /* checks and gets mode */
4213 fluid_profile_print = atoi(av[0]); /* gets and saves mode parameter */
4214 r = FLUID_OK;
4215 }
4216 else
4217 {
4218 fluid_ostream_printf(out, "profile_set_print: invalid argument\n");
4219 r = FLUID_FAILED;
4220 }
4221
4222 /* unlocks */
4223 fluid_profile_unlock_command();
4224 return r;
4225 }
4226
4227 /*
4228 * Generates simultaneous notes for precise profiling.
4229 *
4230 * @param synth, synthesizer instance.
4231 * @param notes, the number of notes to generate.
4232 * @param bank, prog, soundfont bank preset number used.
4233 * @param out, stream output device.
4234 * @return the number of voices generated. It can be lower than notes number
4235 * when the preset have instrument only on few key range.
4236 */
fluid_profile_send_notes(fluid_synth_t * synth,int notes,int bank,int prog,fluid_ostream_t out)4237 static unsigned short fluid_profile_send_notes(fluid_synth_t *synth, int notes,
4238 int bank, int prog,
4239 fluid_ostream_t out)
4240 {
4241 int n; /* number of notes generated */
4242 int n_voices, n_actives = 0; /* Maximum voices, voices generated */
4243 int n_chan, chan, key ;
4244 /* MIDI channels count and maximum polyphony */
4245 n_chan = fluid_synth_count_midi_channels(synth); /* channels count */
4246 n_voices = fluid_synth_get_polyphony(synth); /* maximum voices */
4247 /* */
4248 fluid_ostream_printf(out, "Generating %d notes, ", notes);
4249
4250 for(n = 0, key = FLUID_PROFILE_LAST_KEY + 1, chan = -1; n < notes; n++, key++)
4251 {
4252 if(key > FLUID_PROFILE_LAST_KEY)
4253 {
4254 /* next channel */
4255 chan++;
4256
4257 if(chan >= n_chan)
4258 {
4259 break; /* stops generation */
4260 }
4261
4262 /* select preset */
4263 fluid_synth_bank_select(synth, chan, bank);
4264 fluid_synth_program_change(synth, chan, prog);
4265 key = FLUID_PROFILE_FIRST_KEY;
4266 }
4267
4268 fluid_synth_noteon(synth, chan, key, FLUID_PROFILE_DEFAULT_VEL);
4269 n_actives = fluid_synth_get_active_voice_count(synth); /* running voices */
4270
4271 if(n_actives >= n_voices)
4272 {
4273 fluid_ostream_printf(out, "max polyphony reached:%d, ", n_voices);
4274 break; /* stops notes generation */
4275 }
4276 }
4277
4278 fluid_ostream_printf(out, "generated voices:%d\n", n_actives);
4279 return n_actives;
4280 }
4281
4282 /*
4283 * command: prof_start [n_prof [dur] ]
4284 *
4285 * Starts n_prof measures of dur duration(ms) each.
4286 *
4287 * n_prof number of measures (default value if not specified).
4288 * dur: measure duration (ms) (default value if not specified).
4289 *
4290 * The result of each measure is displayed.
4291 *
4292 * Note: The command ends when the last measure ends or when the user
4293 * cancels the command using <ENTER> key (cancellation using <ENTER>
4294 * is implemented using FLUID_PROFILE_CANCEL macro in fluid_sys.h).
4295 *
4296 * @return FLUID_OK if success , otherwise FLUID_FAILED.
4297 */
4298 int
fluid_handle_prof_start(void * data,int ac,char ** av,fluid_ostream_t out)4299 fluid_handle_prof_start(void *data, int ac, char **av, fluid_ostream_t out)
4300 {
4301 FLUID_ENTRY_COMMAND(data);
4302 fluid_synth_t *synth = handler->synth;
4303
4304 unsigned short n_prof, n, dur; /* previous parameters */
4305 unsigned int total_dur, rem_dur; /* total and remainder duration (ms) */
4306 unsigned short notes; /* notes number to generate */
4307 int n_actives = 0; /* actives voices */
4308 float gain; /* current gain */
4309 int r = 1; /* checking parameter result */
4310
4311 /* Locks to prevent simultaneous command by an other shell */
4312 if(fluid_profile_lock_command(out) == FLUID_FAILED)
4313 {
4314 return FLUID_FAILED;
4315 }
4316
4317 /* Gets previous parameters values */
4318 n_prof = fluid_profile_n_prof; /* number of measuses */
4319 dur = fluid_profile_dur; /* duration of one measure (ms) */
4320
4321 /* check parameters */
4322 if(ac >= 1)
4323 {
4324 r = fluid_is_number(av[0]);
4325
4326 if(r)
4327 {
4328 n_prof = atoi(av[0]); /* gets n_prof parameter */
4329
4330 if(ac >= 2)
4331 {
4332 r = fluid_is_number(av[1]);
4333
4334 if(r)
4335 {
4336 dur = atoi(av[1]);/* gets dur parameter */
4337 }
4338 }
4339 }
4340 }
4341
4342 if(!r || n_prof < 1 || dur < 1)
4343 {
4344 fluid_ostream_printf(out, "profile_start: invalid argument\n");
4345 fluid_profile_unlock_command();
4346 return FLUID_FAILED;
4347 }
4348
4349 /* Saves new parameters */
4350 fluid_profile_n_prof = n_prof;
4351 fluid_profile_dur = dur;
4352
4353 /* Saves current gain */
4354 gain = fluid_synth_get_gain(synth);
4355
4356 /* Generates notes if any */
4357 notes = fluid_profile_notes;
4358
4359 if(notes)
4360 {
4361 /* checks if the synth is playing */
4362 /* Warn the user */
4363 if(fluid_synth_get_active_voice_count(synth))
4364 {
4365 fluid_ostream_printf(out,
4366 "Warning: can't generate notes, please stop any playing\n");
4367 }
4368 else
4369 {
4370 float send_gain;
4371 /* sets low gain before sending notes */
4372 fluid_synth_set_gain(synth, 0.01);
4373 /* sends notes */
4374 n_actives = fluid_profile_send_notes(synth, notes, fluid_profile_bank,
4375 fluid_profile_prog, out);
4376 /* compensates gain to avoid a loud sound */
4377 send_gain = 1.0 * pow(10, (n_actives * FLUID_PROFILE_VOICE_ATTEN) / 20);
4378 fluid_synth_set_gain(synth, send_gain);
4379
4380 /* Before starting profiling immediately we wait to ensures that voices are
4381 currently synthesized by audio rendering API. This ensure that macro
4382 probes will register the expected number of actives voices.
4383 */
4384 fluid_msleep(200); /* wait 200 ms */
4385 }
4386 }
4387
4388 /* Starts - waits - prints n_prof measures */
4389 fluid_ostream_printf(out, "Number of measures(n_prof):%d, duration of one measure(dur):%dms\n",
4390 n_prof, dur);
4391
4392 /* Clears any previous <ENTER> pending key */
4393 fluid_profile_is_cancel_req();
4394
4395 total_dur = rem_dur = n_prof * dur;
4396
4397 for(n = 0 ; n < n_prof; rem_dur -= dur, n++)
4398 {
4399 unsigned int end_ticks;/* ending position (in ticks) */
4400 unsigned int tm, ts, rm, rs;
4401 int status;
4402 ts = total_dur / 1000;
4403 tm = ts / 60;
4404 ts = ts % 60; /* total minutes and seconds */
4405
4406 rs = rem_dur / 1000;
4407 rm = rs / 60;
4408 rs = rs % 60; /* remainder minutes and seconds */
4409
4410 /* Prints total and remainder duration */
4411 #ifdef FLUID_PROFILE_CANCEL
4412 fluid_ostream_printf(out,
4413 "\nProfiling time(mm:ss): Total=%d:%d Remainder=%d:%d, press <ENTER> to cancel\n",
4414 tm, ts, rm, rs);
4415 #else
4416 fluid_ostream_printf(out,
4417 "\nProfiling time(mm:ss): Total=%d:%d Remainder=%d:%d\n",
4418 tm, ts, rm, rs);
4419 #endif
4420
4421 /* converts duration(ms) in end position in ticks. */
4422 end_ticks = fluid_atomic_int_get(&synth->ticks_since_start) +
4423 dur * synth->sample_rate / 1000;
4424 /* requests to start the measurement in audio rendering API */
4425 fluid_profile_start_stop(end_ticks, n);
4426
4427 /* waits while running */
4428 do
4429 {
4430 /* passive waiting */
4431 fluid_msleep(500); /* wait 500 ms */
4432 status = fluid_profile_get_status();
4433 }
4434 while(status == PROFILE_RUNNING);
4435
4436 /* checks if data are ready */
4437 if(status == PROFILE_READY)
4438 {
4439 /* profiling data are ready, prints profile data */
4440 fluid_profiling_print_data(synth->sample_rate, out);
4441 }
4442 /* checks if the measurement has been cancelled */
4443 else if(status == PROFILE_CANCELED || status == PROFILE_STOP)
4444 {
4445 fluid_ostream_printf(out, "Profiling cancelled.\n");
4446 break; /* cancel the command */
4447 }
4448 }
4449
4450 /* Stops voices if any had been generated */
4451 if(n_actives)
4452 {
4453 fluid_ostream_printf(out, "Stopping %d voices...", n_actives);
4454 fluid_synth_system_reset(synth);
4455
4456 /* waits until all voices become inactives */
4457 do
4458 {
4459 fluid_msleep(10); /* wait 10 ms */
4460 n_actives = fluid_synth_get_active_voice_count(synth);
4461 }
4462 while(n_actives);
4463
4464 fluid_ostream_printf(out, "voices stopped.\n");
4465 }
4466
4467 /* Restores initial gain */
4468 fluid_synth_set_gain(synth, gain);
4469
4470 /* Unlocks */
4471 fluid_profile_unlock_command();
4472 return FLUID_OK;
4473 }
4474 #endif /* WITH_PROFILING */
4475
4476 int
fluid_is_number(char * a)4477 fluid_is_number(char *a)
4478 {
4479 while(*a != 0)
4480 {
4481 if(((*a < '0') || (*a > '9')) && (*a != '-') && (*a != '+') && (*a != '.'))
4482 {
4483 return FALSE;
4484 }
4485
4486 a++;
4487 }
4488
4489 return TRUE;
4490 }
4491
4492 char *
fluid_expand_path(char * path,char * new_path,int len)4493 fluid_expand_path(char *path, char *new_path, int len)
4494 {
4495 #if defined(WIN32) || defined(MACOS9)
4496 FLUID_SNPRINTF(new_path, len - 1, "%s", path);
4497 #else
4498
4499 if((path[0] == '~') && (path[1] == '/'))
4500 {
4501 char *home = getenv("HOME");
4502
4503 if(home == NULL)
4504 {
4505 FLUID_SNPRINTF(new_path, len - 1, "%s", path);
4506 }
4507 else
4508 {
4509 FLUID_SNPRINTF(new_path, len - 1, "%s%s", home, &path[1]);
4510 }
4511 }
4512 else
4513 {
4514 FLUID_SNPRINTF(new_path, len - 1, "%s", path);
4515 }
4516
4517 #endif
4518
4519 new_path[len - 1] = 0;
4520 return new_path;
4521 }
4522
4523
4524
4525 /*
4526 * Command
4527 */
4528
fluid_cmd_copy(const fluid_cmd_t * cmd)4529 fluid_cmd_t *fluid_cmd_copy(const fluid_cmd_t *cmd)
4530 {
4531 fluid_cmd_t *copy = FLUID_NEW(fluid_cmd_t);
4532
4533 if(copy == NULL)
4534 {
4535 FLUID_LOG(FLUID_PANIC, "Out of memory");
4536 return NULL;
4537 }
4538
4539 copy->name = FLUID_STRDUP(cmd->name);
4540 copy->topic = FLUID_STRDUP(cmd->topic);
4541 copy->help = FLUID_STRDUP(cmd->help);
4542 copy->handler = cmd->handler;
4543 return copy;
4544 }
4545
delete_fluid_cmd(fluid_cmd_t * cmd)4546 void delete_fluid_cmd(fluid_cmd_t *cmd)
4547 {
4548 fluid_return_if_fail(cmd != NULL);
4549 FLUID_FREE(cmd->name);
4550 FLUID_FREE(cmd->topic);
4551 FLUID_FREE(cmd->help);
4552 FLUID_FREE(cmd);
4553 }
4554
4555 /*
4556 * Command handler
4557 */
4558
4559 static void
fluid_cmd_handler_destroy_hash_value(void * value)4560 fluid_cmd_handler_destroy_hash_value(void *value)
4561 {
4562 delete_fluid_cmd((fluid_cmd_t *)value);
4563 }
4564
4565 /**
4566 * Create a new command handler.
4567 *
4568 * See new_fluid_cmd_handler2() for more information.
4569 */
new_fluid_cmd_handler(fluid_synth_t * synth,fluid_midi_router_t * router)4570 fluid_cmd_handler_t *new_fluid_cmd_handler(fluid_synth_t *synth, fluid_midi_router_t *router)
4571 {
4572 return new_fluid_cmd_handler2(fluid_synth_get_settings(synth), synth, router, NULL);
4573 }
4574
4575 /**
4576 * Create a new command handler.
4577 *
4578 * @param settings If not NULL, all the settings related commands will be added to the new handler. The @p settings
4579 * object must be the same as the one you used for creating the @p synth and @p router. Otherwise the
4580 * behaviour is undefined.
4581 * @param synth If not NULL, all the default synthesizer commands will be added to the new handler.
4582 * @param router If not NULL, all the default midi_router commands will be added to the new handler.
4583 * @param player If not NULL, all the default midi file player commands will be added to the new handler.
4584 * @return New command handler, or NULL if alloc failed
4585 */
new_fluid_cmd_handler2(fluid_settings_t * settings,fluid_synth_t * synth,fluid_midi_router_t * router,fluid_player_t * player)4586 fluid_cmd_handler_t *new_fluid_cmd_handler2(fluid_settings_t *settings,
4587 fluid_synth_t *synth,
4588 fluid_midi_router_t *router,
4589 fluid_player_t *player)
4590 {
4591 unsigned int i;
4592 fluid_cmd_handler_t *handler;
4593
4594 handler = FLUID_NEW(fluid_cmd_handler_t);
4595
4596 if(handler == NULL)
4597 {
4598 return NULL;
4599 }
4600
4601 FLUID_MEMSET(handler, 0, sizeof(*handler));
4602
4603 handler->commands = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
4604 NULL, fluid_cmd_handler_destroy_hash_value);
4605
4606 if(handler->commands == NULL)
4607 {
4608 FLUID_FREE(handler);
4609 return NULL;
4610 }
4611
4612 handler->settings = settings;
4613 handler->synth = synth;
4614 handler->router = router;
4615 handler->player = player;
4616
4617 for(i = 0; i < FLUID_N_ELEMENTS(fluid_commands); i++)
4618 {
4619 const fluid_cmd_t *cmd = &fluid_commands[i];
4620 int is_settings_cmd = FLUID_STRCMP(cmd->topic, "settings") == 0;
4621 int is_router_cmd = FLUID_STRCMP(cmd->topic, "router") == 0;
4622 int is_player_cmd = FLUID_STRCMP(cmd->topic, "player") == 0;
4623 int is_synth_cmd = !(is_settings_cmd || is_router_cmd || is_player_cmd);
4624
4625 int no_cmd = is_settings_cmd && settings == NULL; /* no settings command */
4626 no_cmd = no_cmd || (is_router_cmd && router == NULL); /* no router command */
4627 no_cmd = no_cmd || (is_player_cmd && player == NULL); /* no player command */
4628 no_cmd = no_cmd || (is_synth_cmd && synth == NULL); /* no synth command */
4629
4630 if(no_cmd)
4631 {
4632 /* register a no-op command, this avoids an unknown command error later on */
4633 fluid_cmd_t noop = *cmd;
4634 noop.handler = NULL;
4635 fluid_cmd_handler_register(handler, &noop);
4636 }
4637 else
4638 {
4639 fluid_cmd_handler_register(handler, cmd);
4640 }
4641 }
4642
4643 return handler;
4644 }
4645
4646 /**
4647 * Delete a command handler.
4648 *
4649 * @param handler Command handler to delete
4650 */
4651 void
delete_fluid_cmd_handler(fluid_cmd_handler_t * handler)4652 delete_fluid_cmd_handler(fluid_cmd_handler_t *handler)
4653 {
4654 fluid_return_if_fail(handler != NULL);
4655
4656 delete_fluid_hashtable(handler->commands);
4657 FLUID_FREE(handler);
4658 }
4659
4660 /**
4661 * Register a new command to the handler.
4662 *
4663 * @param handler Command handler instance
4664 * @param cmd Command info (gets copied)
4665 * @return #FLUID_OK if command was inserted, #FLUID_FAILED otherwise
4666 */
4667 int
fluid_cmd_handler_register(fluid_cmd_handler_t * handler,const fluid_cmd_t * cmd)4668 fluid_cmd_handler_register(fluid_cmd_handler_t *handler, const fluid_cmd_t *cmd)
4669 {
4670 fluid_cmd_t *copy = fluid_cmd_copy(cmd);
4671 fluid_hashtable_insert(handler->commands, copy->name, copy);
4672 return FLUID_OK;
4673 }
4674
4675 /**
4676 * Unregister a command from a command handler.
4677 *
4678 * @param handler Command handler instance
4679 * @param cmd Name of the command
4680 * @return TRUE if command was found and unregistered, FALSE otherwise
4681 */
4682 int
fluid_cmd_handler_unregister(fluid_cmd_handler_t * handler,const char * cmd)4683 fluid_cmd_handler_unregister(fluid_cmd_handler_t *handler, const char *cmd)
4684 {
4685 return fluid_hashtable_remove(handler->commands, cmd);
4686 }
4687
4688 int
fluid_cmd_handler_handle(void * data,int ac,char ** av,fluid_ostream_t out)4689 fluid_cmd_handler_handle(void *data, int ac, char **av, fluid_ostream_t out)
4690 {
4691 FLUID_ENTRY_COMMAND(data);
4692 fluid_cmd_t *cmd;
4693
4694 cmd = fluid_hashtable_lookup(handler->commands, av[0]);
4695
4696 if(cmd)
4697 {
4698 if(cmd->handler)
4699 {
4700 return (*cmd->handler)(handler, ac - 1, av + 1, out);
4701 }
4702 else
4703 {
4704 /* no-op command */
4705 return 1;
4706 }
4707 }
4708 else
4709 {
4710 fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
4711 return FLUID_FAILED;
4712 }
4713 }
4714
4715
4716 #ifdef NETWORK_SUPPORT
4717
4718 struct _fluid_server_t
4719 {
4720 fluid_server_socket_t *socket;
4721 fluid_settings_t *settings;
4722 fluid_synth_t *synth;
4723 fluid_midi_router_t *router;
4724 fluid_player_t *player;
4725 fluid_list_t *clients;
4726 fluid_mutex_t mutex;
4727 };
4728
fluid_server_close(fluid_server_t * server)4729 static void fluid_server_close(fluid_server_t *server)
4730 {
4731 fluid_list_t *list;
4732 fluid_list_t *clients;
4733 fluid_client_t *client;
4734
4735 fluid_return_if_fail(server != NULL);
4736
4737 fluid_mutex_lock(server->mutex);
4738 clients = server->clients;
4739 server->clients = NULL;
4740 fluid_mutex_unlock(server->mutex);
4741
4742 list = clients;
4743
4744 while(list)
4745 {
4746 client = fluid_list_get(list);
4747 fluid_client_quit(client);
4748 list = fluid_list_next(list);
4749 }
4750
4751 delete_fluid_list(clients);
4752
4753 if(server->socket)
4754 {
4755 delete_fluid_server_socket(server->socket);
4756 server->socket = NULL;
4757 }
4758 }
4759
4760 static int
fluid_server_handle_connection(fluid_server_t * server,fluid_socket_t client_socket,char * addr)4761 fluid_server_handle_connection(fluid_server_t *server, fluid_socket_t client_socket, char *addr)
4762 {
4763 fluid_client_t *client;
4764
4765 client = new_fluid_client(server, server->settings, client_socket);
4766
4767 if(client == NULL)
4768 {
4769 return -1;
4770 }
4771
4772 fluid_server_add_client(server, client);
4773
4774 return 0;
4775 }
4776
fluid_server_add_client(fluid_server_t * server,fluid_client_t * client)4777 void fluid_server_add_client(fluid_server_t *server, fluid_client_t *client)
4778 {
4779 fluid_mutex_lock(server->mutex);
4780 server->clients = fluid_list_append(server->clients, client);
4781 fluid_mutex_unlock(server->mutex);
4782 }
4783
fluid_server_remove_client(fluid_server_t * server,fluid_client_t * client)4784 void fluid_server_remove_client(fluid_server_t *server, fluid_client_t *client)
4785 {
4786 fluid_mutex_lock(server->mutex);
4787 server->clients = fluid_list_remove(server->clients, client);
4788 fluid_mutex_unlock(server->mutex);
4789 }
4790
4791 struct _fluid_client_t
4792 {
4793 fluid_server_t *server;
4794 fluid_settings_t *settings;
4795 fluid_cmd_handler_t *handler;
4796 fluid_socket_t socket;
4797 fluid_thread_t *thread;
4798 };
4799
4800
fluid_client_run(void * data)4801 static fluid_thread_return_t fluid_client_run(void *data)
4802 {
4803 fluid_shell_t shell;
4804 fluid_client_t *client = (fluid_client_t *)data;
4805
4806 fluid_shell_init(&shell,
4807 client->settings,
4808 client->handler,
4809 fluid_socket_get_istream(client->socket),
4810 fluid_socket_get_ostream(client->socket));
4811 fluid_shell_run(&shell);
4812 fluid_server_remove_client(client->server, client);
4813 delete_fluid_client(client);
4814
4815 return FLUID_THREAD_RETURN_VALUE;
4816 }
4817
4818
4819 fluid_client_t *
new_fluid_client(fluid_server_t * server,fluid_settings_t * settings,fluid_socket_t sock)4820 new_fluid_client(fluid_server_t *server, fluid_settings_t *settings, fluid_socket_t sock)
4821 {
4822 fluid_client_t *client;
4823
4824 client = FLUID_NEW(fluid_client_t);
4825
4826 if(client == NULL)
4827 {
4828 FLUID_LOG(FLUID_ERR, "Out of memory");
4829 return NULL;
4830 }
4831
4832 client->server = server;
4833 client->socket = sock;
4834 client->settings = settings;
4835 client->handler = new_fluid_cmd_handler2(fluid_synth_get_settings(server->synth),
4836 server->synth, server->router,
4837 server->player);
4838 client->thread = new_fluid_thread("client", fluid_client_run, client,
4839 0, FALSE);
4840
4841 if(client->handler == NULL || client->thread == NULL)
4842 {
4843 goto error_recovery;
4844 }
4845
4846 return client;
4847
4848 error_recovery:
4849 FLUID_LOG(FLUID_ERR, "Out of memory");
4850 delete_fluid_client(client);
4851 return NULL;
4852
4853 }
4854
fluid_client_quit(fluid_client_t * client)4855 void fluid_client_quit(fluid_client_t *client)
4856 {
4857 fluid_socket_close(client->socket);
4858
4859 FLUID_LOG(FLUID_DBG, "fluid_client_quit: joining");
4860 fluid_thread_join(client->thread);
4861 FLUID_LOG(FLUID_DBG, "fluid_client_quit: done");
4862 }
4863
delete_fluid_client(fluid_client_t * client)4864 void delete_fluid_client(fluid_client_t *client)
4865 {
4866 fluid_return_if_fail(client != NULL);
4867
4868 delete_fluid_cmd_handler(client->handler);
4869 fluid_socket_close(client->socket);
4870 delete_fluid_thread(client->thread);
4871
4872 FLUID_FREE(client);
4873 }
4874
4875 #endif /* NETWORK_SUPPORT */
4876
4877 /**
4878 * Create a new TCP/IP command shell server.
4879 *
4880 * See new_fluid_server2() for more information.
4881 */
4882 fluid_server_t *
new_fluid_server(fluid_settings_t * settings,fluid_synth_t * synth,fluid_midi_router_t * router)4883 new_fluid_server(fluid_settings_t *settings,
4884 fluid_synth_t *synth, fluid_midi_router_t *router)
4885 {
4886 return new_fluid_server2(settings, synth, router, NULL);
4887 }
4888
4889 /**
4890 * Create a new TCP/IP command shell server.
4891 *
4892 * @param settings Settings instance to use for the shell
4893 * @param synth If not NULL, the synth instance for the command handler to be used by the client
4894 * @param router If not NULL, the midi_router instance for the command handler to be used by the client
4895 * @param player If not NULL, the player instance for the command handler to be used by the client
4896 * @return New shell server instance or NULL on error
4897 */
4898 fluid_server_t *
new_fluid_server2(fluid_settings_t * settings,fluid_synth_t * synth,fluid_midi_router_t * router,fluid_player_t * player)4899 new_fluid_server2(fluid_settings_t *settings,
4900 fluid_synth_t *synth, fluid_midi_router_t *router,
4901 fluid_player_t *player)
4902 {
4903 #ifdef NETWORK_SUPPORT
4904 fluid_server_t *server;
4905 int port;
4906
4907 server = FLUID_NEW(fluid_server_t);
4908
4909 if(server == NULL)
4910 {
4911 FLUID_LOG(FLUID_ERR, "Out of memory");
4912 return NULL;
4913 }
4914
4915 server->settings = settings;
4916 server->clients = NULL;
4917 server->synth = synth;
4918 server->router = router;
4919 server->player = player;
4920
4921 fluid_mutex_init(server->mutex);
4922
4923 fluid_settings_getint(settings, "shell.port", &port);
4924
4925 server->socket = new_fluid_server_socket(port,
4926 (fluid_server_func_t) fluid_server_handle_connection,
4927 server);
4928
4929 if(server->socket == NULL)
4930 {
4931 FLUID_FREE(server);
4932 return NULL;
4933 }
4934
4935 return server;
4936 #else
4937 FLUID_LOG(FLUID_WARN, "Network support disabled on this platform.");
4938 return NULL;
4939 #endif
4940 }
4941
4942 /**
4943 * Delete a TCP/IP shell server.
4944 *
4945 * @param server Shell server instance
4946 */
4947 void
delete_fluid_server(fluid_server_t * server)4948 delete_fluid_server(fluid_server_t *server)
4949 {
4950 #ifdef NETWORK_SUPPORT
4951 fluid_return_if_fail(server != NULL);
4952
4953 fluid_server_close(server);
4954
4955 FLUID_FREE(server);
4956 #endif
4957 }
4958
4959 /**
4960 * Join a shell server thread (wait until it quits).
4961 *
4962 * @param server Shell server instance
4963 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
4964 */
fluid_server_join(fluid_server_t * server)4965 int fluid_server_join(fluid_server_t *server)
4966 {
4967 #ifdef NETWORK_SUPPORT
4968 return fluid_server_socket_join(server->socket);
4969 #else
4970 return FLUID_FAILED;
4971 #endif
4972 }
4973