add a unit test for complex modulator amounts

This commit is contained in:
derselbst 2019-07-10 13:50:28 +02:00
parent 392ae1518c
commit 3d33a0b7f6
3 changed files with 109 additions and 23 deletions

View file

@ -506,6 +506,35 @@ fluid_voice_calculate_gen_pitch(fluid_voice_t *voice)
voice->gen[GEN_PITCH].val = fluid_voice_calculate_pitch(voice, fluid_voice_get_actual_key(voice));
}
/* outsourced function that calculates modulator contributions to make it unit testable */
void fluid_voice_calculate_modulator_contributions(fluid_voice_t *voice)
{
int i;
/* The voice contains unlinked modulators + possible complex linked modulators.
We scan modulators from the last member of possible complex linked
modulator to the first member (i.e the one connected to a generator).
*/
for (i = voice->mod_count - 1; i >= 0; i--)
{
fluid_mod_t* mod = &voice->mod[i];
fluid_real_t modval = fluid_mod_get_value(mod, voice);
int dest_index = mod->dest;
if(dest_index & FLUID_MOD_LINK_DEST)
{
/* destination is a modulator */
voice->mod[dest_index & ~FLUID_MOD_LINK_DEST].link += modval;
}
else
{
/* destination is a generator */
fluid_gen_t* dest_gen = &voice->gen[dest_index];
dest_gen->mod += modval;
}
/* fluid_dump_modulator(mod); */
}
}
/*
* fluid_voice_calculate_runtime_synthesis_parameters
*
@ -519,7 +548,6 @@ fluid_voice_calculate_gen_pitch(fluid_voice_t *voice)
static int
fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t *voice)
{
int i;
unsigned int n;
static int const list_of_generators_to_initialize[] =
@ -598,28 +626,7 @@ fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t *voice)
* fluid_gen_init().
*/
/* The voice contains unlinked modulators + possible complex linked modulators.
We scan modulators from the last member of possible complex linked
modulator to the first member (i.e the one connected to a generator).
*/
for (i = voice->mod_count - 1; i >= 0; i--)
{
fluid_mod_t* mod = &voice->mod[i];
fluid_real_t modval = fluid_mod_get_value(mod, voice);
int dest_index = mod->dest;
if(dest_index & FLUID_MOD_LINK_DEST)
{
/* destination is a modulator */
voice->mod[dest_index & ~FLUID_MOD_LINK_DEST].link += modval;
}
else
{
/* destination is a generator */
fluid_gen_t* dest_gen = &voice->gen[dest_index];
dest_gen->mod += modval;
}
/* fluid_dump_modulator(mod); */
}
fluid_voice_calculate_modulator_contributions(voice);
/* Now the generators are initialized, nominal and modulation value.
* The voice parameters (which depend on generators) are calculated

View file

@ -16,6 +16,7 @@ ADD_FLUID_TEST(test_seqbind_unregister)
ADD_FLUID_TEST(test_synth_chorus_reverb)
ADD_FLUID_TEST(test_snprintf)
ADD_FLUID_TEST(test_modulator_links)
ADD_FLUID_TEST(test_modulator_amount)
if ( LIBSNDFILE_HASVORBIS )
ADD_FLUID_TEST(test_sf3_sfont_loading)

View file

@ -0,0 +1,78 @@
#include "test.h"
#include "fluidsynth.h"
#include "utils/fluid_sys.h"
#include "synth/fluid_voice.h"
#include "synth/fluid_chan.h"
void fluid_voice_calculate_modulator_contributions(fluid_voice_t *voice);
// test modulators (amount, source, linked modulators...)
int main(void)
{
static const int CC = 20;
fluid_settings_t* set = new_fluid_settings();
fluid_synth_t* synth = new_fluid_synth(set);
fluid_channel_t *ch = new_fluid_channel(synth, 0);
fluid_voice_t *v = new_fluid_voice(NULL, 22050);
fluid_mod_t *mod0 = &v->mod[0];
fluid_mod_t *mod1 = &v->mod[1];
fluid_mod_t *mod2 = &v->mod[2];
fluid_mod_t *mod3 = &v->mod[3];
v->mod_count = 3;
fluid_channel_set_cc(ch, CC, 127);
v->channel = ch;
// set up a valid list of complex modulators
{
fluid_mod_set_source1(mod0, FLUID_MOD_LINK_SRC, FLUID_MOD_GC);
fluid_mod_set_source2(mod0, FLUID_MOD_NONE, FLUID_MOD_GC);
fluid_mod_set_amount (mod0, 100);
fluid_mod_set_dest (mod0, GEN_FILTERFC);
fluid_mod_set_source1(mod1, CC,
FLUID_MOD_CC | FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod1, FLUID_MOD_NONE, FLUID_MOD_GC);
fluid_mod_set_amount (mod1, 200);
fluid_mod_set_dest (mod1, FLUID_MOD_LINK_DEST | 0);
fluid_mod_set_source1(mod2, CC, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod2, FLUID_MOD_NONE, FLUID_MOD_GC);
fluid_mod_set_amount (mod2, 300);
fluid_mod_set_dest (mod2, FLUID_MOD_LINK_DEST | 0);
fluid_voice_calculate_modulator_contributions(v);
TEST_ASSERT(mod0->link == fluid_mod_get_amount(mod1) + fluid_mod_get_amount(mod2));
TEST_ASSERT(v->gen[GEN_FILTERFC].mod == mod0->link * fluid_mod_get_amount(mod0));
}
// same list, with additional mod3
{
v->mod_count++;
v->gen[GEN_FILTERFC].mod = mod0->link = 0;
fluid_mod_set_source1(mod1, FLUID_MOD_LINK_SRC, FLUID_MOD_GC);
fluid_mod_set_source1(mod3, CC, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod3, FLUID_MOD_NONE, FLUID_MOD_GC);
fluid_mod_set_amount (mod3, 50);
fluid_mod_set_dest (mod3, FLUID_MOD_LINK_DEST | 1); // link to mod1
fluid_voice_calculate_modulator_contributions(v);
TEST_ASSERT(mod1->link == 50);
TEST_ASSERT(mod0->link == fluid_mod_get_amount(mod2) + fluid_mod_get_amount(mod1) * mod1->link);
TEST_ASSERT(v->gen[GEN_FILTERFC].mod == mod0->link * fluid_mod_get_amount(mod0));
}
delete_fluid_voice(v);
delete_fluid_channel(ch);
delete_fluid_synth(synth);
delete_fluid_settings(set);
return EXIT_SUCCESS;
}