mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 15:01:40 +00:00
333 lines
15 KiB
C
333 lines
15 KiB
C
/*----------------------------------------------------------------------------
|
|
Test of modulation contribution produced by fluid_voice_modulate().
|
|
|
|
These tests use the modulation value (mod_modulation) produced by
|
|
fluid_voice_modulate() with one modulator (simple or complex) at a time in the
|
|
voice.
|
|
Then mod_modulation is compared to the expected modulation value
|
|
(mod_modulation_expected).
|
|
|
|
Tests must be done for each type of modulator (simple or complex).
|
|
|
|
The comparison is done 2 times:
|
|
1) mod_modulation is compared to theorical expected modulation value.
|
|
2) mod_modulation is compared to the modulation computed by running
|
|
fluid_voice_calculate_modulator_contributions() (see note).
|
|
|
|
Note about test dependency and precedence:
|
|
This step is dependent of fluid_voice_calculate_modulator_contributions()
|
|
function. That means that any change in this function must be checked by
|
|
running test_modulator_amount before running test_fluid_voice_modulate.
|
|
----------------------------------------------------------------------------*/
|
|
#include "test.h"
|
|
#include "fluidsynth.h"
|
|
#include "utils/fluid_sys.h"
|
|
#include "synth/fluid_voice.h"
|
|
#include "synth/fluid_chan.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/**
|
|
* Compute expected modulation a modulator will supply by
|
|
* calling fluid_voice_calculate_modulator_contributions().
|
|
*
|
|
* @param voice, the voice that must contains only one modulator
|
|
* (simple or complex).
|
|
* @return the expected modulation this modulator will supply.
|
|
*/
|
|
static fluid_real_t get_expected_mod_modulation(fluid_voice_t *voice)
|
|
{
|
|
int i;
|
|
// Check that the voice contains one modulator
|
|
TEST_ASSERT(fluid_voice_get_count_modulators(voice) == 1);
|
|
|
|
// calculate generator mod value
|
|
for(i = 0; i < voice->mod_count; i++)
|
|
{
|
|
voice->mod[i].link = 0.0; // reset link input
|
|
}
|
|
voice->gen[GEN_FILTERFC].mod = 0; // reset mod input
|
|
fluid_voice_calculate_modulator_contributions(voice);
|
|
|
|
return voice->gen[GEN_FILTERFC].mod; // return mod input}
|
|
}
|
|
|
|
/*-- functions for simple modulator -----------------------------------------*/
|
|
|
|
/**
|
|
* - Initialize a simple modulator (mod = bipo(cc20) * amount) and put it in voice.
|
|
* - Compute modulation given by this simple modulator by calling fluid_voice_modulate()
|
|
* and return this value.
|
|
*
|
|
* @param voice, the voice to initialize.
|
|
* @param mod, the simple modulator to initialize.
|
|
* @param src1_cc_value, src1_cc value.
|
|
* @param amount, amount value.
|
|
*/
|
|
static fluid_real_t get_simple_mod_modulation(fluid_voice_t *voice, fluid_mod_t *mod,
|
|
int src1_cc_value,
|
|
double amount)
|
|
{
|
|
static const int src1_cc = 20;
|
|
|
|
// Initialize CC values in channel
|
|
fluid_channel_set_cc(voice->channel, src1_cc, src1_cc_value);
|
|
|
|
//initialize modulators sources and amount values.
|
|
fluid_mod_set_source1(mod, src1_cc, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE);
|
|
fluid_mod_set_source2(mod, FLUID_MOD_NONE, FLUID_MOD_GC);
|
|
fluid_mod_set_amount (mod, amount);
|
|
fluid_mod_set_dest(mod, GEN_FILTERFC);
|
|
|
|
// Add one simple modulator using fluid_voice_add_mod().
|
|
voice->mod_count = 0; // clear voice modulator table.
|
|
fluid_voice_add_mod(voice, mod, FLUID_VOICE_DEFAULT);
|
|
|
|
/* Compute modulation by calling fluid_voice_modulate() */
|
|
TEST_ASSERT(fluid_voice_modulate(voice, 1, src1_cc) == FLUID_OK);
|
|
|
|
return voice->gen[GEN_FILTERFC].mod; // return mod input
|
|
}
|
|
|
|
//-- functions for complex modulator ------------------------------------------
|
|
/**
|
|
* - Initialize a complex modulator: (m2 + m1)-->m0-->GEN_ATTENUATION with
|
|
* m0: source1 linked, source2 unip, CC20, destination GEN_FILTERFC
|
|
* m1: source1 bip, CC21, source2 none, destination m0
|
|
* m2: source1 bip, CC22, source2 none, destination m0
|
|
* - Put this modulator in voice.
|
|
* - Compute modulation given by this complex modulator by calling
|
|
* fluid_voice_modulate() and return this value.
|
|
*
|
|
* @param voice, the voice to initialize.
|
|
* @param m0, ending modulator member.
|
|
* @param m1, member modulator linked to m0.
|
|
* @param m2, member modulator linked to m0.
|
|
*
|
|
* @param m0_src2_cc_value, cc value on source2 of m0 (0..127).
|
|
* @param m1_src1_cc_value, cc value on source1 of m1 (0..127).
|
|
* @param m2_src1_cc_value, cc value on source1 of m2 (0..127).
|
|
*
|
|
* @param m0_amount, amount value of m0.
|
|
* @param m1_amount, amount value of m1.
|
|
* @param m2_amount, amount value of m2.
|
|
*/
|
|
static fluid_real_t get_complex_mod_modulation(fluid_voice_t *voice,
|
|
// modulators: m0, m1, m2
|
|
fluid_mod_t *m0, fluid_mod_t *m1, fluid_mod_t *m2,
|
|
|
|
// m0: cc value, m1 cc value, m2 cc value
|
|
int m0_src2_cc_value, int m1_src1_cc_value, int m2_src1_cc_value,
|
|
|
|
// m0 amount, m1 amount, m2 amout
|
|
double m0_amount, double m1_amount, double m2_amount)
|
|
{
|
|
static const int m0_src2_cc = 20;
|
|
static const int m1_src1_cc = 21;
|
|
static const int m2_src1_cc = 22;
|
|
|
|
// Initialize CC values in channel
|
|
fluid_channel_set_cc(voice->channel, m0_src2_cc, m0_src2_cc_value);
|
|
fluid_channel_set_cc(voice->channel, m1_src1_cc, m1_src1_cc_value);
|
|
fluid_channel_set_cc(voice->channel, m2_src1_cc, m2_src1_cc_value);
|
|
|
|
//initialize modulator m0: sources , amount , destination values.
|
|
fluid_mod_set_source1(m0, FLUID_MOD_LINK_SRC, FLUID_MOD_GC);
|
|
fluid_mod_set_source2(m0, m0_src2_cc, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE);
|
|
fluid_mod_set_amount (m0, m0_amount);
|
|
fluid_mod_set_dest(m0, GEN_FILTERFC);
|
|
|
|
//initialize modulator m1: sources , amount , destination values.
|
|
fluid_mod_set_source1(m1, m1_src1_cc, FLUID_MOD_CC | FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE);
|
|
fluid_mod_set_source2(m1, FLUID_MOD_NONE, FLUID_MOD_GC);
|
|
fluid_mod_set_amount (m1, m1_amount);
|
|
fluid_mod_set_dest (m1, FLUID_MOD_LINK_DEST | 0);
|
|
|
|
//initialize modulator m2: sources , amount , destination values.
|
|
fluid_mod_set_source1(m2, m2_src1_cc, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE);
|
|
fluid_mod_set_source2(m2, FLUID_MOD_NONE, FLUID_MOD_GC);
|
|
fluid_mod_set_amount (m2, m2_amount);
|
|
fluid_mod_set_dest (m2, FLUID_MOD_LINK_DEST | 0);
|
|
|
|
/* valid internal list of linked modulators members for a complex modulator (mod0,mod1,mod2).
|
|
Modulator member ordering is expected to be equivalent to the one produced by
|
|
fluid_mod_copy_linked_mod()
|
|
*/
|
|
m0->next = m1;
|
|
m1->next = m2;
|
|
|
|
voice->mod_count = 0; // clear voice modulator table.
|
|
fluid_voice_add_mod_local(voice, m0, FLUID_VOICE_DEFAULT, FLUID_NUM_MOD);
|
|
|
|
/* Compute modulation by calling fluid_voice_modulate() */
|
|
TEST_ASSERT(fluid_voice_modulate(voice, 1, m1_src1_cc) == FLUID_OK);
|
|
|
|
return voice->gen[GEN_FILTERFC].mod; // return mod input
|
|
}
|
|
|
|
/* Main tests --------------------------------------------------------------*/
|
|
int main(void)
|
|
{
|
|
fluid_real_t mod_modulation;
|
|
fluid_real_t mod_modulation_expected;
|
|
|
|
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_sample_t *s = new_fluid_sample();
|
|
|
|
// for modulation we need a voice belonging to the synthesizer
|
|
fluid_voice_t *v = fluid_synth_alloc_voice(synth, s, 0, 0, 0);
|
|
|
|
fluid_mod_t *mod0 = new_fluid_mod();
|
|
fluid_mod_t *mod1 = new_fluid_mod();
|
|
fluid_mod_t *mod2 = new_fluid_mod();
|
|
|
|
TEST_ASSERT(v != NULL);
|
|
|
|
fluid_gen_init(&v->gen[0], NULL);
|
|
v->channel = ch;
|
|
v->mod_count = 0;
|
|
|
|
// Tests using one simple modulator:
|
|
// bip(CC20)-->mod0-->GEN_FILTERFC
|
|
printf("Tests using one simple modulator:\n");
|
|
{
|
|
//---------------------------------------------------------------------
|
|
// Test 0 -- mod_modulation = b(cc20) * a0
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_simple_mod_modulation(v, mod0, 0, 100.0);
|
|
mod_modulation_expected = -100.0; // expected theoritical modulation
|
|
printf(" Test 0.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 0.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
//---------------------------------------------------------------------
|
|
// Test 1 -- mod_modulation = b(cc20) * a0
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_simple_mod_modulation(v, mod0, 127, 100.0);
|
|
mod_modulation_expected = 100.0; // expected theoritical modulation
|
|
printf(" Test 1.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 1.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
}
|
|
|
|
// Tests using one complex modulator
|
|
// uni(CC20)--------->mod0
|
|
// bip(CC21)-->mod1-->mod0-->GEN_FILTERFC
|
|
// bip(CC21)-->mod2-->mod0
|
|
printf("Tests using one complex modulator:\n");
|
|
{
|
|
//---------------------------------------------------------------------
|
|
// Test 0 mod_modulation = u(cc20) * a0 * ((b(cc21) * a1) + (b(cc22) * a2))
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_complex_mod_modulation(v, mod0, mod1, mod2,
|
|
// cc20, cc21, cc22, a0, a1, a2
|
|
0, 0, 0, 10.0, 20.0, 30.0);
|
|
// expected theoritical minimun value: 0 because cc20 value is 0
|
|
mod_modulation_expected = 0.0;
|
|
printf(" Test 0.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 0.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
//---------------------------------------------------------------------
|
|
// Test 1 mod_modulation = u(cc20) * a0 * ((b(cc21) * a1) + (b(cc22) * a2))
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_complex_mod_modulation(v, mod0, mod1, mod2,
|
|
// cc20, cc21, cc22, a0, a1, a2
|
|
127, 0, 0, 10.0, 20.0, 30.0);
|
|
// expected theoritical minimun value: -500 because cc20 value is 127
|
|
mod_modulation_expected = -500;
|
|
printf(" Test 1.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 1.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
//---------------------------------------------------------------------
|
|
// Test 2 mod_modulation = u(cc20) * a0 * ((b(cc21) * a1) + (b(cc22) * a2))
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_complex_mod_modulation(v, mod0, mod1, mod2,
|
|
// cc20, cc21, cc22, a0, a1, a2
|
|
127, 127, 0, 10.0, 20.0, 30.0);
|
|
// expected theoritical minimun value: -100
|
|
mod_modulation_expected = -100;
|
|
printf(" Test 2.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 2.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
//---------------------------------------------------------------------
|
|
// Test 3 mod_modulation = u(cc20) * a0 * ((b(cc21) * a1) + (b(cc22) * a2))
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_complex_mod_modulation(v, mod0, mod1, mod2,
|
|
// cc20, cc21, cc22, a0, a1, a2
|
|
127, 0, 127, 10.0, 20.0, 30.0);
|
|
// expected theoritical minimun value: -100
|
|
mod_modulation_expected = 100;
|
|
printf(" Test 3.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 3.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
//---------------------------------------------------------------------
|
|
// Test 4 mod_modulation = u(cc20) * a0 * ((b(cc21) * a1) + (b(cc22) * a2))
|
|
// get modulation value by calling fluid_voice_modulate()
|
|
mod_modulation = get_complex_mod_modulation(v, mod0, mod1, mod2,
|
|
// cc20, cc21, cc22, a0, a1, a2
|
|
127, 127, 127, 10.0, 20.0, 30.0);
|
|
// expected theoritical minimun value: -100
|
|
mod_modulation_expected = 500;
|
|
printf(" Test 4.0: mod_modulation:%f, mod_modulation theoritical:%f\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
|
|
// get expected modulation value obtained by running the modulator in the voice
|
|
mod_modulation_expected = get_expected_mod_modulation(v);
|
|
printf(" Test 4.1: mod_modulation:%f, mod_modulation_expected:%f\n\n",
|
|
mod_modulation, mod_modulation_expected);
|
|
TEST_ASSERT(mod_modulation == mod_modulation_expected);
|
|
}
|
|
|
|
delete_fluid_mod(mod0);
|
|
delete_fluid_mod(mod1);
|
|
delete_fluid_mod(mod2);
|
|
|
|
delete_fluid_sample(s);
|
|
delete_fluid_channel(ch);
|
|
delete_fluid_synth(synth);
|
|
delete_fluid_settings(set);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|