Skip to content

Commit

Permalink
Add support for absolute transform (#1409)
Browse files Browse the repository at this point in the history
Add support for absolute transform modulators

---------

Co-authored-by: derselbst <[email protected]>
  • Loading branch information
spessasus and derselbst authored Oct 26, 2024
1 parent 98b1d3e commit 98b115f
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 8 deletions.
1 change: 1 addition & 0 deletions doc/recent_changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- synth.device-id now has a default value of 16
- synth.gain now has a default value of 0.6
- Default values of reverb and chorus settings have been tuned
- fluid_mod_get_transform() and fluid_mod_set_transform() for SoundFont 2.04 compliant modulators

\section NewIn2_3_2 What's new in 2.3.2?

Expand Down
11 changes: 11 additions & 0 deletions include/fluidsynth/mod.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ enum fluid_mod_flags
FLUID_MOD_SIN = 0x80, /**< Custom non-standard sinus mapping function */
};

/**
* Transform types for the SoundFont2 modulators as defined by SoundFont 2.04 section 8.3.
*/
enum fluid_mod_transforms
{
FLUID_MOD_TRANSFORM_LINEAR = 0, /**< Linear: directly add the computed value to summing node */
FLUID_MOD_TRANSFORM_ABS = 2 /**< Abs: add the absolute value of the computed to summing node */
};

/**
* General controller (if #FLUID_MOD_GC in flags). This
* corresponds to SoundFont 2.04 PDF section 8.2.1
Expand All @@ -83,13 +92,15 @@ FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags);
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags);
FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t *mod, int dst);
FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t *mod, double amount);
FLUIDSYNTH_API void fluid_mod_set_transform(fluid_mod_t *mod, int type);

FLUIDSYNTH_API int fluid_mod_get_source1(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_flags1(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_source2(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_flags2(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_dest(const fluid_mod_t *mod);
FLUIDSYNTH_API double fluid_mod_get_amount(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_transform(fluid_mod_t *mod);

FLUIDSYNTH_API int fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2);
FLUIDSYNTH_API int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl);
Expand Down
16 changes: 11 additions & 5 deletions src/sfloader/fluid_defsfont.c
Original file line number Diff line number Diff line change
Expand Up @@ -1639,7 +1639,7 @@ fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone)
/* Note: When secondary source input (src2) is set to General Controller 'No Controller',
output will be forced to +1.0 at synthesis time (see fluid_mod_get_value()).
That means that this source will behave unipolar only. We need to force the
unipolar flag to ensure to ensure a correct evaluation of the minimum
unipolar flag to ensure a correct evaluation of the minimum
value later (see fluid_voice_get_lower_boundary_for_attenuation()).
*/
if(((mod_dest->flags2 & FLUID_MOD_CC) == FLUID_MOD_GC) &&
Expand All @@ -1648,13 +1648,19 @@ fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone)
mod_dest->flags2 &= ~FLUID_MOD_BIPOLAR;
}

/* *** Transform *** */
/* SF2.01 only uses the 'linear' transform (0).
* Deactivate the modulator by setting the amount to 0 in any other case.
/**
* *** Transform Type ***
* Only 2 types of transform are defined in the sf2 specification.
*/
if(mod_src->trans != 0)
if(mod_src->trans != FLUID_MOD_TRANSFORM_LINEAR && mod_src->trans != FLUID_MOD_TRANSFORM_ABS)
{
/* disable the modulator as the transform is invalid */
mod_dest->amount = 0;
mod_dest->trans = FLUID_MOD_TRANSFORM_LINEAR;
}
else
{
mod_dest->trans = mod_src->trans;
}

/* Store the new modulator in the zone The order of modulators
Expand Down
46 changes: 43 additions & 3 deletions src/synth/fluid_mod.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src)
mod->src2 = src->src2;
mod->flags2 = src->flags2;
mod->amount = src->amount;
mod->trans = src->trans;
}

/**
Expand Down Expand Up @@ -97,6 +98,24 @@ fluid_mod_set_amount(fluid_mod_t *mod, double amount)
mod->amount = (double) amount;
}

/**
* Set the transform type of a modulator.
*
* @param mod The modulator instance
* @param type Transform type, see #fluid_mod_transforms
*/
void
fluid_mod_set_transform(fluid_mod_t *mod, int type)
{
unsigned char flag = (unsigned char) type;
if(flag != FLUID_MOD_TRANSFORM_LINEAR && flag != FLUID_MOD_TRANSFORM_ABS)
{
FLUID_LOG(FLUID_ERR, "fluid_mod_set_transform() called with invalid transform type %d", type);
return;
}
mod->trans = flag;
}

/**
* Get the primary source value from a modulator.
*
Expand Down Expand Up @@ -169,6 +188,18 @@ fluid_mod_get_amount(const fluid_mod_t *mod)
return (double) mod->amount;
}

/**
* Get the transform type of a modulator.
*
* @param mod The modulator instance
* @param type Transform type, see #fluid_mod_transforms
*/
int
fluid_mod_get_transform(fluid_mod_t *mod)
{
return (int) mod->trans;
}

/*
* retrieves the initial value from the given source of the modulator
*/
Expand Down Expand Up @@ -382,6 +413,7 @@ fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
extern fluid_mod_t default_vel2filter_mod;

fluid_real_t v1 = 0.0, v2 = 1.0;
fluid_real_t final_value;
/* The wording of the default modulators refers to a range of 127/128.
* And the table in section 9.5.3 suggests, that this mapping should be applied
* to all unipolar and bipolar mappings respectively.
Expand Down Expand Up @@ -470,8 +502,15 @@ fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
v2 = 1.0f;
}

/* it's as simple as that: */
return (fluid_real_t) mod->amount * v1 * v2;
/* it indeed is as simple as that: */
final_value = (fluid_real_t) mod->amount * v1 * v2;

/* check for absolute value transform */
if(mod->trans == FLUID_MOD_TRANSFORM_ABS)
{
final_value = FLUID_FABS(final_value);
}
return final_value;
}

/**
Expand All @@ -489,7 +528,8 @@ new_fluid_mod(void)
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}

// for the sake of backward compatibility
mod->trans = FLUID_MOD_TRANSFORM_LINEAR;
return mod;
}

Expand Down
1 change: 1 addition & 0 deletions src/synth/fluid_mod.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct _fluid_mod_t
unsigned char flags1; /**< Source controller 1 flags */
unsigned char src2; /**< Source controller 2 */
unsigned char flags2; /**< Source controller 2 flags */
unsigned char trans; /**< Output transform flag */
double amount; /**< Multiplier amount */
/* The 'next' field allows to link modulators into a list. It is
* not used in fluid_voice.c, there each voice allocates memory for a
Expand Down

0 comments on commit 98b115f

Please sign in to comment.