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