diff --git a/doc/recent_changes.txt b/doc/recent_changes.txt index 725c2fa6..ba86d0a2 100644 --- a/doc/recent_changes.txt +++ b/doc/recent_changes.txt @@ -11,6 +11,7 @@ - Events that share the same tick was given a new, documented order, see fluid_sequencer_send_at(). - The sequencer's scale can now be used for arbitrary tempo changes. Previously, the scale of the sequencer was limited to 1000. The only limitation now is >0. - The dynamic-sample-loader has learned support to pin samples, see fluid_synth_pin_preset() and fluid_synth_unpin_preset() +- Added getter and setter functions for individual effect groups \section NewIn2_1_4 What's new in 2.1.4? diff --git a/include/fluidsynth/synth.h b/include/fluidsynth/synth.h index e4794319..b8d0b0ab 100644 --- a/include/fluidsynth/synth.h +++ b/include/fluidsynth/synth.h @@ -159,19 +159,31 @@ FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_i * * @{ */ -FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize, - double damping, double width, double level); -FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize); -FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping); -FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width); -FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level); +FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on); +FLUIDSYNTH_API int fluid_synth_reverb_on(fluid_synth_t *synth, int fx_group, int on); -FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on); -FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth); -FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth); -FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth); -FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth); -/* @} Reverb */ +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize, + double damping, double width, double level); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level); + +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth); + +FLUIDSYNTH_API int fluid_synth_set_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double roomsize); +FLUIDSYNTH_API int fluid_synth_set_reverb_group_damp(fluid_synth_t *synth, int fx_group, double damping); +FLUIDSYNTH_API int fluid_synth_set_reverb_group_width(fluid_synth_t *synth, int fx_group, double width); +FLUIDSYNTH_API int fluid_synth_set_reverb_group_level(fluid_synth_t *synth, int fx_group, double level); + +FLUIDSYNTH_API int fluid_synth_get_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double *roomsize); +FLUIDSYNTH_API int fluid_synth_get_reverb_group_damp(fluid_synth_t *synth, int fx_group, double *damping); +FLUIDSYNTH_API int fluid_synth_get_reverb_group_width(fluid_synth_t *synth, int fx_group, double *width); +FLUIDSYNTH_API int fluid_synth_get_reverb_group_level(fluid_synth_t *synth, int fx_group, double *level); + /* @} Reverb */ /** @@ -192,22 +204,36 @@ enum fluid_chorus_mod FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */ }; -FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level, - double speed, double depth_ms, int type); -FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr); -FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level); -FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed); -FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms); -FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type); -FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on); -FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth); -FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth); -FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth); -FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth); -FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */ -/* @} Chrous */ +FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on); +FLUIDSYNTH_API int fluid_synth_chorus_on(fluid_synth_t *synth, int fx_group, int on); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level, + double speed, double depth_ms, int type); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type); + +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */ + +FLUIDSYNTH_API int fluid_synth_set_chorus_group_nr(fluid_synth_t *synth, int fx_group, int nr); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_level(fluid_synth_t *synth, int fx_group, double level); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_speed(fluid_synth_t *synth, int fx_group, double speed); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_depth(fluid_synth_t *synth, int fx_group, double depth_ms); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_type(fluid_synth_t *synth, int fx_group, int type); + +FLUIDSYNTH_API int fluid_synth_get_chorus_group_nr(fluid_synth_t *synth, int fx_group, int *nr); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_level(fluid_synth_t *synth, int fx_group, double *level); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_speed(fluid_synth_t *synth, int fx_group, double *speed); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_depth(fluid_synth_t *synth, int fx_group, double *depth_ms); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_type(fluid_synth_t *synth, int fx_group, int *type); +/* @} Chorus */ /** * @defgroup synthesis_params Synthesis Parameters diff --git a/src/bindings/fluid_cmd.c b/src/bindings/fluid_cmd.c index 968f53dc..2776417d 100644 --- a/src/bindings/fluid_cmd.c +++ b/src/bindings/fluid_cmd.c @@ -192,48 +192,48 @@ static const fluid_cmd_t fluid_commands[] = /* reverb commands */ { "rev_preset", "reverb", fluid_handle_reverbpreset, - "rev_preset num Load preset num into the reverb unit" + "rev_preset num Load preset num into all reverb unit" }, { "rev_setroomsize", "reverb", fluid_handle_reverbsetroomsize, - "rev_setroomsize num Change reverb room size" + "rev_setroomsize [group] num Set room size of all or one reverb group to num" }, { "rev_setdamp", "reverb", fluid_handle_reverbsetdamp, - "rev_setdamp num Change reverb damping" + "rev_setdamp [group] num Set damping of all or one reverb group to num" }, { "rev_setwidth", "reverb", fluid_handle_reverbsetwidth, - "rev_setwidth num Change reverb width" + "rev_setwidth [group] num Set width of all or one reverb group to num" }, { "rev_setlevel", "reverb", fluid_handle_reverbsetlevel, - "rev_setlevel num Change reverb level" + "rev_setlevel [group] num Set output level of all or one reverb group to num" }, { "reverb", "reverb", fluid_handle_reverb, - "reverb [0|1|on|off] Turn the reverb on or off" + "reverb [0|1|on|off] Turn all reverb groups on or off" }, /* chorus commands */ { "cho_set_nr", "chorus", fluid_handle_chorusnr, - "cho_set_nr n Use n delay lines (default 3)" + "cho_set_nr [group] n Set n delay lines (default 3) in all or one chorus group" }, { "cho_set_level", "chorus", fluid_handle_choruslevel, - "cho_set_level num Set output level of each chorus line to num" + "cho_set_level [group] num Set output level of all or one chorus group to num" }, { "cho_set_speed", "chorus", fluid_handle_chorusspeed, - "cho_set_speed num Set mod speed of chorus to num (Hz)" + "cho_set_speed [group] num Set mod speed of all or one chorus group to num (Hz)" }, { "cho_set_depth", "chorus", fluid_handle_chorusdepth, - "cho_set_depth num Set chorus modulation depth to num (ms)" + "cho_set_depth [group] num Set modulation depth of all or one chorus group to num (ms)" }, { "chorus", "chorus", fluid_handle_chorus, - "chorus [0|1|on|off] Turn the chorus on or off" + "chorus [0|1|on|off] Turn all chorus groups on or off" }, { "gain", "general", fluid_handle_gain, @@ -623,13 +623,13 @@ fluid_get_userconf(char *buf, int len) #if defined(WIN32) home = getenv("USERPROFILE"); config_file = "\\fluidsynth.cfg"; - + #elif !defined(MACOS9) home = getenv("HOME"); config_file = "/.fluidsynth"; - + #endif - + if(home == NULL) { return NULL; @@ -1096,275 +1096,365 @@ fluid_handle_reverbpreset(void *data, int ac, char **av, fluid_ostream_t out) return FLUID_OK; } +/* + The function is useful for reverb and chorus commands which have + 1 or 2 parameters. + The function checks that there is 1 or 2 aguments. + When there is 2 parameters it checks the first argument that must be + an fx group index in the range[0..synth->effects_groups-1]. + + return the group index: + -1, when the command is for all fx groups. + 0 to synth->effects_groups-1, when the command is for this group index. + -2 if error. +*/ +static int check_fx_group_idx(int ac, char **av, fluid_ostream_t out, + fluid_synth_t *synth, const char *name_cde) +{ + int fx_group; /* fx unit index */ + int ngroups; /* count of fx groups */ + + /* One or 2 arguments allowed */ + if(ac < 1 || ac > 2) + { + fluid_ostream_printf(out, "%s: needs 1 or 2 arguments\n", name_cde); + return -2; + } + + /* check optionnal first argument which is a fx group index */ + fx_group = -1; + + if(ac > 1) + { + fx_group = atoi(av[0]); /* get fx group index */ + ngroups = fluid_synth_count_effects_groups(synth); + + if(!fluid_is_number(av[0]) || fx_group < 0 || fx_group >= ngroups) + { + fluid_ostream_printf(out, "%s: group index \"%s\" must be in range [%d..%d]\n", + name_cde, av[0], 0, ngroups - 1); + return -2; + } + } + + return fx_group; +} + +/* parameter value */ +struct value +{ + char *name; + double min; + double max; +}; + +/* + check 2 arguments for reverb commands : fx group index , value + - group index must be an integer in the range [-1..synth->effects_groups]. + - value must be a double in the range [min..max] + @param param a pointer on a value to return the second value argument. + return the fx group index: + -1 when the command is for all fx group. + 0 to synth->effects_groups-1 when the command is for this group index. + -2 if error. +*/ +static int check_fx_reverb_param(int ac, char **av, fluid_ostream_t out, + fluid_synth_t *synth, const char *name_cde, + const struct value *value, + fluid_real_t *param) +{ + /* get and check fx group index argument */ + int fx_group = check_fx_group_idx(ac, av, out, synth, name_cde); + + if(fx_group >= -1) + { + fluid_real_t val; + + /* get and check value argument */ + ac--; + val = atof(av[ac]); + + if(!fluid_is_number(av[ac]) || val < value->min || val > value->max) + { + fluid_ostream_printf(out, "%s: %s \"%s\" must be in range [%f..%f]\n", + name_cde, value->name, av[ac], value->min, value->max); + return -2; + } + + *param = val; + } + + return fx_group; +} + +/* Purpose: + * Response to fluid_handle_reverbsetxxxx commands + */ +static int +fluid_handle_reverb_command(void *data, int ac, char **av, fluid_ostream_t out, + int param) +{ + int fx_group; + + /* reverb commands name table */ + static const char *name_cde[FLUID_REVERB_PARAM_LAST] = + {"rev_setroomsize", "rev_setdamp", "rev_setwidth", "rev_setlevel"}; + + /* name and min/max values table */ + static struct value values[FLUID_REVERB_PARAM_LAST] = + { + {"room size"}, {"damp"}, {"width"}, {"level"} + }; + + FLUID_ENTRY_COMMAND(data); + fluid_real_t value; + + fluid_settings_getnum_range(handler->synth->settings, "synth.reverb.room-size", + &values[FLUID_REVERB_ROOMSIZE].min, + &values[FLUID_REVERB_ROOMSIZE].max); + + fluid_settings_getnum_range(handler->synth->settings, "synth.reverb.damp", + &values[FLUID_REVERB_DAMP].min, + &values[FLUID_REVERB_DAMP].max); + + + fluid_settings_getnum_range(handler->synth->settings, "synth.reverb.width", + &values[FLUID_REVERB_WIDTH].min, + &values[FLUID_REVERB_WIDTH].max); + + fluid_settings_getnum_range(handler->synth->settings, "synth.reverb.level", + &values[FLUID_REVERB_LEVEL].min, + &values[FLUID_REVERB_LEVEL].max); + + /* get and check command arguments */ + fx_group = check_fx_reverb_param(ac, av, out, handler->synth, + name_cde[param], &values[param], &value); + + if(fx_group >= -1) + { + /* run reverb function */ + fluid_synth_reverb_set_param(handler->synth, fx_group, param, value); + return FLUID_OK; + } + + return FLUID_FAILED; +} + /* Purpose: * Response to 'rev_setroomsize' command. - * Load the new room size into the reverb unit. */ + * Load the new room size into the reverb fx group. + * Example: rev_setroomzize 0 0.5 + * load roomsize 0.5 in the reverb fx group at index 0 + */ int fluid_handle_reverbsetroomsize(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - fluid_real_t room_size; - - if(ac < 1) - { - fluid_ostream_printf(out, "rev_setroomsize: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "rev_setroomsize is deprecated! Use 'set synth.reverb.room-size %s' instead.\n", av[0]); - - room_size = atof(av[0]); - - if(room_size < 0) - { - fluid_ostream_printf(out, "rev_setroomsize: Room size must be positive!\n"); - return FLUID_FAILED; - } - - if(room_size > 1.0) - { - fluid_ostream_printf(out, "rev_setroomsize: Room size too big!\n"); - return FLUID_FAILED; - } - - fluid_synth_set_reverb_roomsize(handler->synth, room_size); - return FLUID_OK; + return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_ROOMSIZE); } /* Purpose: * Response to 'rev_setdamp' command. - * Load the new damp factor into the reverb unit. */ + * Load the new damp factor into the reverb fx group. + * Example: rev_setdamp 1 0.5 + * load damp 0.5 in the reverb fx group at index 1 + */ int fluid_handle_reverbsetdamp(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - fluid_real_t damp; - - if(ac < 1) - { - fluid_ostream_printf(out, "rev_setdamp: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "rev_setdamp is deprecated! Use 'set synth.reverb.damp %s' instead.\n", av[0]); - - damp = atof(av[0]); - - if((damp < 0.0f) || (damp > 1)) - { - fluid_ostream_printf(out, "rev_setdamp: damp must be between 0 and 1!\n"); - return FLUID_FAILED; - } - - fluid_synth_set_reverb_damp(handler->synth, damp); - return FLUID_OK; + return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_DAMP); } /* Purpose: * Response to 'rev_setwidth' command. - * Load the new width into the reverb unit. */ + * Load the new width into the reverb fx group. + * Example: rev_setwidth 1 0.5 + * load width 0.5 in the reverb fx group at index 1. + */ int fluid_handle_reverbsetwidth(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - fluid_real_t width; - - if(ac < 1) - { - fluid_ostream_printf(out, "rev_setwidth: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "rev_setroomsize is deprecated! Use 'set synth.reverb.width %s' instead.\n", av[0]); - - width = atof(av[0]); - - if((width < 0) || (width > 100)) - { - fluid_ostream_printf(out, "rev_setroomsize: Too wide! (0..100)\n"); - return FLUID_FAILED; - } - - fluid_synth_set_reverb_width(handler->synth, width); - return FLUID_OK; + return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_WIDTH); } /* Purpose: * Response to 'rev_setlevel' command. - * Load the new level into the reverb unit. */ + * Load the new level into the reverb fx group. + * Example: rev_setlevel 1 0.5 + * load level 0.5 in the reverb fx group at index 1. + */ int fluid_handle_reverbsetlevel(void *data, int ac, char **av, fluid_ostream_t out) { + return fluid_handle_reverb_command(data, ac, av, out, FLUID_REVERB_LEVEL); +} + +/* reverb/chorus on/off commands enum */ +enum rev_chor_on_cde +{ + REVERB_ON_CDE, + CHORUS_ON_CDE, + NBR_REV_CHOR_ON_CDE +}; + +/* Purpose: + * Set all reverb/chorus units on or off + */ +static int +fluid_handle_reverb_chorus_on_command(void *data, int ac, char **av, fluid_ostream_t out, + enum rev_chor_on_cde cde) +{ + /* commands name table */ + static const char *name_cde[NBR_REV_CHOR_ON_CDE] = {"reverb", "chorus"}; + /* functions table */ + static int (*onoff_func[NBR_REV_CHOR_ON_CDE])(fluid_synth_t *, int, int) = + { + fluid_synth_reverb_on, fluid_synth_chorus_on + }; + FLUID_ENTRY_COMMAND(data); - fluid_real_t level; + int onoff; - if(ac < 1) + /* get and check fx group index argument */ + int fx_group = check_fx_group_idx(ac, av, out, handler->synth, name_cde[cde]); + + if(fx_group >= -1) { - fluid_ostream_printf(out, "rev_setlevel: too few arguments.\n"); - return FLUID_FAILED; + ac--; + + /* check argument value */ + if((FLUID_STRCMP(av[ac], "0") == 0) || (FLUID_STRCMP(av[ac], "off") == 0)) + { + onoff = 0; + } + else if((FLUID_STRCMP(av[ac], "1") == 0) || (FLUID_STRCMP(av[ac], "on") == 0)) + { + onoff = 1; + } + else + { + fluid_ostream_printf(out, "%s: invalid arguments %s [0|1|on|off]\n", + name_cde[cde], av[ac]); + return FLUID_FAILED; + } + + /* run on/off function */ + return onoff_func[cde](handler->synth, fx_group, onoff); } - fluid_ostream_printf(out, "rev_setlevel is deprecated! Use 'set synth.reverb.level %s' instead.\n", av[0]); - - level = atof(av[0]); - - if(fabs(level) > 30) - { - fluid_ostream_printf(out, "rev_setlevel: Value too high! (Value of 10 =+20 dB)\n"); - return FLUID_FAILED; - } - - fluid_synth_set_reverb_level(handler->synth, level); - return FLUID_OK; + return FLUID_FAILED; } /* Purpose: - * Response to 'reverb' command. - * Change the FLUID_REVERB flag in the synth */ + * Set all reverb units on + */ int fluid_handle_reverb(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - - if(ac < 1) - { - fluid_ostream_printf(out, "reverb: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "reverb is deprecated! Use 'set synth.reverb.active %s' instead.\n", av[0]); - - if((FLUID_STRCMP(av[0], "0") == 0) || (FLUID_STRCMP(av[0], "off") == 0)) - { - fluid_synth_set_reverb_on(handler->synth, 0); - } - else if((FLUID_STRCMP(av[0], "1") == 0) || (FLUID_STRCMP(av[0], "on") == 0)) - { - fluid_synth_set_reverb_on(handler->synth, 1); - } - else - { - fluid_ostream_printf(out, "reverb: invalid arguments %s [0|1|on|off]", av[0]); - return FLUID_FAILED; - } - - return FLUID_OK; + return fluid_handle_reverb_chorus_on_command(data, ac, av, out, REVERB_ON_CDE); } +/* Purpose: + * Response to fluid_handle_chorus_xxx commands + */ +static int +fluid_handle_chorus_command(void *data, int ac, char **av, fluid_ostream_t out, + int param) +{ + /* chorus commands name table */ + static const char *name_cde[FLUID_CHORUS_PARAM_LAST - 1] = + {"cho_set_nr", "cho_set_level", "cho_set_speed", "cho_set_depth"}; + + /* value name table */ + static const char *name_value[FLUID_CHORUS_PARAM_LAST - 1] = + {"nr", "level", "speed", "depth"}; + + FLUID_ENTRY_COMMAND(data); + + /* get and check index fx group index argument */ + int fx_group = check_fx_group_idx(ac, av, out, handler->synth, name_cde[param]); + + if(fx_group >= -1) + { + double value; + /* get and check value argument */ + ac--; + + if(!fluid_is_number(av[ac])) + { + fluid_ostream_printf(out, "%s: %s \"%s\" must be a number\n", + name_cde[param], name_value[param], av[ac]); + return FLUID_FAILED; + } + + /* run chorus function */ + if(param == FLUID_CHORUS_NR) /* commands with integer parameter */ + { + value = (double)atoi(av[ac]); + } + else /* commands with float parameter */ + { + value = atof(av[ac]); + } + + fluid_synth_chorus_set_param(handler->synth, fx_group, param, value); + return FLUID_OK; + } + + return FLUID_FAILED; +} /* Purpose: - * Response to 'chorus_setnr' command */ + * Response to 'cho_set_nr' command + * Load the new voice count into the chorus fx group. + * Example: cho_set_nr 1 3 + * load 3 voices in the chorus fx group at index 1. + */ int fluid_handle_chorusnr(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - int nr; - - if(ac < 1) - { - fluid_ostream_printf(out, "cho_set_nr: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "cho_set_nr is deprecated! Use 'set synth.chorus.nr %s' instead.\n", av[0]); - - nr = atoi(av[0]); - fluid_synth_set_chorus_nr(handler->synth, nr); - return FLUID_OK; + return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_NR); } /* Purpose: - * Response to 'chorus_setlevel' command */ + * Response to 'cho_setlevel' command + * Example: cho_set_level 1 3 + * load level 3 in the chorus fx group at index 1. + */ int fluid_handle_choruslevel(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - fluid_real_t level; - - if(ac < 1) - { - fluid_ostream_printf(out, "cho_set_level: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "cho_set_level is deprecated! Use 'set synth.chorus.level %s' instead.\n", av[0]); - - level = atof(av[0]); - fluid_synth_set_chorus_level(handler->synth, level); - return FLUID_OK; - + return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_LEVEL); } /* Purpose: - * Response to 'chorus_setspeed' command */ + * Response to 'cho_setspeed' command + * Example: cho_set_speed 1 0.1 + * load speed 0.1 in the chorus fx group at index 1. + */ int fluid_handle_chorusspeed(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - fluid_real_t speed; - - if(ac < 1) - { - fluid_ostream_printf(out, "cho_set_speed: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "cho_set_speed is deprecated! Use 'set synth.chorus.speed %s' instead.\n", av[0]); - - speed = atof(av[0]); - fluid_synth_set_chorus_speed(handler->synth, speed); - return FLUID_OK; + return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_SPEED); } /* Purpose: - * Response to 'chorus_setdepth' command */ + * Response to 'cho_setdepth' command + * Example: cho_set_depth 1 0.3 + * load depth 0.3 in the chorus fx group at index 1. + */ int fluid_handle_chorusdepth(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - fluid_real_t depth; - - if(ac < 1) - { - fluid_ostream_printf(out, "cho_set_depth: too few arguments.\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "cho_set_depth is deprecated! Use 'set synth.chorus.depth %s' instead.\n", av[0]); - - depth = atof(av[0]); - fluid_synth_set_chorus_depth(handler->synth, depth); - return FLUID_OK; + return fluid_handle_chorus_command(data, ac, av, out, FLUID_CHORUS_DEPTH); } +/* Purpose: + * Set all chorus units on + */ int fluid_handle_chorus(void *data, int ac, char **av, fluid_ostream_t out) { - FLUID_ENTRY_COMMAND(data); - - if(ac < 1) - { - fluid_ostream_printf(out, "chorus: too few arguments\n"); - return FLUID_FAILED; - } - - fluid_ostream_printf(out, "chorus is deprecated! Use 'set synth.chorus.active %s' instead.\n", av[0]); - - if((FLUID_STRCMP(av[0], "0") == 0) || (FLUID_STRCMP(av[0], "off") == 0)) - { - fluid_synth_set_chorus_on(handler->synth, 0); - } - else if((FLUID_STRCMP(av[0], "1") == 0) || (FLUID_STRCMP(av[0], "on") == 0)) - { - fluid_synth_set_chorus_on(handler->synth, 1); - } - else - { - fluid_ostream_printf(out, "chorus: invalid arguments %s [0|1|on|off]", av[0]); - return FLUID_FAILED; - } - - return FLUID_OK; + return fluid_handle_reverb_chorus_on_command(data, ac, av, out, CHORUS_ON_CDE); } /* Purpose: @@ -1880,7 +1970,7 @@ fluid_handle_set(void *data, int ac, char **av, fluid_ostream_t out) { fluid_ostream_printf(out, "set: Value out of range. Try 'info %s' for valid ranges\n", av[0]); } - + if(!fluid_settings_is_realtime(handler->synth->settings, av[0])) { fluid_ostream_printf(out, "Warning: '%s' is not a realtime setting, changes won't take effect.\n", av[0]); @@ -2474,7 +2564,8 @@ int fluid_handle_router_par2(void *data, int ac, char **av, fluid_ostream_t out) /** commands Poly/mono mode *************************************************/ -static const char *const mode_name[] = { +static const char *const mode_name[] = +{ "poly omni on (0)", "mono omni on (1)", "poly omni off(2)", "mono omni off(3)" }; @@ -2552,7 +2643,7 @@ static int get_channel_mode_num(char *name) { /* argument names for channel mode parameter (see resetbasicchannels and setbasicchannels commands*/ - static const char * const name_channel_mode [FLUID_CHANNEL_MODE_LAST] = + static const char *const name_channel_mode [FLUID_CHANNEL_MODE_LAST] = {"poly_omnion", "mono_omnion", "poly_omnioff", "mono_omnioff"}; int i; diff --git a/src/rvoice/fluid_chorus.h b/src/rvoice/fluid_chorus.h index affc777d..c6d247fa 100644 --- a/src/rvoice/fluid_chorus.h +++ b/src/rvoice/fluid_chorus.h @@ -27,14 +27,28 @@ typedef struct _fluid_chorus_t fluid_chorus_t; +/* enum describing each chorus parameter */ +enum fluid_chorus_param +{ + FLUID_CHORUS_NR, /**< number of delay line */ + FLUID_CHORUS_LEVEL, /**< output level */ + FLUID_CHORUS_SPEED, /**< lfo frequency */ + FLUID_CHORUS_DEPTH, /**< modulation depth */ + FLUID_CHORUS_TYPE, /**< type of waveform */ + FLUID_CHORUS_PARAM_LAST /* number of enum fluid_chorus_param */ +}; + +/* return a bit flag from param: 2^param */ +#define FLUID_CHORPARAM_TO_SETFLAG(param) (1 << param) + /** Flags for fluid_chorus_set() */ typedef enum { - FLUID_CHORUS_SET_NR = 1 << 0, - FLUID_CHORUS_SET_LEVEL = 1 << 1, - FLUID_CHORUS_SET_SPEED = 1 << 2, - FLUID_CHORUS_SET_DEPTH = 1 << 3, - FLUID_CHORUS_SET_TYPE = 1 << 4, + FLUID_CHORUS_SET_NR = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_NR), + FLUID_CHORUS_SET_LEVEL = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_LEVEL), + FLUID_CHORUS_SET_SPEED = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_SPEED), + FLUID_CHORUS_SET_DEPTH = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_DEPTH), + FLUID_CHORUS_SET_TYPE = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_TYPE), /** Value for fluid_chorus_set() which sets all chorus parameters. */ FLUID_CHORUS_SET_ALL = FLUID_CHORUS_SET_NR diff --git a/src/rvoice/fluid_rev.h b/src/rvoice/fluid_rev.h index 597467bb..35c9cf66 100644 --- a/src/rvoice/fluid_rev.h +++ b/src/rvoice/fluid_rev.h @@ -26,14 +26,26 @@ typedef struct _fluid_revmodel_t fluid_revmodel_t; +/* enum describing each reverb parameter */ +enum fluid_reverb_param +{ + FLUID_REVERB_ROOMSIZE, /**< reverb time */ + FLUID_REVERB_DAMP, /**< high frequency damping */ + FLUID_REVERB_WIDTH, /**< stereo width */ + FLUID_REVERB_LEVEL, /**< output level */ + FLUID_REVERB_PARAM_LAST /* number of enum fluid_reverb_param */ +}; + +/* return a bit flag from param: 2^param */ +#define FLUID_REVPARAM_TO_SETFLAG(param) (1 << param) /** Flags for fluid_revmodel_set() */ typedef enum { - FLUID_REVMODEL_SET_ROOMSIZE = 1 << 0, - FLUID_REVMODEL_SET_DAMPING = 1 << 1, - FLUID_REVMODEL_SET_WIDTH = 1 << 2, - FLUID_REVMODEL_SET_LEVEL = 1 << 3, + FLUID_REVMODEL_SET_ROOMSIZE = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_ROOMSIZE), + FLUID_REVMODEL_SET_DAMPING = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_DAMP), + FLUID_REVMODEL_SET_WIDTH = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_WIDTH), + FLUID_REVMODEL_SET_LEVEL = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_LEVEL), /** Value for fluid_revmodel_set() which sets all reverb parameters. */ FLUID_REVMODEL_SET_ALL = FLUID_REVMODEL_SET_LEVEL diff --git a/src/rvoice/fluid_rvoice_mixer.c b/src/rvoice/fluid_rvoice_mixer.c index 1a3f685a..01b69671 100644 --- a/src/rvoice/fluid_rvoice_mixer.c +++ b/src/rvoice/fluid_rvoice_mixer.c @@ -77,7 +77,14 @@ typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t; struct _fluid_mixer_fx_t { fluid_revmodel_t *reverb; /**< Reverb unit */ + /* reverb shadow parameters here will be returned if queried */ + double reverb_param[FLUID_REVERB_PARAM_LAST]; + int reverb_on; /* reverb on/off */ + fluid_chorus_t *chorus; /**< Chorus unit */ + /* chorus shadow parameters here will be returned if queried */ + double chorus_param[FLUID_CHORUS_PARAM_LAST]; + int chorus_on; /* chorus on/off */ }; struct _fluid_rvoice_mixer_t @@ -128,6 +135,9 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun int dry_count = mixer->buffers.buf_count; /* dry buffers count */ int mix_fx_to_out = mixer->mix_fx_to_out; /* get mix_fx_to_out mode */ int dry_idx = 0; /* dry buffer index */ + int buf_idx; /* buffer index */ + int samp_idx; /* sample index in buffer */ + int sample_count; /* sample count to process */ void (*reverb_process_func)(fluid_revmodel_t *rev, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out); void (*chorus_process_func)(fluid_chorus_t *chorus, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out); @@ -166,9 +176,14 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun { for(f = 0; f < mixer->fx_units; f++) { - int buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL; - int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; - int sample_count = current_blockcount * FLUID_BUFSIZE; + if(!mixer->fx[f].reverb_on) + { + continue; /* this reverb unit is disabled */ + } + + buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL; + samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; + sample_count = current_blockcount * FLUID_BUFSIZE; /* in mix mode, map fx out_rev at index f to a dry buffer at index dry_idx */ if(mix_fx_to_out) @@ -194,10 +209,15 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun { for(f = 0; f < mixer->fx_units; f++) { - int buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL; - int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; - int sample_count = current_blockcount * FLUID_BUFSIZE; - + if(!mixer->fx[f].chorus_on) + { + continue; /* this chorus unit is disabled */ + } + + buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL; + samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; + sample_count = current_blockcount * FLUID_BUFSIZE; + /* in mix mode, map fx out_ch at index f to a dry buffer at index dry_idx */ if(mix_fx_to_out) { @@ -260,18 +280,18 @@ fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbu for(i = 0; i < buffers->mixer->fx_units; i++) { int fx_idx = i * fx_channels_per_unit; - + outbufs[offset + fx_idx + SYNTH_REVERB_CHANNEL] = (with_reverb) ? &base_ptr[(fx_idx + SYNTH_REVERB_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT] : NULL; - + outbufs[offset + fx_idx + SYNTH_CHORUS_CHANNEL] = (with_chorus) ? &base_ptr[(fx_idx + SYNTH_CHORUS_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT] : NULL; } - + /* The output associated with a MIDI channel is wrapped around * using the number of audio groups as modulo divider. This is * typically the number of output channels on the 'sound card', @@ -421,6 +441,7 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers, /* mixdown sample_count samples in the current buffer buf Note, that this loop could be unrolled by FLUID_BUFSIZE elements */ #pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT) + for(dsp_i = 0; dsp_i < sample_count; dsp_i++) { // Index by blocks (not by samples) to let the compiler know that we always start accessing @@ -449,20 +470,22 @@ fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers, { /* render one block in src_buf */ int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]); + if(s == -1) { /* the voice is silent, mix back all the previously rendered sound */ fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed, - total_samples - (last_block_mixed*FLUID_BUFSIZE), + total_samples - (last_block_mixed * FLUID_BUFSIZE), dest_bufs, dest_bufcount); - last_block_mixed = i+1; /* future block start index to mix from */ + last_block_mixed = i + 1; /* future block start index to mix from */ total_samples += FLUID_BUFSIZE; /* accumulate samples count rendered */ } else { /* the voice wasn't quiet. Some samples have been rendered [0..FLUID_BUFSIZE] */ total_samples += s; + if(s < FLUID_BUFSIZE) { /* voice has finished */ @@ -473,7 +496,7 @@ fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers, /* Now mix the remaining blocks from last_block_mixed to total_sample */ fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed, - total_samples - (last_block_mixed*FLUID_BUFSIZE), + total_samples - (last_block_mixed * FLUID_BUFSIZE), dest_bufs, dest_bufcount); if(total_samples < blockcount * FLUID_BUFSIZE) @@ -692,6 +715,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate) fluid_real_t samplerate = param[1].real; // because fluid_synth_update_mixer() puts real into arg2 int i; + for(i = 0; i < mixer->fx_units; i++) { if(mixer->fx[i].chorus) @@ -751,6 +775,7 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, /* allocate the reverb module */ mixer->fx = FLUID_ARRAY(fluid_mixer_fx_t, fx_units); + if(mixer->fx == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); @@ -819,7 +844,7 @@ fluid_mixer_buffers_free(fluid_mixer_buffers_t *buffers) void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer) { int i; - + fluid_return_if_fail(mixer != NULL); #if ENABLE_MIXER_THREADS @@ -848,7 +873,7 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer) #endif fluid_mixer_buffers_free(&mixer->buffers); - + for(i = 0; i < mixer->fx_units; i++) { if(mixer->fx[i].reverb) @@ -867,7 +892,6 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer) FLUID_FREE(mixer); } - #ifdef LADSPA /** * Set a LADSPS fx instance to be used by the mixer and assign the mixer buffers @@ -911,6 +935,130 @@ void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer, } #endif +/** + * set one or more reverb shadow parameters for one fx group. + * These parameters will be returned if queried. + * (see fluid_rvoice_mixer_reverb_get_param()) + * + * @param mixer that contains all fx units. + * @param fx_group index of the fx group to which parameters must be set. + * must be in the range [-1..mixer->fx_units[. If -1 the changes are applied to + * all fx units. + * @param set Flags indicating which parameters should be set (#fluid_revmodel_set_t) + * @param values table of parameters values. + */ +void +fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]) +{ + fluid_mixer_fx_t *fx = mixer->fx; + int nr_units = mixer->fx_units; + + if(fx_group >= 0) /* apply parameters to this fx group only */ + { + nr_units = fx_group + 1; + } + else /* apply parameters to all fx groups */ + { + fx_group = 0; + } + + for(; fx_group < nr_units; fx_group++) + { + int param; + + for(param = 0; param < FLUID_REVERB_PARAM_LAST; param++) + { + if(set & FLUID_REVPARAM_TO_SETFLAG(param)) + { + fx[fx_group].reverb_param[param] = values[param]; + } + } + } +} + +/** + * get one reverb shadow parameter for one fx group. + * (see fluid_rvoice_mixer_set_reverb_full()) + * + * @param mixer that contains all fx group units. + * @param fx_group index of the fx group to get parameter from. + * must be in the range [0..mixer->fx_units[. + * @param enum indicating the parameter to get. + * FLUID_REVERB_ROOMSIZE, reverb room size value. + * FLUID_REVERB_DAMP, reverb damping value. + * FLUID_REVERB_WIDTH, reverb width value. + * FLUID_REVERB_LEVEL, reverb level value. + * @return value. + */ +double +fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param) +{ + return mixer->fx[fx_group].reverb_param[param]; +} + +/** + * set one or more chorus shadow parameters for one fx group. + * These parameters will be returned if queried. + * (see fluid_rvoice_mixer_chorus_get_param()) + * + * @param mixer that contains all fx units. + * @param fx_group index of the fx group to which parameters must be set. + * must be in the range [-1..mixer->fx_units[. If -1 the changes are applied + * to all fx group. + * Keep in mind, that the needed CPU time is proportional to 'nr'. + * @param set Flags indicating which parameters to set (#fluid_chorus_set_t) + * @param values table of pararameters. + */ +void +fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]) +{ + fluid_mixer_fx_t *fx = mixer->fx; + int nr_units = mixer->fx_units; + + if(fx_group >= 0) /* apply parameters to this group fx only */ + { + nr_units = fx_group + 1; + } + else /* apply parameters to all fx units*/ + { + fx_group = 0; + } + + for(; fx_group < nr_units; fx_group++) + { + int param; + + for(param = 0; param < FLUID_CHORUS_PARAM_LAST; param++) + { + if(set & FLUID_CHORPARAM_TO_SETFLAG(param)) + { + fx[fx_group].chorus_param[param] = values[param]; + } + } + } +} + +/** + * get one chorus shadow parameter for one fx group. + * (see fluid_rvoice_mixer_set_chorus_full()) + * + * @param mixer that contains all fx groups units. + * @param fx_group index of the fx group to get parameter from. + * must be in the range [0..mixer->fx_units[. + * @param get Flags indicating which parameter to get (#fluid_chorus_set_t) + * @return the parameter value (0.0 is returned if error) + */ +double +fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param) +{ + return mixer->fx[fx_group].chorus_param[param]; +} + +/* @deprecated: use fluid_rvoice_mixer_reverb_enable instead */ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled) { fluid_rvoice_mixer_t *mixer = obj; @@ -919,6 +1067,43 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled) mixer->with_reverb = on; } +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable) +{ + fluid_rvoice_mixer_t *mixer = obj; + int fx_group = param[0].i; /* reverb fx group index */ + int on = param[1].i; /* on/off */ + + int nr_units = mixer->fx_units; + + /* does on/off must be applied only to fx group at index fx_group ? */ + if(fx_group >= 0) + { + mixer->fx[fx_group].reverb_on = on; + } + /* on/off must be applied to all fx groups */ + else + { + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + mixer->fx[fx_group].reverb_on = on; + } + } + + /* set with_reverb if at least one reverb unit is on */ + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + on = mixer->fx[fx_group].reverb_on; + + if(on) + { + break; + } + } + + mixer->with_reverb = on; +} + +/* @deprecated: use fluid_rvoice_mixer_chorus_enable instead */ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled) { fluid_rvoice_mixer_t *mixer = obj; @@ -926,6 +1111,42 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled) mixer->with_chorus = on; } +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable) +{ + fluid_rvoice_mixer_t *mixer = obj; + int fx_group = param[0].i; /* chorus fx group index */ + int on = param[1].i; /* on/off */ + + int nr_units = mixer->fx_units; + + /* does on/off must be applied only to fx group at index fx_group ? */ + if(fx_group >= 0) + { + mixer->fx[fx_group].chorus_on = on; + } + /* on/off must be applied to all fx groups */ + else + { + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + mixer->fx[fx_group].chorus_on = on; + } + } + + /* set with_chorus if at least one chorus unit is on */ + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + on = mixer->fx[fx_group].chorus_on; + + if(on) + { + break; + } + } + + mixer->with_chorus = on; +} + void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on) { mixer->mix_fx_to_out = on; @@ -934,33 +1155,57 @@ void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on) DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params) { fluid_rvoice_mixer_t *mixer = obj; - int set = param[0].i; - int nr = param[1].i; - fluid_real_t level = param[2].real; - fluid_real_t speed = param[3].real; - fluid_real_t depth_ms = param[4].real; - int type = param[5].i; + int i = param[0].i; + int set = param[1].i; + int nr = param[2].i; + fluid_real_t level = param[3].real; + fluid_real_t speed = param[4].real; + fluid_real_t depth_ms = param[5].real; + int type = param[6].i; - int i; - for(i = 0; i < mixer->fx_units; i++) + int nr_units = mixer->fx_units; + + /* does parameters must be applied only to fx group i ? */ + if(i >= 0) { - fluid_chorus_set(mixer->fx[i].chorus, set, nr, level, speed, depth_ms, type); + nr_units = i + 1; + } + else + { + i = 0; /* parameters must be applied to all fx groups */ + } + + while(i < nr_units) + { + fluid_chorus_set(mixer->fx[i++].chorus, set, nr, level, speed, depth_ms, type); } } DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params) { fluid_rvoice_mixer_t *mixer = obj; - int set = param[0].i; - fluid_real_t roomsize = param[1].real; - fluid_real_t damping = param[2].real; - fluid_real_t width = param[3].real; - fluid_real_t level = param[4].real; + int i = param[0].i; /* fx group index */ + int set = param[1].i; + fluid_real_t roomsize = param[2].real; + fluid_real_t damping = param[3].real; + fluid_real_t width = param[4].real; + fluid_real_t level = param[5].real; - int i; - for(i = 0; i < mixer->fx_units; i++) + int nr_units = mixer->fx_units; + + /* does parameters change should be applied only to fx group i ? */ + if(i >= 0) { - fluid_revmodel_set(mixer->fx[i].reverb, set, roomsize, damping, width, level); + nr_units = i + 1; /* parameters change must be applied to fx groups i */ + } + else + { + i = 0; /* parameters change must be applied to all fx groups */ + } + + while(i < nr_units) + { + fluid_revmodel_set(mixer->fx[i++].reverb, set, roomsize, damping, width, level); } } @@ -968,6 +1213,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb) { fluid_rvoice_mixer_t *mixer = obj; int i; + for(i = 0; i < mixer->fx_units; i++) { fluid_revmodel_reset(mixer->fx[i].reverb); @@ -978,6 +1224,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus) { fluid_rvoice_mixer_t *mixer = obj; int i; + for(i = 0; i < mixer->fx_units; i++) { fluid_chorus_reset(mixer->fx[i].chorus); diff --git a/src/rvoice/fluid_rvoice_mixer.h b/src/rvoice/fluid_rvoice_mixer.h index acc3fb02..63a456ce 100644 --- a/src/rvoice/fluid_rvoice_mixer.h +++ b/src/rvoice/fluid_rvoice_mixer.h @@ -43,12 +43,33 @@ fluid_rvoice_mixer_t *new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, in void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *); +void +fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]); + +double +fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param); +void +fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]); +double +fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param); + DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice); DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate); DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony); + +/* @deprecated */ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled); +/* @deprecated */ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled); + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable); + DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params); DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params); diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index bf3ac21a..f45da2b7 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -78,6 +78,11 @@ static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t *synth, int chan); static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t *synth, int chan); static int fluid_synth_set_preset(fluid_synth_t *synth, int chan, fluid_preset_t *preset); +static int fluid_synth_reverb_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value); +static int fluid_synth_chorus_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value); + static fluid_preset_t * fluid_synth_get_preset(fluid_synth_t *synth, int sfontnum, int banknum, int prognum); @@ -926,44 +931,35 @@ new_fluid_synth(fluid_settings_t *settings) fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony, synth->polyphony, 0.0f); - fluid_synth_set_reverb_on(synth, synth->with_reverb); - fluid_synth_set_chorus_on(synth, synth->with_chorus); + fluid_synth_reverb_on(synth, -1, synth->with_reverb); + fluid_synth_chorus_on(synth, -1, synth->with_chorus); synth->cur = FLUID_BUFSIZE; synth->curmax = 0; synth->dither_index = 0; { - double room, damp, width, level; + double values[FLUID_REVERB_PARAM_LAST]; - fluid_settings_getnum(settings, "synth.reverb.room-size", &room); - fluid_settings_getnum(settings, "synth.reverb.damp", &damp); - fluid_settings_getnum(settings, "synth.reverb.width", &width); - fluid_settings_getnum(settings, "synth.reverb.level", &level); + fluid_settings_getnum(settings, "synth.reverb.room-size", &values[FLUID_REVERB_ROOMSIZE]); + fluid_settings_getnum(settings, "synth.reverb.damp", &values[FLUID_REVERB_DAMP]); + fluid_settings_getnum(settings, "synth.reverb.width", &values[FLUID_REVERB_WIDTH]); + fluid_settings_getnum(settings, "synth.reverb.level", &values[FLUID_REVERB_LEVEL]); - fluid_synth_set_reverb_full(synth, - FLUID_REVMODEL_SET_ALL, - room, - damp, - width, - level); + fluid_synth_set_reverb_full(synth, -1, FLUID_REVMODEL_SET_ALL, values); } { - double level, speed, depth; + double values[FLUID_CHORUS_PARAM_LAST]; fluid_settings_getint(settings, "synth.chorus.nr", &i); - fluid_settings_getnum(settings, "synth.chorus.level", &level); - fluid_settings_getnum(settings, "synth.chorus.speed", &speed); - fluid_settings_getnum(settings, "synth.chorus.depth", &depth); + values[FLUID_CHORUS_NR] = (double)i; + fluid_settings_getnum(settings, "synth.chorus.level", &values[FLUID_CHORUS_LEVEL]); + fluid_settings_getnum(settings, "synth.chorus.speed", &values[FLUID_CHORUS_SPEED]); + fluid_settings_getnum(settings, "synth.chorus.depth", &values[FLUID_CHORUS_DEPTH]); + values[FLUID_CHORUS_TYPE] = (double)FLUID_CHORUS_DEFAULT_TYPE; - fluid_synth_set_chorus_full(synth, - FLUID_CHORUS_SET_ALL, - i, - level, - speed, - depth, - FLUID_CHORUS_DEFAULT_TYPE); + fluid_synth_set_chorus_full(synth, -1, FLUID_CHORUS_SET_ALL, values); } @@ -4649,31 +4645,31 @@ static void fluid_synth_handle_reverb_chorus_num(void *data, const char *name, d if(FLUID_STRCMP(name, "synth.reverb.room-size") == 0) { - fluid_synth_set_reverb_roomsize(synth, value); + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_ROOMSIZE, value); } else if(FLUID_STRCMP(name, "synth.reverb.damp") == 0) { - fluid_synth_set_reverb_damp(synth, value); + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_DAMP, value); } else if(FLUID_STRCMP(name, "synth.reverb.width") == 0) { - fluid_synth_set_reverb_width(synth, value); + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_WIDTH, value); } else if(FLUID_STRCMP(name, "synth.reverb.level") == 0) { - fluid_synth_set_reverb_level(synth, value); + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_LEVEL, value); } else if(FLUID_STRCMP(name, "synth.chorus.depth") == 0) { - fluid_synth_set_chorus_depth(synth, value); + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_DEPTH, value); } else if(FLUID_STRCMP(name, "synth.chorus.speed") == 0) { - fluid_synth_set_chorus_speed(synth, value); + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_SPEED, value); } else if(FLUID_STRCMP(name, "synth.chorus.level") == 0) { - fluid_synth_set_chorus_level(synth, value); + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_LEVEL, value); } } @@ -4687,15 +4683,15 @@ static void fluid_synth_handle_reverb_chorus_int(void *data, const char *name, i if(FLUID_STRCMP(name, "synth.reverb.active") == 0) { - fluid_synth_set_reverb_on(synth, value); + fluid_synth_reverb_on(synth, -1, value); } else if(FLUID_STRCMP(name, "synth.chorus.active") == 0) { - fluid_synth_set_chorus_on(synth, value); + fluid_synth_chorus_on(synth, -1, value); } else if(FLUID_STRCMP(name, "synth.chorus.nr") == 0) { - fluid_synth_set_chorus_nr(synth, value); + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_NR, (double)value); } } @@ -5464,13 +5460,13 @@ fluid_synth_get_voicelist(fluid_synth_t *synth, fluid_voice_t *buf[], int bufsiz /** * Enable or disable reverb effect. * @param synth FluidSynth instance - * @param on TRUE to enable reverb, FALSE to disable + * @param on TRUE to enable chorus, FALSE to disable + * @deprecated Use fluid_synth_reverb_on() instead. */ void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on) { fluid_return_if_fail(synth != NULL); - fluid_synth_api_enter(synth); synth->with_reverb = (on != 0); @@ -5479,6 +5475,44 @@ fluid_synth_set_reverb_on(fluid_synth_t *synth, int on) fluid_synth_api_exit(synth); } +/** + * Enable or disable reverb on one fx group unit. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param on TRUE to enable reverb, FALSE to disable + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_reverb_on(fluid_synth_t *synth, int fx_group, int on) +{ + int ret; + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if(fx_group < 0 ) + { + synth->with_reverb = (on != 0); + } + + param[0].i = fx_group; + param[1].i = on; + ret = fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_reverb_enable, + synth->eventhandler->mixer, + param); + + FLUID_API_RETURN(ret); +} + /** * Activate a reverb preset. * @param synth FluidSynth instance @@ -5490,19 +5524,23 @@ fluid_synth_set_reverb_on(fluid_synth_t *synth, int on) int fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num) { + double values[FLUID_REVERB_PARAM_LAST]; + fluid_return_val_if_fail( num < FLUID_N_ELEMENTS(revmodel_preset), FLUID_FAILED ); - fluid_synth_set_reverb(synth, revmodel_preset[num].roomsize, - revmodel_preset[num].damp, revmodel_preset[num].width, - revmodel_preset[num].level); + values[FLUID_REVERB_ROOMSIZE] = revmodel_preset[num].roomsize; + values[FLUID_REVERB_DAMP] = revmodel_preset[num].damp; + values[FLUID_REVERB_WIDTH] = revmodel_preset[num].width; + values[FLUID_REVERB_LEVEL] = revmodel_preset[num].level; + fluid_synth_set_reverb_full(synth, -1, FLUID_REVMODEL_SET_ALL, values); return FLUID_OK; } /** - * Set reverb parameters. + * Set reverb parameters to all groups. * * @param synth FluidSynth instance * @param roomsize Reverb room size value (0.0-1.0) @@ -5510,195 +5548,391 @@ fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num) * @param width Reverb width value (0.0-100.0) * @param level Reverb level value (0.0-1.0) * @return #FLUID_OK on success, #FLUID_FAILED otherwise - * - * @note Not realtime safe and therefore should not be called from synthesis - * context at the risk of stalling audio output. + * @deprecated Use the individual reverb setter functions in new code instead. */ int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize, double damping, double width, double level) { - return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_ALL, - roomsize, damping, width, level); + double values[FLUID_REVERB_PARAM_LAST]; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + values[FLUID_REVERB_ROOMSIZE] = roomsize; + values[FLUID_REVERB_DAMP] = damping; + values[FLUID_REVERB_WIDTH] = width; + values[FLUID_REVERB_LEVEL] = level; + return fluid_synth_set_reverb_full(synth, -1, FLUID_REVMODEL_SET_ALL, values); } /** - * Set reverb roomsize. + * Set reverb roomsize of all groups. * * @param synth FluidSynth instance * @param roomsize Reverb room size value (0.0-1.0) * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_roomsize() in new code instead. */ int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize) { - return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_ROOMSIZE, roomsize, 0, 0, 0); + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_ROOMSIZE, roomsize); } /** - * Set reverb damping. + * Set reverb damping of all groups. * * @param synth FluidSynth instance * @param damping Reverb damping value (0.0-1.0) * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_damp() in new code instead. */ int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping) { - return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_DAMPING, 0, damping, 0, 0); + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_DAMP, damping); } /** - * Set reverb width. + * Set reverb width of all groups. * * @param synth FluidSynth instance * @param width Reverb width value (0.0-100.0) * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_width() in new code instead. */ int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width) { - return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_WIDTH, 0, 0, width, 0); + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_WIDTH, width); } /** - * Set reverb level. + * Set reverb level of all groups. * * @param synth FluidSynth instance * @param level Reverb level value (0.0-1.0) * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_level() in new code instead. */ int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level) { - return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_LEVEL, 0, 0, 0, level); + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_LEVEL, level); } /** - * Set one or more reverb parameters. - * - * @param synth FluidSynth instance - * @param set Flags indicating which parameters should be set (#fluid_revmodel_set_t) - * @param roomsize Reverb room size value (0.0-1.2) - * @param damping Reverb damping value (0.0-1.0) - * @param width Reverb width value (0.0-100.0) - * @param level Reverb level value (0.0-1.0) + * Set reverb roomsize to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param roomsize roomsize value to set. Must be in the range indicated by + * synth.reverb.room-size setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int fluid_synth_set_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, + double roomsize) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_ROOMSIZE, roomsize); +} + +/** + * Set reverb damp to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param damping damping value to set. Must be in the range indicated by + * synth.reverb.damp setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_set_reverb_group_damp(fluid_synth_t *synth, int fx_group, + double damping) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_DAMP, damping); +} + +/** + * Set reverb width to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param width width value to set. Must be in the range indicated by + * synth.reverb.width setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_set_reverb_group_width(fluid_synth_t *synth, int fx_group, + double width) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_WIDTH, width); +} + +/** + * Set reverb level to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param level output level to set. Must be in the range indicated by + * synth.reverb.level setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_set_reverb_group_level(fluid_synth_t *synth, int fx_group, + double level) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_LEVEL, level); +} + +/** + * Set one reverb parameter to one fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param enum indicating the parameter to set (#fluid_reverb_param). + * FLUID_REVERB_ROOMSIZE, roomsize Reverb room size value (0.0-1.0) + * FLUID_REVERB_DAMP, reverb damping value (0.0-1.0) + * FLUID_REVERB_WIDTH, reverb width value (0.0-100.0) + * FLUID_REVERB_LEVEL, reverb level value (0.0-1.0) + * @param value, parameter value * @return #FLUID_OK on success, #FLUID_FAILED otherwise - * - * @note Not realtime safe and therefore should not be called from synthesis - * context at the risk of stalling audio output. */ int -fluid_synth_set_reverb_full(fluid_synth_t *synth, int set, double roomsize, - double damping, double width, double level) +fluid_synth_reverb_set_param(fluid_synth_t *synth, int fx_group, + int param, double value) { int ret; - fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + double values[FLUID_REVERB_PARAM_LAST] = {0.0}; + static const char *name[FLUID_REVERB_PARAM_LAST] = + { + "synth.reverb.room-size", "synth.reverb.damp", + "synth.reverb.width", "synth.reverb.level" + }; + double min; /* minimum value */ + double max; /* maximum value */ + + /* check parameters */ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); - /* if non of the flags is set, fail */ - fluid_return_val_if_fail(set & FLUID_REVMODEL_SET_ALL, FLUID_FAILED); - - /* Synth shadow values are set here so that they will be returned if querried */ - + fluid_return_val_if_fail((param >= 0) && (param < FLUID_REVERB_PARAM_LAST), FLUID_FAILED); fluid_synth_api_enter(synth); - if(set & FLUID_REVMODEL_SET_ROOMSIZE) + if(fx_group < -1 || fx_group >= synth->effects_groups) { - synth->reverb_roomsize = roomsize; + FLUID_API_RETURN(FLUID_FAILED); } - if(set & FLUID_REVMODEL_SET_DAMPING) - { - synth->reverb_damping = damping; - } + /* check if reverb value is in max min range */ + fluid_settings_getnum_range(synth->settings, name[param], &min, &max); + fluid_return_val_if_fail( min <= value && value <= max, FLUID_FAILED); - if(set & FLUID_REVMODEL_SET_WIDTH) - { - synth->reverb_width = width; - } - - if(set & FLUID_REVMODEL_SET_LEVEL) - { - synth->reverb_level = level; - } - - param[0].i = set; - param[1].real = roomsize; - param[2].real = damping; - param[3].real = width; - param[4].real = level; - /* finally enqueue an rvoice event to the mixer to actual update reverb */ - ret = fluid_rvoice_eventhandler_push(synth->eventhandler, - fluid_rvoice_mixer_set_reverb_params, - synth->eventhandler->mixer, - param); + /* set the value */ + values[param] = value; + ret = fluid_synth_set_reverb_full(synth, fx_group, FLUID_REVPARAM_TO_SETFLAG(param), values); FLUID_API_RETURN(ret); } +int +fluid_synth_set_reverb_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + /* if non of the flags is set, fail */ + fluid_return_val_if_fail(set & FLUID_REVMODEL_SET_ALL, FLUID_FAILED); + + /* fx group shadow values are set here so that they will be returned if queried */ + fluid_rvoice_mixer_set_reverb_full(synth->eventhandler->mixer, fx_group, set, + values); + + /* Synth shadow values are set here so that they will be returned if queried */ + if (fx_group < 0) + { + int i; + for(i = 0; i < FLUID_REVERB_PARAM_LAST; i++) + { + if(set & FLUID_REVPARAM_TO_SETFLAG(i)) + { + synth->reverb_param[i] = values[i]; + } + } + } + + param[0].i = fx_group; + param[1].i = set; + param[2].real = values[FLUID_REVERB_ROOMSIZE]; + param[3].real = values[FLUID_REVERB_DAMP]; + param[4].real = values[FLUID_REVERB_WIDTH]; + param[5].real = values[FLUID_REVERB_LEVEL]; + /* finally enqueue an rvoice event to the mixer to actual update reverb */ + return fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_set_reverb_params, + synth->eventhandler->mixer, + param); +} + /** - * Get reverb room size. + * Get reverb room size of all fx groups. * @param synth FluidSynth instance * @return Reverb room size (0.0-1.2) + * @deprecated Use fluid_synth_get_reverb_group_roomsize() in new code instead. */ double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - result = synth->reverb_roomsize; - FLUID_API_RETURN(result); + double roomsize = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_ROOMSIZE, &roomsize); + return roomsize; } /** - * Get reverb damping. + * Get reverb damping of all fx groups. * @param synth FluidSynth instance * @return Reverb damping value (0.0-1.0) + * @deprecated Use fluid_synth_get_reverb_group_damp() in new code instead. */ double fluid_synth_get_reverb_damp(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - - result = synth->reverb_damping; - FLUID_API_RETURN(result); + double damp = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_DAMP, &damp); + return damp; } /** - * Get reverb level. + * Get reverb level of all fx groups. * @param synth FluidSynth instance * @return Reverb level value (0.0-1.0) + * @deprecated Use fluid_synth_get_reverb_group_level() in new code instead. */ double fluid_synth_get_reverb_level(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - - result = synth->reverb_level; - FLUID_API_RETURN(result); + double level = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_LEVEL, &level); + return level; } /** - * Get reverb width. + * Get reverb width of all fx groups. * @param synth FluidSynth instance * @return Reverb width value (0.0-100.0) + * @deprecated Use fluid_synth_get_reverb_group_width() in new code instead. */ double fluid_synth_get_reverb_width(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - - result = synth->reverb_width; - FLUID_API_RETURN(result); + double width = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_WIDTH, &width); + return width; } /** - * Enable or disable chorus effect. + * get reverb roomsize of one or all groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param roomsize valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int fluid_synth_get_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, + double *roomsize) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_ROOMSIZE, roomsize); +} + +/** + * get reverb damp of one or all groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param damping valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_get_reverb_group_damp(fluid_synth_t *synth, int fx_group, + double *damping) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_DAMP, damping); +} + +/** + * get reverb width of one or all groups + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param width valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_get_reverb_group_width(fluid_synth_t *synth, int fx_group, + double *width) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_WIDTH, width); +} + +/** + * get reverb level of one or all groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param level valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_get_reverb_group_level(fluid_synth_t *synth, int fx_group, + double *level) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_LEVEL, level); +} + + +/** + * Get one reverb parameter value of one fx groups. + * @param synth FluidSynth instance + * @param fx_group index of the fx group to get parameter value from. + * Must be in the range -1 to synth->effects_groups-1. If -1 get the + * parameter common to all fx groups. + * @param enum indicating the parameter to get (#fluid_reverb_param). + * FLUID_REVERB_ROOMSIZE, reverb room size value. + * FLUID_REVERB_DAMP, reverb damping value. + * FLUID_REVERB_WIDTH, reverb width value. + * FLUID_REVERB_LEVEL, reverb level value. + * @param value pointer on the value to return. + * @return FLUID_OK if success, FLUID_FAILED otherwise. + */ +static int fluid_synth_reverb_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value) +{ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_REVERB_PARAM_LAST), FLUID_FAILED); + fluid_return_val_if_fail(value != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if (fx_group < 0) + { + /* return reverb param common to all fx groups */ + *value = synth->reverb_param[param]; + } + else + { + /* return reverb param of fx group at index fx_group */ + *value = fluid_rvoice_mixer_reverb_get_param(synth->eventhandler->mixer, + fx_group, param); + } + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Enable or disable all chorus groups. * @param synth FluidSynth instance * @param on TRUE to enable chorus, FALSE to disable + * @deprecated Use fluid_synth_chorus_on() in new code instead. */ void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on) @@ -5713,137 +5947,37 @@ fluid_synth_set_chorus_on(fluid_synth_t *synth, int on) } /** - * Set chorus parameters. - * + * Enable or disable chorus on one or all groups. * @param synth FluidSynth instance - * @param nr Chorus voice count (0-99, CPU time consumption proportional to - * this value) - * @param level Chorus level (0.0-10.0) - * @param speed Chorus speed in Hz (0.1-5.0) - * @param depth_ms Chorus depth (max value depends on synth sample-rate, - * 0.0-21.0 is safe for sample-rate values up to 96KHz) - * @param type Chorus waveform type (#fluid_chorus_mod) - * @return #FLUID_OK on success, #FLUID_FAILED otherwise - * - * It should be turned on with fluid_synth_set_chorus_on(). - * Keep in mind, that the needed CPU time is proportional to 'nr'. - */ -int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level, - double speed, double depth_ms, int type) -{ - return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_ALL, nr, level, speed, - depth_ms, type); -} - -/** - * Set the chorus voice count. - * - * @param synth FluidSynth instance - * @param nr Chorus voice count (0-99, CPU time consumption proportional to - * this value) + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param on TRUE to enable chorus, FALSE to disable * @return #FLUID_OK on success, #FLUID_FAILED otherwise */ -int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr) -{ - return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_NR, nr, 0, 0, 0, 0); -} - -/** - * Set the chorus level. - * - * @param synth FluidSynth instance - * @param level Chorus level (0.0-10.0) - * @return #FLUID_OK on success, #FLUID_FAILED otherwise - */ -int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level) -{ - return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_LEVEL, 0, level, 0, 0, 0); -} - -/** - * Set the chorus speed. - * - * @param synth FluidSynth instance - * @param speed Chorus speed in Hz (0.1-5.0) - * @return #FLUID_OK on success, #FLUID_FAILED otherwise - */ -int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed) -{ - return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_SPEED, 0, 0, speed, 0, 0); -} - -/** - * Set the chorus depth. - * - * @param synth FluidSynth instance - * @param depth_ms Chorus depth (max value depends on synth sample-rate, - * 0.0-21.0 is safe for sample-rate values up to 96KHz) - * @return #FLUID_OK on success, #FLUID_FAILED otherwise - */ -int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms) -{ - return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_DEPTH, 0, 0, 0, depth_ms, 0); -} - -/** - * Set the chorus type. - * - * @param synth FluidSynth instance - * @param type Chorus waveform type (#fluid_chorus_mod) - * @return #FLUID_OK on success, #FLUID_FAILED otherwise - */ -int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type) -{ - return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_TYPE, 0, 0, 0, 0, type); -} - int -fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level, - double speed, double depth_ms, int type) +fluid_synth_chorus_on(fluid_synth_t *synth, int fx_group, int on) { int ret; - fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; - + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); - /* if non of the flags is set, fail */ - fluid_return_val_if_fail(set & FLUID_CHORUS_SET_ALL, FLUID_FAILED); - /* Synth shadow values are set here so that they will be returned if queried */ fluid_synth_api_enter(synth); - if(set & FLUID_CHORUS_SET_NR) + if(fx_group < -1 || fx_group >= synth->effects_groups) { - synth->chorus_nr = nr; + FLUID_API_RETURN(FLUID_FAILED); } - if(set & FLUID_CHORUS_SET_LEVEL) + if(fx_group < 0 ) { - synth->chorus_level = level; + synth->with_chorus = (on != 0); } - if(set & FLUID_CHORUS_SET_SPEED) - { - synth->chorus_speed = speed; - } - - if(set & FLUID_CHORUS_SET_DEPTH) - { - synth->chorus_depth = depth_ms; - } - - if(set & FLUID_CHORUS_SET_TYPE) - { - synth->chorus_type = type; - } - - param[0].i = set; - param[1].i = nr; - param[2].real = level; - param[3].real = speed; - param[4].real = depth_ms; - param[5].i = type; + param[0].i = fx_group; + param[1].i = on; ret = fluid_rvoice_eventhandler_push(synth->eventhandler, - fluid_rvoice_mixer_set_chorus_params, + fluid_rvoice_mixer_chorus_enable, synth->eventhandler->mixer, param); @@ -5851,83 +5985,476 @@ fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level, } /** - * Get chorus voice number (delay line count) value. + * Set chorus parameters to all fx groups. + * Keep in mind, that the needed CPU time is proportional to 'nr'. + * @param synth FluidSynth instance + * @param nr Chorus voice count (0-99, CPU time consumption proportional to + * this value) + * @param level Chorus level (0.0-10.0) + * @param speed Chorus speed in Hz (0.1-5.0) + * @param depth_ms Chorus depth (max value depends on synth sample-rate, + * 0.0-21.0 is safe for sample-rate values up to 96KHz) + * @param type Chorus waveform type (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use the individual chorus setter functions in new code instead. + * + * Keep in mind, that the needed CPU time is proportional to 'nr'. + */ +int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level, + double speed, double depth_ms, int type) +{ + double values[FLUID_CHORUS_PARAM_LAST]; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + values[FLUID_CHORUS_NR] = nr; + values[FLUID_CHORUS_LEVEL] = level; + values[FLUID_CHORUS_SPEED] = speed; + values[FLUID_CHORUS_DEPTH] = depth_ms; + values[FLUID_CHORUS_TYPE] = type; + return fluid_synth_set_chorus_full(synth, -1, FLUID_CHORUS_SET_ALL, values); +} + +/** + * Set the chorus voice count of all groups. + * + * @param synth FluidSynth instance + * @param nr Chorus voice count (0-99, CPU time consumption proportional to + * this value) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_nr() in new code instead. + */ +int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_NR, nr); +} + +/** + * Set the chorus level of all groups. + * + * @param synth FluidSynth instance + * @param level Chorus level (0.0-10.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_level() in new code instead. + */ +int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_LEVEL, level); +} + +/** + * Set the chorus speed of all groups. + * + * @param synth FluidSynth instance + * @param speed Chorus speed in Hz (0.1-5.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_level() in new code instead. + */ +int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_SPEED, speed); +} + +/** + * Set the chorus depth of all groups. + * + * @param synth FluidSynth instance + * @param depth_ms Chorus depth (max value depends on synth sample-rate, + * 0.0-21.0 is safe for sample-rate values up to 96KHz) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_depth() in new code instead. + */ +int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_DEPTH, depth_ms); +} + +/** + * Set the chorus type of all groups. + * + * @param synth FluidSynth instance + * @param type Chorus waveform type (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_type() in new code instead. + */ +int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_TYPE, type); +} + +/** + * Set chorus voice count nr to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param nr Voice count to set. Must be in the range indicated by \setting{synth_chorus_nr} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_nr(fluid_synth_t *synth, int fx_group, int nr) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_NR, (double)nr); +} + +/** + * Set chorus output level to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param level Output level to set. Must be in the range indicated by \setting{synth_chorus_level} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_level(fluid_synth_t *synth, int fx_group, double level) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_LEVEL, level); +} + +/** + * Set chorus lfo speed to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param speed Lfo speed to set. Must be in the range indicated by \settings{synth_chorus_speed} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_speed(fluid_synth_t *synth, int fx_group, double speed) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_SPEED, speed); +} + +/** + * Set chorus lfo depth to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @depth_ms, lfo depth to set. Must be in the range indicated by synth.chorus.depth + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_depth(fluid_synth_t *synth, int fx_group, double depth_ms) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_DEPTH, depth_ms); +} + +/** + * Set chorus lfo waveform type to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param type Lfo waveform type to set. (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_type(fluid_synth_t *synth, int fx_group, int type) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_TYPE, (double)type); +} + +/** + * Set one chorus parameter to one fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param enum indicating the parameter to set (#fluid_chorus_param). + * FLUID_CHORUS_NR, chorus voice count (0-99, CPU time consumption proportional to + * this value). + * FLUID_CHORUS_LEVEL, chorus level (0.0-10.0). + * FLUID_CHORUS_SPEED, chorus speed in Hz (0.1-5.0). + * FLUID_CHORUS_DEPTH, chorus depth (max value depends on synth sample-rate, + * 0.0-21.0 is safe for sample-rate values up to 96KHz). + * FLUID_CHORUS_TYPE, chorus waveform type (#fluid_chorus_mod) + * @param value, parameter value + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_chorus_set_param(fluid_synth_t *synth, int fx_group, int param, + double value) +{ + int ret; + double values[FLUID_CHORUS_PARAM_LAST] = {0.0}; + + /* setting name (except lfo waveform type) */ + static const char *name[FLUID_CHORUS_PARAM_LAST-1] = + { + "synth.chorus.nr", "synth.chorus.level", + "synth.chorus.speed", "synth.chorus.depth" + }; + + /* check parameters */ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_CHORUS_PARAM_LAST), FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + /* check if chorus value is in max min range */ + if(param == FLUID_CHORUS_TYPE || param == FLUID_CHORUS_NR) /* integer value */ + { + int min = FLUID_CHORUS_MOD_SINE; + int max = FLUID_CHORUS_MOD_TRIANGLE; + if(param == FLUID_CHORUS_NR) + { + fluid_settings_getint_range(synth->settings, name[param], &min, &max); + } + fluid_return_val_if_fail(min <= (int)value && (int)value <= max, FLUID_FAILED); + } + else /* float value */ + { + double min; + double max; + fluid_settings_getnum_range(synth->settings, name[param], &min, &max); + fluid_return_val_if_fail(min <= value && value <= max, FLUID_FAILED); + } + + /* set the value */ + values[param] = value; + ret = fluid_synth_set_chorus_full(synth, fx_group, + FLUID_CHORPARAM_TO_SETFLAG(param), values); + FLUID_API_RETURN(ret); +} + +int +fluid_synth_set_chorus_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + /* if non of the flags is set, fail */ + fluid_return_val_if_fail(set & FLUID_CHORUS_SET_ALL, FLUID_FAILED); + + /* fx group shadow values are set here so that they will be returned if queried */ + fluid_rvoice_mixer_set_chorus_full(synth->eventhandler->mixer, fx_group, + set, values); + + /* Synth shadow values are set here so that they will be returned if queried */ + if (fx_group < 0) + { + int i; + for(i = 0; i < FLUID_CHORUS_PARAM_LAST; i++) + { + if(set & FLUID_CHORPARAM_TO_SETFLAG(i)) + { + synth->chorus_param[i] = values[i]; + } + } + } + + param[0].i = fx_group; + param[1].i = set; + param[2].i = (int)values[FLUID_CHORUS_NR]; + param[3].real = values[FLUID_CHORUS_LEVEL]; + param[4].real = values[FLUID_CHORUS_SPEED]; + param[5].real = values[FLUID_CHORUS_DEPTH]; + param[6].i = (int)values[FLUID_CHORUS_TYPE]; + return fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_set_chorus_params, + synth->eventhandler->mixer, + param); +} + +/** + * Get chorus voice number (delay line count) value of all fx groups. * @param synth FluidSynth instance * @return Chorus voice count + * @deprecated Use fluid_synth_get_chorus_group_nr() in new code instead. */ int fluid_synth_get_chorus_nr(fluid_synth_t *synth) { - int result; - fluid_return_val_if_fail(synth != NULL, 0); - fluid_synth_api_enter(synth); - - result = synth->chorus_nr; - FLUID_API_RETURN(result); + double nr = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_NR, &nr); + return (int)nr; } /** - * Get chorus level. + * Get chorus level of all fx groups. * @param synth FluidSynth instance * @return Chorus level value + * @deprecated Use fluid_synth_get_chorus_group_level() in new code instead. */ double fluid_synth_get_chorus_level(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - - result = synth->chorus_level; - FLUID_API_RETURN(result); + double level = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_LEVEL, &level); + return level; } /** - * Get chorus speed in Hz. + * Get chorus speed in Hz of all fx groups. * @param synth FluidSynth instance * @return Chorus speed in Hz + * @deprecated Use fluid_synth_get_chorus_group_speed() in new code instead. */ double fluid_synth_get_chorus_speed(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - - result = synth->chorus_speed; - FLUID_API_RETURN(result); + double speed = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_SPEED, &speed); + return speed; } /** - * Get chorus depth. + * Get chorus depth of all fx groups. * @param synth FluidSynth instance * @return Chorus depth + * @deprecated Use fluid_synth_get_chorus_group_depth() in new code instead. */ double fluid_synth_get_chorus_depth(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); - fluid_synth_api_enter(synth); - - result = synth->chorus_depth; - FLUID_API_RETURN(result); + double depth = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_DEPTH, &depth); + return depth; } /** - * Get chorus waveform type. + * Get chorus waveform type of all fx groups. * @param synth FluidSynth instance * @return Chorus waveform type (#fluid_chorus_mod) + * @deprecated Use fluid_synth_get_chorus_group_type() in new code instead. */ int fluid_synth_get_chorus_type(fluid_synth_t *synth) { - int result; - fluid_return_val_if_fail(synth != NULL, 0); + double type = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_TYPE, &type); + return (int)type; +} + +/** + * Get chorus count nr of one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group from which to fetch the chorus voice count. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param nr valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_get_chorus_group_nr(fluid_synth_t *synth, int fx_group, int *nr) +{ + double num_nr = 0.0; + int status; + status = fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_NR, &num_nr); + *nr = (int)num_nr; + return status; +} + +/** + * Get chorus output level of one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group from which chorus level to fetch. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param level valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_get_chorus_group_level(fluid_synth_t *synth, int fx_group, double *level) +{ + return fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_LEVEL, level); +} + +/** + * Get chorus waveform lfo speed of one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group from which lfo speed to fetch. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param speed valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_get_chorus_group_speed(fluid_synth_t *synth, int fx_group, double *speed) +{ + return fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_SPEED, speed); +} + +/** + * Get chorus lfo depth of one or all fx groups. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group from which lfo depth to fetch. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param depth valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_chorus_group_depth(fluid_synth_t *synth, int fx_group, double *depth_ms) +{ + return fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_DEPTH, depth_ms); +} + +/** + * Get chorus waveform type of one or all fx groups. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group from which to fetch the waveform type. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param type valid pointer on waveform type to return (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_chorus_group_type(fluid_synth_t *synth, int fx_group, int *type) +{ + double num_type = 0.0; + int status; + status = fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_TYPE, &num_type); + *type = (int)num_type; + return status; +} + +/** + * Get chorus parameter value of one or all fx groups. + * @param synth FluidSynth instance + * @param fx_group index of the fx group + * @param enum indicating the parameter to get. + * FLUID_CHORUS_NR, chorus voice count. + * FLUID_CHORUS_LEVEL, chorus level. + * FLUID_CHORUS_SPEED, chorus speed. + * FLUID_CHORUS_DEPTH, chorus depth. + * FLUID_CHORUS_TYPE, chorus waveform type. + * @param value pointer on the value to return. + * @return FLUID_OK if success, FLUID_FAILED otherwise. + */ +static int fluid_synth_chorus_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value) +{ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_CHORUS_PARAM_LAST), FLUID_FAILED); + fluid_return_val_if_fail(value != NULL, FLUID_FAILED); fluid_synth_api_enter(synth); - result = synth->chorus_type; - FLUID_API_RETURN(result); + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if (fx_group < 0) + { + /* return chorus param common to all fx groups */ + *value = synth->chorus_param[param]; + } + else + { + /* return chorus param of fx group at index group */ + *value = fluid_rvoice_mixer_chorus_get_param(synth->eventhandler->mixer, + fx_group, param); + } + + FLUID_API_RETURN(FLUID_OK); } /* @@ -6082,6 +6609,8 @@ fluid_synth_count_effects_channels(fluid_synth_t *synth) /** * Get the total number of allocated effects units. + * + * This is the same number as initially provided by the setting \setting{synth_effects-groups}. * @param synth FluidSynth instance * @return Count of allocated effects units */ diff --git a/src/synth/fluid_synth.h b/src/synth/fluid_synth.h index ab929b34..791ce074 100644 --- a/src/synth/fluid_synth.h +++ b/src/synth/fluid_synth.h @@ -138,16 +138,11 @@ struct _fluid_synth_t int fromkey_portamento; /**< fromkey portamento */ fluid_rvoice_eventhandler_t *eventhandler; - double reverb_roomsize; /**< Shadow of reverb roomsize */ - double reverb_damping; /**< Shadow of reverb damping */ - double reverb_width; /**< Shadow of reverb width */ - double reverb_level; /**< Shadow of reverb level */ + /**< Shadow of reverb parameter: roomsize, damping, width, level */ + double reverb_param[FLUID_REVERB_PARAM_LAST]; - int chorus_nr; /**< Shadow of chorus number */ - double chorus_level; /**< Shadow of chorus level */ - double chorus_speed; /**< Shadow of chorus speed */ - double chorus_depth; /**< Shadow of chorus depth */ - int chorus_type; /**< Shadow of chorus type */ + /**< Shadow of chorus parameter: chorus number, level, speed, depth, type */ + double chorus_param[FLUID_CHORUS_PARAM_LAST]; int cur; /**< the current sample in the audio buffers to be output */ int curmax; /**< current amount of samples present in the audio buffers */ @@ -219,12 +214,17 @@ void fluid_synth_dither_s16(int *dither_index, int len, const float *lin, const int fluid_synth_reset_reverb(fluid_synth_t *synth); int fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num); -int fluid_synth_set_reverb_full(fluid_synth_t *synth, int set, double roomsize, - double damping, double width, double level); +int fluid_synth_reverb_set_param(fluid_synth_t *synth, int fx_group, + int param, + double value); +int fluid_synth_set_reverb_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]); int fluid_synth_reset_chorus(fluid_synth_t *synth); -int fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level, - double speed, double depth_ms, int type); +int fluid_synth_chorus_set_param(fluid_synth_t *synth, int fx_group, + int param, double value); +int fluid_synth_set_chorus_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]); fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data); void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer); diff --git a/src/utils/fluidsynth_priv.h b/src/utils/fluidsynth_priv.h index 8d929c96..fe5bc507 100644 --- a/src/utils/fluidsynth_priv.h +++ b/src/utils/fluidsynth_priv.h @@ -98,7 +98,7 @@ typedef union _fluid_rvoice_param_t int i; fluid_real_t real; } fluid_rvoice_param_t; -enum { MAX_EVENT_PARAMS = 6 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */ +enum { MAX_EVENT_PARAMS = 7 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */ typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS]); /* Macro for declaring an rvoice event function (#fluid_rvoice_function_t). The functions may only access diff --git a/test/test_synth_chorus_reverb.c b/test/test_synth_chorus_reverb.c index 7c372d9b..14c7d716 100644 --- a/test/test_synth_chorus_reverb.c +++ b/test/test_synth_chorus_reverb.c @@ -2,18 +2,25 @@ #include "test.h" #include "fluidsynth.h" -// this test should make sure that sample rate changed are handled correctly +// this test should make sure that effects change (reverb, chorus) are handled correctly int main(void) { fluid_synth_t *synth; fluid_settings_t *settings = new_fluid_settings(); - TEST_ASSERT(settings != NULL); + double value; + int int_value; + TEST_ASSERT(settings != NULL); + /* set 2 group of effects */ + TEST_SUCCESS(fluid_settings_setint(settings, "synth.effects-groups", 2)); + + /* set values for all reverb group */ TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.room-size", 0.1)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.damp", 0.2)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.width", 0.3)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.level", 0.4)); + /* set values for all chorus group */ TEST_SUCCESS(fluid_settings_setint(settings, "synth.chorus.nr", 99)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.chorus.level", 0.5)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.chorus.speed", 0.6)); @@ -22,18 +29,28 @@ int main(void) synth = new_fluid_synth(settings); TEST_ASSERT(synth != NULL); - // check that the synth is initialized with the correct values - TEST_ASSERT(fluid_synth_get_reverb_roomsize(synth) == 0.1); - TEST_ASSERT(fluid_synth_get_reverb_damp(synth) == 0.2); - TEST_ASSERT(fluid_synth_get_reverb_width(synth) == 0.3); - TEST_ASSERT(fluid_synth_get_reverb_level(synth) == 0.4); + /* + check that the synth is initialized with the correct values (for all reverb group) + */ + TEST_ASSERT(fluid_synth_get_reverb_group_roomsize(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.1); + TEST_ASSERT(fluid_synth_get_reverb_group_damp(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.2); + TEST_ASSERT(fluid_synth_get_reverb_group_width(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.3); + TEST_ASSERT(fluid_synth_get_reverb_group_level(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.4); - TEST_ASSERT(fluid_synth_get_chorus_nr(synth) == 99); - TEST_ASSERT(fluid_synth_get_chorus_level(synth) == 0.5); - TEST_ASSERT(fluid_synth_get_chorus_speed(synth) == 0.6); - TEST_ASSERT(fluid_synth_get_chorus_depth(synth) == 0.7); + TEST_ASSERT(fluid_synth_get_chorus_group_nr(synth, -1, &int_value) == FLUID_OK); + TEST_ASSERT(int_value == 99); + TEST_ASSERT(fluid_synth_get_chorus_group_level(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.5); + TEST_ASSERT(fluid_synth_get_chorus_group_speed(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.6); + TEST_ASSERT(fluid_synth_get_chorus_group_depth(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.7); - // update the realtime settings afterward + // update the realtime settings for all reverb group and all chorus group afterward TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.room-size", 0.11)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.damp", 0.22)); TEST_SUCCESS(fluid_settings_setnum(settings, "synth.reverb.width", 0.33)); @@ -45,15 +62,131 @@ int main(void) TEST_SUCCESS(fluid_settings_setnum(settings, "synth.chorus.depth", 0.77)); // check that the realtime settings correctly update the values in the synth - TEST_ASSERT(fluid_synth_get_reverb_roomsize(synth) == 0.11); - TEST_ASSERT(fluid_synth_get_reverb_damp(synth) == 0.22); - TEST_ASSERT(fluid_synth_get_reverb_width(synth) == 0.33); - TEST_ASSERT(fluid_synth_get_reverb_level(synth) == 0.44); + TEST_ASSERT(fluid_synth_get_reverb_group_roomsize(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.11); + TEST_ASSERT(fluid_synth_get_reverb_group_damp(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.22); + TEST_ASSERT(fluid_synth_get_reverb_group_width(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.33); + TEST_ASSERT(fluid_synth_get_reverb_group_level(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.44); - TEST_ASSERT(fluid_synth_get_chorus_nr(synth) == 11); - TEST_ASSERT(fluid_synth_get_chorus_level(synth) == 0.55); - TEST_ASSERT(fluid_synth_get_chorus_speed(synth) == 0.66); - TEST_ASSERT(fluid_synth_get_chorus_depth(synth) == 0.77); + TEST_ASSERT(fluid_synth_get_chorus_group_nr(synth, -1, &int_value) == FLUID_OK); + TEST_ASSERT(int_value == 11); + TEST_ASSERT(fluid_synth_get_chorus_group_level(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.55); + TEST_ASSERT(fluid_synth_get_chorus_group_speed(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.66); + TEST_ASSERT(fluid_synth_get_chorus_group_depth(synth, -1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.77); + + /* + Set/get that the synth is initialized with the correct values for one group only + calling fx set/get API + */ + // test reverb invalid parameters range + // room size valid range: 0.0..1.0 + TEST_ASSERT(fluid_synth_set_reverb_group_roomsize(synth, 0, 1.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_reverb_group_roomsize(synth, 0, -0.1) == FLUID_FAILED); + + // damp valid range: 0.0..1.0 + TEST_ASSERT(fluid_synth_set_reverb_group_damp(synth, 0, 1.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_reverb_group_damp(synth, 0, -0.1) == FLUID_FAILED); + + // width valid range: 0.0..100.0 + TEST_ASSERT(fluid_synth_set_reverb_group_width(synth, 0, 100.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_reverb_group_width(synth, 0, -0.1) == FLUID_FAILED); + + // level valid range: 0.0..1.0 + TEST_ASSERT(fluid_synth_set_reverb_group_level(synth, 0, 1.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_reverb_group_level(synth, 0, -0.1) == FLUID_FAILED); + + // test chorus invalid parameters range + // number of chorus block valid range: 0..99 + TEST_ASSERT(fluid_synth_set_chorus_group_nr(synth, 1, 100) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_chorus_group_nr(synth, 1, -1) == FLUID_FAILED); + + // level valid range: 0..10 + TEST_ASSERT(fluid_synth_set_chorus_group_level(synth, 0, 10.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_chorus_group_level(synth, 0, -0.1) == FLUID_FAILED); + + // lfo speed valid range: 0.1..5.0 + TEST_ASSERT(fluid_synth_set_chorus_group_speed(synth, 0, 5.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_chorus_group_speed(synth, 0, 0.09) == FLUID_FAILED); + + // lfo depth valid range: 0..256 + TEST_ASSERT(fluid_synth_set_chorus_group_depth(synth, 0, 256.1) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_chorus_group_depth(synth, 0, -0.1) == FLUID_FAILED); + + // lfo wafeform type valid range: 0..1 + TEST_ASSERT(fluid_synth_set_chorus_group_type(synth, 0, 2) == FLUID_FAILED); + TEST_ASSERT(fluid_synth_set_chorus_group_type(synth, 0, -1) == FLUID_FAILED); + + // set a value and check if we get the same value to reverb group 0 + TEST_ASSERT(fluid_synth_set_reverb_group_roomsize(synth, 0, 0.1110) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_reverb_group_damp(synth, 0, 0.2220) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_reverb_group_width(synth, 0, 0.3330) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_reverb_group_level(synth, 0, 0.4440) == FLUID_OK); + + TEST_ASSERT(fluid_synth_get_reverb_group_roomsize(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.1110); + TEST_ASSERT(fluid_synth_get_reverb_group_damp(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.2220); + TEST_ASSERT(fluid_synth_get_reverb_group_width(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.3330); + TEST_ASSERT(fluid_synth_get_reverb_group_level(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.4440); + + // set a value and check if we get the same value to reverb group 1 + TEST_ASSERT(fluid_synth_set_reverb_group_roomsize(synth, 1, 0.1111) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_reverb_group_damp(synth, 1, 0.2221) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_reverb_group_width(synth, 1, 0.3331) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_reverb_group_level(synth, 1, 0.4441) == FLUID_OK); + + TEST_ASSERT(fluid_synth_get_reverb_group_roomsize(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.1111); + TEST_ASSERT(fluid_synth_get_reverb_group_damp(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.2221); + TEST_ASSERT(fluid_synth_get_reverb_group_width(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.3331); + TEST_ASSERT(fluid_synth_get_reverb_group_level(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.4441); + + // set a value and check if we get the same value to chorus group 0 + TEST_ASSERT(fluid_synth_set_chorus_group_nr(synth, 0, 20) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_level(synth, 0, 0.5550) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_speed(synth, 0, 0.6660) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_depth(synth, 0, 0.7770) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_type(synth, 0, 0) == FLUID_OK); + + TEST_ASSERT(fluid_synth_get_chorus_group_nr(synth, 0, &int_value) == FLUID_OK); + TEST_ASSERT(int_value == 20); + TEST_ASSERT(fluid_synth_get_chorus_group_level(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.5550); + TEST_ASSERT(fluid_synth_get_chorus_group_speed(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.6660); + TEST_ASSERT(fluid_synth_get_chorus_group_depth(synth, 0, &value) == FLUID_OK); + TEST_ASSERT(value == 0.7770); + TEST_ASSERT(fluid_synth_get_chorus_group_type(synth, 0, &int_value) == FLUID_OK); + TEST_ASSERT(int_value == 0); + + // set a value and check if we get the same value to chorus group 1 + TEST_ASSERT(fluid_synth_set_chorus_group_nr(synth, 1, 21) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_level(synth, 1, 0.5551) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_speed(synth, 1, 0.6661) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_depth(synth, 1, 0.7771) == FLUID_OK); + TEST_ASSERT(fluid_synth_set_chorus_group_type(synth, 1, 1) == FLUID_OK); + + TEST_ASSERT(fluid_synth_get_chorus_group_nr(synth, 1, &int_value) == FLUID_OK); + TEST_ASSERT(int_value == 21); + TEST_ASSERT(fluid_synth_get_chorus_group_level(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.5551); + TEST_ASSERT(fluid_synth_get_chorus_group_speed(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.6661); + TEST_ASSERT(fluid_synth_get_chorus_group_depth(synth, 1, &value) == FLUID_OK); + TEST_ASSERT(value == 0.7771); + TEST_ASSERT(fluid_synth_get_chorus_group_type(synth, 1, &int_value) == FLUID_OK); + TEST_ASSERT(int_value == 1); delete_fluid_synth(synth); delete_fluid_settings(settings);