diff --git a/src/sfloader/fluid_sffile.c b/src/sfloader/fluid_sffile.c index 5f95571e..0e7ffe26 100644 --- a/src/sfloader/fluid_sffile.c +++ b/src/sfloader/fluid_sffile.c @@ -2634,6 +2634,11 @@ static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigne goto error_exit; } + if((sfinfo.format & SF_FORMAT_OGG) == 0) + { + FLUID_LOG(FLUID_WARN, "OGG sample is not OGG compressed, this is not officially supported"); + } + wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels); if(!wav_data) diff --git a/src/sfloader/fluid_sfont.c b/src/sfloader/fluid_sfont.c index fb0b75ac..140fc3c5 100644 --- a/src/sfloader/fluid_sfont.c +++ b/src/sfloader/fluid_sfont.c @@ -700,6 +700,9 @@ int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune) */ int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size) { +#define EXCLUSIVE_FLAGS (FLUID_SAMPLETYPE_MONO | FLUID_SAMPLETYPE_RIGHT | FLUID_SAMPLETYPE_LEFT) + static const unsigned int supported_flags = EXCLUSIVE_FLAGS | FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_OGG_VORBIS | FLUID_SAMPLETYPE_ROM; + /* ROM samples are unusable for us by definition */ if(sample->sampletype & FLUID_SAMPLETYPE_ROM) { @@ -707,6 +710,28 @@ int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size) return FLUID_FAILED; } + if(sample->sampletype & ~supported_flags) + { + FLUID_LOG(FLUID_WARN, "Sample '%s' has unknown flags, possibly using an unsupported compression; sample ignored", sample->name); + return FLUID_FAILED; + } + + if((sample->sampletype & EXCLUSIVE_FLAGS) & ((sample->sampletype & EXCLUSIVE_FLAGS) - 1)) + { + FLUID_LOG(FLUID_INFO, "Sample '%s' should be either mono or left or right; using it anyway", sample->name); + } + + if((sample->sampletype & FLUID_SAMPLETYPE_LINKED) && (sample->sampletype & EXCLUSIVE_FLAGS)) + { + FLUID_LOG(FLUID_INFO, "Linked sample '%s' should not be mono, left or right at the same time; using it anyway", sample->name); + } + + if((sample->sampletype & EXCLUSIVE_FLAGS) == 0) + { + FLUID_LOG(FLUID_INFO, "Sample '%s' has no flags set, assuming mono", sample->name); + sample->sampletype = FLUID_SAMPLETYPE_MONO; + } + /* Ogg vorbis compressed samples in the SF3 format use byte indices for * sample start and end pointers before decompression. Standard SF2 samples * use sample word indices for all pointers, so use half the buffer_size @@ -729,6 +754,7 @@ int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size) } return FLUID_OK; +#undef EXCLUSIVE_FLAGS } /* Check the sample loop pointers and optionally convert them to something diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4d6d4f8d..67be9595 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,7 @@ ADD_FLUID_TEST(test_synth_chorus_reverb) ADD_FLUID_TEST(test_snprintf) ADD_FLUID_TEST(test_synth_process) ADD_FLUID_TEST(test_ct2hz) +ADD_FLUID_TEST(test_sample_validate) ADD_FLUID_TEST(test_seq_event_queue_sort) ADD_FLUID_TEST(test_seq_scale) ADD_FLUID_TEST(test_jack_obtaining_synth) diff --git a/test/test_sample_validate.c b/test/test_sample_validate.c new file mode 100644 index 00000000..0d166116 --- /dev/null +++ b/test/test_sample_validate.c @@ -0,0 +1,106 @@ + +#include "test.h" +#include "fluidsynth.h" +#include "sfloader/fluid_sfont.h" +#include "utils/fluid_sys.h" + + +// this tests ensures that samples with invalid SfSampleType flag combinations are rejected +int main(void) +{ + fluid_sample_t* sample = new_fluid_sample(); + sample->start = 0; + sample->end = 1; + + /// valid flags + { + sample->sampletype = FLUID_SAMPLETYPE_OGG_VORBIS; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_LINKED; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_MONO; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_RIGHT; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_LEFT; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + } + + /// valid, but unsupported linked sample flags + { + sample->sampletype = FLUID_SAMPLETYPE_LINKED; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_OGG_VORBIS; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_MONO; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_RIGHT; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_LEFT; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + } + + /// valid, but rejected ROM sample flags + { + sample->sampletype = FLUID_SAMPLETYPE_ROM; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype = FLUID_SAMPLETYPE_ROM | FLUID_SAMPLETYPE_OGG_VORBIS; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype = FLUID_SAMPLETYPE_ROM | FLUID_SAMPLETYPE_LINKED; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype = FLUID_SAMPLETYPE_ROM | FLUID_SAMPLETYPE_MONO; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype = FLUID_SAMPLETYPE_ROM | FLUID_SAMPLETYPE_RIGHT; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype = FLUID_SAMPLETYPE_ROM | FLUID_SAMPLETYPE_LEFT; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + } + + /// invalid flag combinations + { + // no flags set? technically illegal, but handle it as mono + sample->sampletype = 0; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype = FLUID_SAMPLETYPE_MONO | FLUID_SAMPLETYPE_RIGHT; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype |= FLUID_SAMPLETYPE_LEFT; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + + sample->sampletype |= FLUID_SAMPLETYPE_LINKED; + TEST_SUCCESS(fluid_sample_validate(sample, 2)); + } + + // unknown flags must be rejected (this seems to be implicitly required by SF3) + { + sample->sampletype = 0x20; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype |= 0x40; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype = 0x80; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + + sample->sampletype <<= 1; + TEST_ASSERT(fluid_sample_validate(sample, 2) == FLUID_FAILED); + } + + delete_fluid_sample(sample); + + return EXIT_SUCCESS; +}