fluid_cmd.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:55k
源码类别:

midi

开发平台:

C/C++

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