mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-03-02 07:21:58 +00:00
Zone Validation Test (#826)
This is my implementation of a unit test to verify the preset and instrument zone validation behaviour.
This commit is contained in:
parent
1eda0ae863
commit
8a39c5aea4
5 changed files with 554 additions and 78 deletions
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
matrix:
|
||||
CC: [""]
|
||||
CXX: [""]
|
||||
CMAKE_FLAGS: ["-Denable-profiling=1","-Denable-floats=1 -Denable-profiling=1","-Denable-floats=1","-Denable-trap-on-fpe=1","-Denable-fpe-check=1","-Denable-ipv6=0","-Denable-network=0","-Denable-aufile=0","-DBUILD_SHARED_LIBS=0","-Denable-ubsan=1"]
|
||||
CMAKE_FLAGS: ["-Denable-profiling=1","-Denable-floats=1 -Denable-profiling=1","-Denable-floats=1","-Denable-trap-on-fpe=1","-Denable-fpe-check=1","-Denable-ipv6=0","-Denable-network=0","-Denable-aufile=0","-DBUILD_SHARED_LIBS=0","-Denable-ubsan=1 -Denable-debug=1"]
|
||||
include:
|
||||
- CC: "gcc-7"
|
||||
CXX: "g++-7"
|
||||
|
|
|
@ -112,71 +112,6 @@ static const uint32_t idlist[] =
|
|||
SM24_FCC
|
||||
};
|
||||
|
||||
/* generator types */
|
||||
typedef enum
|
||||
{
|
||||
Gen_StartAddrOfs,
|
||||
Gen_EndAddrOfs,
|
||||
Gen_StartLoopAddrOfs,
|
||||
Gen_EndLoopAddrOfs,
|
||||
Gen_StartAddrCoarseOfs,
|
||||
Gen_ModLFO2Pitch,
|
||||
Gen_VibLFO2Pitch,
|
||||
Gen_ModEnv2Pitch,
|
||||
Gen_FilterFc,
|
||||
Gen_FilterQ,
|
||||
Gen_ModLFO2FilterFc,
|
||||
Gen_ModEnv2FilterFc,
|
||||
Gen_EndAddrCoarseOfs,
|
||||
Gen_ModLFO2Vol,
|
||||
Gen_Unused1,
|
||||
Gen_ChorusSend,
|
||||
Gen_ReverbSend,
|
||||
Gen_Pan,
|
||||
Gen_Unused2,
|
||||
Gen_Unused3,
|
||||
Gen_Unused4,
|
||||
Gen_ModLFODelay,
|
||||
Gen_ModLFOFreq,
|
||||
Gen_VibLFODelay,
|
||||
Gen_VibLFOFreq,
|
||||
Gen_ModEnvDelay,
|
||||
Gen_ModEnvAttack,
|
||||
Gen_ModEnvHold,
|
||||
Gen_ModEnvDecay,
|
||||
Gen_ModEnvSustain,
|
||||
Gen_ModEnvRelease,
|
||||
Gen_Key2ModEnvHold,
|
||||
Gen_Key2ModEnvDecay,
|
||||
Gen_VolEnvDelay,
|
||||
Gen_VolEnvAttack,
|
||||
Gen_VolEnvHold,
|
||||
Gen_VolEnvDecay,
|
||||
Gen_VolEnvSustain,
|
||||
Gen_VolEnvRelease,
|
||||
Gen_Key2VolEnvHold,
|
||||
Gen_Key2VolEnvDecay,
|
||||
Gen_Instrument,
|
||||
Gen_Reserved1,
|
||||
Gen_KeyRange,
|
||||
Gen_VelRange,
|
||||
Gen_StartLoopAddrCoarseOfs,
|
||||
Gen_Keynum,
|
||||
Gen_Velocity,
|
||||
Gen_Attenuation,
|
||||
Gen_Reserved2,
|
||||
Gen_EndLoopAddrCoarseOfs,
|
||||
Gen_CoarseTune,
|
||||
Gen_FineTune,
|
||||
Gen_SampleId,
|
||||
Gen_SampleModes,
|
||||
Gen_Reserved3,
|
||||
Gen_ScaleTune,
|
||||
Gen_ExclusiveClass,
|
||||
Gen_OverrideRootKey,
|
||||
Gen_Dummy
|
||||
} Gen_Type;
|
||||
|
||||
#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
|
||||
#define Gen_Count Gen_Dummy /* count of generators */
|
||||
#define GenArrSize sizeof(SFGenAmount) * Gen_Count /* gen array size */
|
||||
|
@ -303,11 +238,11 @@ static int process_pdta(SFData *sf, int size);
|
|||
static int load_phdr(SFData *sf, unsigned int size);
|
||||
static int load_pbag(SFData *sf, int size);
|
||||
static int load_pmod(SFData *sf, int size);
|
||||
static int load_pgen(SFData *sf, int size);
|
||||
extern int load_pgen(SFData *sf, int size);
|
||||
static int load_ihdr(SFData *sf, unsigned int size);
|
||||
static int load_ibag(SFData *sf, int size);
|
||||
static int load_imod(SFData *sf, int size);
|
||||
static int load_igen(SFData *sf, int size);
|
||||
extern int load_igen(SFData *sf, int size);
|
||||
static int load_shdr(SFData *sf, unsigned int size);
|
||||
static int fixup_pgen(SFData *sf);
|
||||
static int fixup_igen(SFData *sf);
|
||||
|
@ -320,11 +255,6 @@ static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist);
|
|||
static int valid_inst_genid(unsigned short genid);
|
||||
static int valid_preset_genid(unsigned short genid);
|
||||
|
||||
|
||||
static void delete_preset(SFPreset *preset);
|
||||
static void delete_inst(SFInst *inst);
|
||||
static void delete_zone(SFZone *zone);
|
||||
|
||||
static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
|
||||
static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
|
||||
|
||||
|
@ -1366,7 +1296,7 @@ static int load_pmod(SFData *sf, int size)
|
|||
* if a generator follows an instrument discard it
|
||||
* if a duplicate generator exists replace previous one
|
||||
* ------------------------------------------------------------------- */
|
||||
static int load_pgen(SFData *sf, int size)
|
||||
int load_pgen(SFData *sf, int size)
|
||||
{
|
||||
fluid_list_t *dup, **hz = NULL;
|
||||
fluid_list_t *preset_list;
|
||||
|
@ -1885,7 +1815,7 @@ static int load_imod(SFData *sf, int size)
|
|||
}
|
||||
|
||||
/* load instrument generators (see load_pgen for loading rules) */
|
||||
static int load_igen(SFData *sf, int size)
|
||||
int load_igen(SFData *sf, int size)
|
||||
{
|
||||
fluid_list_t *dup, **hz = NULL;
|
||||
fluid_list_t *inst_list;
|
||||
|
@ -2249,7 +2179,7 @@ static int fixup_igen(SFData *sf)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void delete_preset(SFPreset *preset)
|
||||
void delete_preset(SFPreset *preset)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
SFZone *zone;
|
||||
|
@ -2273,7 +2203,7 @@ static void delete_preset(SFPreset *preset)
|
|||
FLUID_FREE(preset);
|
||||
}
|
||||
|
||||
static void delete_inst(SFInst *inst)
|
||||
void delete_inst(SFInst *inst)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
SFZone *zone;
|
||||
|
@ -2299,7 +2229,7 @@ static void delete_inst(SFInst *inst)
|
|||
|
||||
|
||||
/* Free all elements of a zone (Preset or Instrument) */
|
||||
static void delete_zone(SFZone *zone)
|
||||
void delete_zone(SFZone *zone)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
|
||||
|
|
|
@ -228,4 +228,77 @@ int fluid_sffile_parse_presets(SFData *sf);
|
|||
int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
|
||||
int sample_type, short **data, char **data24);
|
||||
|
||||
|
||||
/* extern only for unit test purposes */
|
||||
int load_igen(SFData *sf, int size);
|
||||
int load_pgen(SFData *sf, int size);
|
||||
void delete_preset(SFPreset *preset);
|
||||
void delete_inst(SFInst *inst);
|
||||
void delete_zone(SFZone *zone);
|
||||
|
||||
/* generator types */
|
||||
typedef enum
|
||||
{
|
||||
Gen_StartAddrOfs,
|
||||
Gen_EndAddrOfs,
|
||||
Gen_StartLoopAddrOfs,
|
||||
Gen_EndLoopAddrOfs,
|
||||
Gen_StartAddrCoarseOfs,
|
||||
Gen_ModLFO2Pitch,
|
||||
Gen_VibLFO2Pitch,
|
||||
Gen_ModEnv2Pitch,
|
||||
Gen_FilterFc,
|
||||
Gen_FilterQ,
|
||||
Gen_ModLFO2FilterFc,
|
||||
Gen_ModEnv2FilterFc,
|
||||
Gen_EndAddrCoarseOfs,
|
||||
Gen_ModLFO2Vol,
|
||||
Gen_Unused1,
|
||||
Gen_ChorusSend,
|
||||
Gen_ReverbSend,
|
||||
Gen_Pan,
|
||||
Gen_Unused2,
|
||||
Gen_Unused3,
|
||||
Gen_Unused4,
|
||||
Gen_ModLFODelay,
|
||||
Gen_ModLFOFreq,
|
||||
Gen_VibLFODelay,
|
||||
Gen_VibLFOFreq,
|
||||
Gen_ModEnvDelay,
|
||||
Gen_ModEnvAttack,
|
||||
Gen_ModEnvHold,
|
||||
Gen_ModEnvDecay,
|
||||
Gen_ModEnvSustain,
|
||||
Gen_ModEnvRelease,
|
||||
Gen_Key2ModEnvHold,
|
||||
Gen_Key2ModEnvDecay,
|
||||
Gen_VolEnvDelay,
|
||||
Gen_VolEnvAttack,
|
||||
Gen_VolEnvHold,
|
||||
Gen_VolEnvDecay,
|
||||
Gen_VolEnvSustain,
|
||||
Gen_VolEnvRelease,
|
||||
Gen_Key2VolEnvHold,
|
||||
Gen_Key2VolEnvDecay,
|
||||
Gen_Instrument,
|
||||
Gen_Reserved1,
|
||||
Gen_KeyRange,
|
||||
Gen_VelRange,
|
||||
Gen_StartLoopAddrCoarseOfs,
|
||||
Gen_Keynum,
|
||||
Gen_Velocity,
|
||||
Gen_Attenuation,
|
||||
Gen_Reserved2,
|
||||
Gen_EndLoopAddrCoarseOfs,
|
||||
Gen_CoarseTune,
|
||||
Gen_FineTune,
|
||||
Gen_SampleId,
|
||||
Gen_SampleModes,
|
||||
Gen_Reserved3,
|
||||
Gen_ScaleTune,
|
||||
Gen_ExclusiveClass,
|
||||
Gen_OverrideRootKey,
|
||||
Gen_Dummy
|
||||
} Gen_Type;
|
||||
|
||||
#endif /* _FLUID_SFFILE_H */
|
||||
|
|
|
@ -22,6 +22,7 @@ ADD_FLUID_TEST(test_synth_process)
|
|||
ADD_FLUID_TEST(test_ct2hz)
|
||||
ADD_FLUID_TEST(test_sample_validate)
|
||||
ADD_FLUID_TEST(test_sfont_unloading)
|
||||
ADD_FLUID_TEST(test_sfont_zone)
|
||||
ADD_FLUID_TEST(test_seq_event_queue_sort)
|
||||
ADD_FLUID_TEST(test_seq_scale)
|
||||
ADD_FLUID_TEST(test_seq_evt_order)
|
||||
|
|
472
test/test_sfont_zone.c
Normal file
472
test/test_sfont_zone.c
Normal file
|
@ -0,0 +1,472 @@
|
|||
|
||||
#include "test.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "sfloader/fluid_sfont.h"
|
||||
#include "sfloader/fluid_defsfont.h"
|
||||
#include "sfloader/fluid_sffile.h"
|
||||
#include "utils/fluid_sys.h"
|
||||
|
||||
|
||||
#define SET_BUF2(START, SIZE) \
|
||||
do \
|
||||
{ \
|
||||
file_buf = START; \
|
||||
file_end = (START) + (SIZE); \
|
||||
} while (0)
|
||||
#define SET_BUF(BUF) SET_BUF2(BUF, FLUID_N_ELEMENTS(BUF))
|
||||
#define UNSET_BUF \
|
||||
do \
|
||||
{ \
|
||||
file_buf = NULL; \
|
||||
file_end = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// pointer to the start of the file_buf
|
||||
const unsigned char *start;
|
||||
// actual size of the buffer
|
||||
unsigned int size;
|
||||
// expected end address of the buffer
|
||||
const unsigned char *end;
|
||||
} buf_t;
|
||||
|
||||
static const unsigned char *file_buf = NULL;
|
||||
static const unsigned char *file_end = NULL;
|
||||
static int test_reader(void *buf, fluid_long_long_t count, void *h)
|
||||
{
|
||||
if (file_buf + count > file_end)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
FLUID_MEMCPY(buf, file_buf, count);
|
||||
file_buf += count;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
static int test_seek(void *handle, fluid_long_long_t offset, int origin)
|
||||
{
|
||||
if (origin == SEEK_CUR)
|
||||
{
|
||||
file_buf += offset;
|
||||
if (file_buf > file_end)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
// shouldn't happen?
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
|
||||
static const fluid_file_callbacks_t fcb =
|
||||
{
|
||||
NULL, &test_reader, &test_seek, NULL, NULL
|
||||
};
|
||||
|
||||
static SFZone* new_test_zone(fluid_list_t** parent_list, int gen_count)
|
||||
{
|
||||
int i;
|
||||
SFZone *zone = FLUID_NEW(SFZone);
|
||||
TEST_ASSERT(zone != NULL);
|
||||
FLUID_MEMSET(zone, 0, sizeof(*zone));
|
||||
|
||||
for (i = 0; i < gen_count; i++)
|
||||
{
|
||||
zone->gen = fluid_list_prepend(zone->gen, NULL);
|
||||
}
|
||||
|
||||
if(parent_list != NULL)
|
||||
{
|
||||
*parent_list = fluid_list_append(*parent_list, zone);
|
||||
}
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
// test the good case first: one zone, with two generators and one terminal generator
|
||||
static void good_test_1zone_2gen_1termgen(int (*load_func)(SFData *sf, int size), SFData* sf, SFZone *zone)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] =
|
||||
{
|
||||
Gen_KeyRange, 0, 60, 127, Gen_VelRange, 0, 60, 127, 0, 0, 0, 0
|
||||
};
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_KeyRange);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_VelRange);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// bad case: too few generators in buffer, triggering a chunk size mismatch
|
||||
static void bad_test_too_short_gen_buffer(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone)
|
||||
{
|
||||
const Gen_Type final_gen = (load_func == &load_pgen) ? Gen_Instrument : Gen_SampleId;
|
||||
SFGen *gen;
|
||||
unsigned int i;
|
||||
static const unsigned char buf1[] = { Gen_KeyRange, 0, 0 };
|
||||
static const unsigned char buf2[] = { Gen_KeyRange, 0 };
|
||||
static const unsigned char buf3[] = { Gen_KeyRange };
|
||||
static const unsigned char buf8[] = { Gen_VelRange, 0, 0 };
|
||||
static const unsigned char buf9[] = { Gen_VelRange, 0 };
|
||||
static const unsigned char buf10[] = { Gen_VelRange };
|
||||
static const unsigned char buf4[] = { Gen_VelRange, 0, 0, 127, Gen_CoarseTune, 0, 4 };
|
||||
static const unsigned char buf5[] = { Gen_VelRange, 0, 0, 127, Gen_CoarseTune, 0 };
|
||||
static const unsigned char buf6[] = { Gen_VelRange, 0, 0, 127, Gen_CoarseTune };
|
||||
const unsigned char buf11[] = { Gen_VelRange, 0, 0, 127, final_gen, 0, 4 };
|
||||
const unsigned char buf12[] = { Gen_VelRange, 0, 0, 127, final_gen, 0 };
|
||||
const unsigned char buf13[] = { Gen_VelRange, 0, 0, 127, final_gen };
|
||||
static const unsigned char buf7[] = { Gen_KeyRange, 0, 60, 127, Gen_OverrideRootKey };
|
||||
|
||||
static const buf_t buf_with_one_gen[] =
|
||||
{
|
||||
{ buf1, sizeof(buf1), buf1 + sizeof(buf1) },
|
||||
{ buf2, sizeof(buf2),buf2 + sizeof(buf2) },
|
||||
{ buf3, sizeof(buf3), buf3 },
|
||||
{ buf8, sizeof(buf8), buf8 + sizeof(buf8) },
|
||||
{ buf9, sizeof(buf9), buf9 + sizeof(buf9) },
|
||||
{ buf10, sizeof(buf10), buf10 }
|
||||
};
|
||||
|
||||
const buf_t buf_with_two_gen[] =
|
||||
{
|
||||
{ buf4, sizeof(buf4), buf4 + sizeof(buf4) -1 },
|
||||
{ buf5, sizeof(buf5), buf5 + sizeof(buf5) },
|
||||
{ buf6, sizeof(buf6), buf6 + sizeof(buf6) - 1 },
|
||||
{ buf11, sizeof(buf11), buf11 + sizeof(buf11) - 1 },
|
||||
{ buf12, sizeof(buf12), buf12 + sizeof(buf12) },
|
||||
{ buf13, sizeof(buf13), buf13 + sizeof(buf13) -1}
|
||||
};
|
||||
|
||||
for (i = 0; i < FLUID_N_ELEMENTS(buf_with_one_gen); i++)
|
||||
{
|
||||
SET_BUF2(buf_with_one_gen[i].start, buf_with_one_gen[i].size);
|
||||
TEST_ASSERT(load_func(sf, 8 /* pretend that our input buffer is big enough, to make it fail in the fcbs later */) == FALSE);
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
TEST_ASSERT(file_buf == buf_with_one_gen[i].end);
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
for (i = 0; i < FLUID_N_ELEMENTS(buf_with_two_gen); i++)
|
||||
{
|
||||
SET_BUF2(buf_with_two_gen[i].start, buf_with_two_gen[i].size);
|
||||
TEST_ASSERT(load_func(sf, 8) == FALSE);
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
FLUID_FREE(gen);
|
||||
zone->gen->data = NULL;
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
TEST_ASSERT(file_buf == buf_with_two_gen[i].end);
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
SET_BUF(buf7);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf7)) == FALSE);
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_KeyRange);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
TEST_ASSERT(file_buf == buf7 + sizeof(buf7) - 1);
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// bad case: one zone, with two similar generators
|
||||
static void bad_test_duplicate_gen(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] = { Gen_CoarseTune, 0, 5, 0, Gen_CoarseTune, 0, 10, 0 };
|
||||
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_CoarseTune);
|
||||
TEST_ASSERT(gen->amount.range.lo == 10);
|
||||
TEST_ASSERT(gen->amount.range.hi == 0);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// bad case: with one zone, generators in wrong order
|
||||
static void bad_test_gen_wrong_order(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] =
|
||||
{
|
||||
Gen_VelRange, 0, 60, 127,
|
||||
Gen_KeyRange, 0, 60, 127,
|
||||
Gen_Instrument, 0, 0xDD, 0xDD
|
||||
};
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_VelRange);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
// The INSTRUMENT generator is mistakenly accepted by load_igen. This will be fixed by Marcus' PR.
|
||||
// Once merge, this if clause should be removed.
|
||||
if (load_func != &load_igen)
|
||||
{
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
}
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 2));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
if (load_func == &load_pgen)
|
||||
{
|
||||
TEST_ASSERT(FLUID_POINTER_TO_UINT(zone->instsamp) == 0xDDDD + 1);
|
||||
zone->instsamp = NULL;
|
||||
}
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// This test-case is derived from the invalid SoundFont provided in #808
|
||||
static void bad_test_issue_808(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone1)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] =
|
||||
{
|
||||
// zone 1
|
||||
Gen_ReverbSend, 0, 50, 0,
|
||||
Gen_VolEnvRelease, 0, 206, 249,
|
||||
// zone 2
|
||||
Gen_KeyRange, 0, 0, 35,
|
||||
Gen_OverrideRootKey, 0, 43, 0,
|
||||
Gen_StartAddrCoarseOfs, 0, 0, 0,
|
||||
Gen_SampleModes, 0, 1, 0,
|
||||
Gen_StartAddrOfs, 0, 0, 0
|
||||
};
|
||||
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_ReverbSend);
|
||||
TEST_ASSERT(gen->amount.range.lo == 50);
|
||||
TEST_ASSERT(gen->amount.range.hi == 0);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 1));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_VolEnvRelease);
|
||||
TEST_ASSERT(gen->amount.range.lo == 206);
|
||||
TEST_ASSERT(gen->amount.range.hi == 249);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 2));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// This test-case has a single zone which has additional generators after the final generator, while some of them are incomplete and others still have an extra (maybe incomplete) terminal gen.
|
||||
static void bad_test_additional_gens_after_final_gen(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone1)
|
||||
{
|
||||
unsigned int i;
|
||||
SFGen *gen;
|
||||
const Gen_Type final_gen = (load_func == &load_pgen) ? Gen_Instrument : Gen_SampleId;
|
||||
|
||||
const unsigned char buf1[] =
|
||||
{
|
||||
// zone 1
|
||||
Gen_KeyRange, 0, 60, 127,
|
||||
Gen_Unused1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
Gen_KeyRange, 0, 0, 35,
|
||||
Gen_OverrideRootKey, 0, 43, 0,
|
||||
0, 0, 0, 0 // terminal generator
|
||||
};
|
||||
|
||||
const unsigned char buf2[] =
|
||||
{
|
||||
// zone 1
|
||||
Gen_KeyRange, 0, 60, 127,
|
||||
Gen_Unused1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
Gen_KeyRange, 0, 0, 35,
|
||||
Gen_OverrideRootKey, 0, 43, 0,
|
||||
0, 0, 0 // incomplete terminal generator
|
||||
};
|
||||
|
||||
const unsigned char buf3[] =
|
||||
{
|
||||
// zone 1
|
||||
Gen_KeyRange, 0, 60, 127,
|
||||
Gen_Unused1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
Gen_KeyRange, 0, 0, 35,
|
||||
Gen_OverrideRootKey, 0, 43
|
||||
};
|
||||
|
||||
const unsigned char buf4[] =
|
||||
{
|
||||
// zone 1
|
||||
Gen_KeyRange, 0, 60, 127,
|
||||
Gen_Unused1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
Gen_KeyRange, 0, 0, 35,
|
||||
Gen_OverrideRootKey, 0
|
||||
};
|
||||
|
||||
const buf_t buf[] =
|
||||
{
|
||||
{ buf1, sizeof(buf1), buf1 + sizeof(buf1) },
|
||||
{ buf2, sizeof(buf2), buf2 + sizeof(buf2) - 3 },
|
||||
{ buf3, sizeof(buf3), buf3 + sizeof(buf3) - 3 },
|
||||
{ buf4, sizeof(buf4), buf4 + sizeof(buf4) - 2 },
|
||||
};
|
||||
|
||||
// the first test case should return true, all others false
|
||||
int expected_ret_val = TRUE;
|
||||
for (i = 0; i < FLUID_N_ELEMENTS(buf); i++)
|
||||
{
|
||||
SET_BUF2(buf[i].start, buf[i].size);
|
||||
TEST_ASSERT(load_func(sf, buf[i].size) == expected_ret_val);
|
||||
expected_ret_val = FALSE;
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == Gen_KeyRange);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
// delete this generator
|
||||
FLUID_FREE(gen);
|
||||
zone1->gen->data = NULL;
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 1));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 2));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 3));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 4));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(FLUID_POINTER_TO_UINT(zone1->instsamp) == 0xDDDD + 1);
|
||||
zone1->instsamp = NULL;
|
||||
|
||||
TEST_ASSERT(file_buf == buf[i].end);
|
||||
UNSET_BUF;
|
||||
|
||||
// The test cases above expect zone1 to be pre-populated with 5 generators
|
||||
delete_fluid_list(zone1->gen);
|
||||
zone1->gen = NULL;
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// prepare a soundfont that has one preset and one instrument, with up to 2 zones
|
||||
|
||||
SFZone *zone1;
|
||||
SFData *sf = FLUID_NEW(SFData);
|
||||
SFPreset *preset = FLUID_NEW(SFPreset);
|
||||
SFInst *inst = FLUID_NEW(SFInst);
|
||||
|
||||
TEST_ASSERT(sf != NULL);
|
||||
FLUID_MEMSET(sf, 0, sizeof(*sf));
|
||||
TEST_ASSERT(preset != NULL);
|
||||
FLUID_MEMSET(preset, 0, sizeof(*preset));
|
||||
TEST_ASSERT(inst != NULL);
|
||||
FLUID_MEMSET(inst, 0, sizeof(*inst));
|
||||
|
||||
sf->fcbs = &fcb;
|
||||
sf->preset = fluid_list_append(sf->preset, preset);
|
||||
sf->inst = fluid_list_append(sf->inst, inst);
|
||||
|
||||
// Calls the given test function for 1 zone once for preset and once for inst case.
|
||||
#define TEST_CASE_1(TEST_FUNC, GEN_COUNT) \
|
||||
do \
|
||||
{ \
|
||||
zone1 = new_test_zone(&preset->zone, GEN_COUNT); \
|
||||
TEST_FUNC(&load_pgen, sf, zone1); \
|
||||
delete_zone(zone1); \
|
||||
delete_fluid_list(preset->zone); \
|
||||
preset->zone = NULL; \
|
||||
\
|
||||
zone1 = new_test_zone(&inst->zone, GEN_COUNT); \
|
||||
TEST_FUNC(&load_igen, sf, zone1); \
|
||||
delete_zone(zone1); \
|
||||
delete_fluid_list(inst->zone); \
|
||||
inst->zone = NULL; \
|
||||
} while (0)
|
||||
|
||||
TEST_CASE_1(good_test_1zone_2gen_1termgen, 2);
|
||||
TEST_CASE_1(good_test_1zone_2gen_1termgen, 3);
|
||||
|
||||
TEST_CASE_1(bad_test_too_short_gen_buffer, 2);
|
||||
|
||||
TEST_CASE_1(bad_test_duplicate_gen, 2);
|
||||
|
||||
TEST_CASE_1(bad_test_gen_wrong_order, 3);
|
||||
|
||||
TEST_CASE_1(bad_test_additional_gens_after_final_gen, 5);
|
||||
|
||||
zone1 = new_test_zone(&preset->zone, 2);
|
||||
(void)new_test_zone(&preset->zone, 5);
|
||||
bad_test_issue_808(&load_pgen, sf, zone1);
|
||||
// zone 2 was dropped
|
||||
TEST_ASSERT(preset->zone->next == NULL);
|
||||
delete_zone(zone1);
|
||||
// zone2 already deleted
|
||||
delete_fluid_list(preset->zone);
|
||||
preset->zone = NULL;
|
||||
|
||||
zone1 = new_test_zone(&inst->zone, 2);
|
||||
(void)new_test_zone(&inst->zone, 5);
|
||||
bad_test_issue_808(&load_igen, sf, zone1);
|
||||
// zone 2 was dropped
|
||||
TEST_ASSERT(inst->zone->next == NULL);
|
||||
delete_zone(zone1);
|
||||
// zone2 already deleted
|
||||
delete_fluid_list(inst->zone);
|
||||
inst->zone = NULL;
|
||||
|
||||
delete_inst(inst);
|
||||
delete_preset(preset);
|
||||
delete_fluid_list(sf->inst);
|
||||
delete_fluid_list(sf->preset);
|
||||
// we cannot call fluid_sffile_close here, because it would destroy the mutex which is not initialized
|
||||
FLUID_FREE(sf);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in a new issue