Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for absolute transform #1409

Merged
merged 5 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 */
derselbst marked this conversation as resolved.
Show resolved Hide resolved
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
Loading