Hi Hamish, Am Dienstag, den 24.11.2015, 22:40 +1100 schrieb ham...@cloud.net.au: > Thanks Fabian. I will try tomorrow.
I think I found the real culprit: I had an off-by-one error in the calculation of the sample sizes. In FluidSynth, sample->end points to the last valid point in a sample, not to the first point after. This means that all samples were calculated one byte too short. Now, all samples are correctly decoded, i.e. there are no samples with sfinfo.frames == 0 anymore. This also means that the loopstart and loopend variables are now correctly set; the workaround of setting them both to 0 that I previously suggested is not necessary anymore. Also, most of the quality loss that I originally blamed on the compression seems to be gone now. Please find a new patch attached. Thanks, Fabian
Description: Add support for sound fonts in SF3 format that contain Ogg Vorbis compressed samples Author: Fabian Greffrath <fab...@debian.org> Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=740710 Forwarded: https://sourceforge.net/p/fluidsynth/tickets/142/ Last-Update: 2015-11-26 --- a/include/fluidsynth/sfont.h +++ b/include/fluidsynth/sfont.h @@ -270,6 +270,7 @@ struct _fluid_sample_t #define FLUID_SAMPLETYPE_RIGHT 2 /**< Flag for #fluid_sample_t \a sampletype field for right samples of a stereo pair */ #define FLUID_SAMPLETYPE_LEFT 4 /**< Flag for #fluid_sample_t \a sampletype field for left samples of a stereo pair */ #define FLUID_SAMPLETYPE_LINKED 8 /**< Flag for #fluid_sample_t \a sampletype field, not used currently */ +#define FLUID_SAMPLETYPE_OGG_VORBIS 0x10 /**< Flag for #fluid_sample_t \a sampletype field for Ogg Vorbis compressed samples */ #define FLUID_SAMPLETYPE_ROM 0x8000 /**< Flag for #fluid_sample_t \a sampletype field, ROM sample, causes sample to be ignored */ --- a/src/sfloader/fluid_defsfont.c +++ b/src/sfloader/fluid_defsfont.c @@ -26,6 +26,10 @@ /* Todo: Get rid of that 'include' */ #include "fluid_sys.h" +#if LIBSNDFILE_SUPPORT +#include <sndfile.h> +#endif + /*************************************************************** * * SFONT LOADER @@ -1582,6 +1586,14 @@ new_fluid_sample() int delete_fluid_sample(fluid_sample_t* sample) { + if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS) + { +#if LIBSNDFILE_SUPPORT + if (sample->data) + FLUID_FREE(sample->data); +#endif + } + FLUID_FREE(sample); return FLUID_OK; } @@ -1598,6 +1610,61 @@ fluid_sample_in_rom(fluid_sample_t* samp /* * fluid_sample_import_sfont */ +#if LIBSNDFILE_SUPPORT +// virtual file access rountines to allow for handling +// samples as virtual files in memory +static sf_count_t sfvio_pos; + +static sf_count_t +sfvio_get_filelen(void* user_data) +{ + fluid_sample_t *sample = (fluid_sample_t *)user_data; + + return (sf_count_t)(sample->end + 1 - sample->start); +}; + +static sf_count_t +sfvio_seek(sf_count_t offset, int whence, void* user_data) +{ + fluid_sample_t *sample = (fluid_sample_t *)user_data; + + switch (whence) + { + case SEEK_SET: + sfvio_pos = offset; + break; + case SEEK_CUR: + sfvio_pos += offset; + break; + case SEEK_END: + sfvio_pos = sfvio_get_filelen(user_data) + offset; + break; + } + + return sfvio_pos; +}; + +static sf_count_t +sfvio_read(void* ptr, sf_count_t count, void* user_data) +{ + fluid_sample_t *sample = (fluid_sample_t *)user_data; + + if (count > sfvio_get_filelen(user_data) - sfvio_pos) + count = sfvio_get_filelen(user_data) - sfvio_pos; + + memcpy(ptr, (char *)sample->data + sample->start + sfvio_pos, count); + sfvio_pos += count; + + return count; +}; + +static sf_count_t +sfvio_tell (void* user_data) +{ + return sfvio_pos; +}; +#endif + int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont) { @@ -1612,6 +1679,87 @@ fluid_sample_import_sfont(fluid_sample_t sample->pitchadj = sfsample->pitchadj; sample->sampletype = sfsample->sampletype; + if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS) + { +#if LIBSNDFILE_SUPPORT + SNDFILE *sndfile; + SF_INFO sfinfo; + SF_VIRTUAL_IO sfvio = { + sfvio_get_filelen, + sfvio_seek, + sfvio_read, + NULL, + sfvio_tell + }; + short *sampledata_ogg; + + // initialize file position indicator and SF_INFO structure + sfvio_pos = 0; + memset(&sfinfo, 0, sizeof(sfinfo)); + + // open sample as a virtual file in memory + sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, sample); + if (!sndfile) + { + FLUID_LOG(FLUID_ERR, sf_strerror(sndfile)); + return FLUID_FAILED; + } + + // empty sample + if (!sfinfo.frames || !sfinfo.channels) + { + sample->start = sample->end = + sample->loopstart = sample->loopend = + sample->valid = 0; + sample->data = NULL; + sf_close(sndfile); + return FLUID_OK; + } + + // allocate memory for uncompressed sample data stream + sampledata_ogg = (short *)FLUID_MALLOC(sfinfo.frames * sfinfo.channels * sizeof(short)); + if (!sampledata_ogg) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + sf_close(sndfile); + return FLUID_FAILED; + } + + // uncompress sample data stream + if (sf_readf_short(sndfile, sampledata_ogg, sfinfo.frames) < sfinfo.frames) + { + FLUID_FREE(sampledata_ogg); + FLUID_LOG(FLUID_ERR, sf_strerror(sndfile)); + sf_close(sndfile); + return FLUID_FAILED; + } + sf_close(sndfile); + + // point sample data to uncompressed data stream + sample->data = sampledata_ogg; + sample->start = 0; + sample->end = sfinfo.frames - 1; + + /* loop is fowled?? (cluck cluck :) */ + if (sample->loopend > sample->end || + sample->loopstart >= sample->loopend || + sample->loopstart <= sample->start) + { + /* can pad loop by 8 samples and ensure at least 4 for loop (2*8+4) */ + if ((sample->end - sample->start) >= 20) + { + sample->loopstart = sample->start + 8; + sample->loopend = sample->end - 8; + } + else /* loop is fowled, sample is tiny (can't pad 8 samples) */ + { + sample->loopstart = sample->start + 1; + sample->loopend = sample->end - 1; + } + } +#endif + } + if (sample->sampletype & FLUID_SAMPLETYPE_ROM) { sample->valid = 0; FLUID_LOG(FLUID_WARN, "Ignoring sample %s: can't use ROM samples", sample->name); @@ -1937,6 +2085,10 @@ process_info (int size, SFData * sf, FIL return (FAIL); } +#if LIBSNDFILE_SUPPORT + if (sf->version.major == 3) {} + else +#endif if (sf->version.major > 2) { FLUID_LOG (FLUID_WARN, _("Sound font version is %d.%d which is newer than" @@ -2958,6 +3110,9 @@ fixup_sample (SFData * sf) return (OK); } + /* compressed samples get fixed up after decompression */ + else if (sam->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS) + {} else if (sam->loopend > sam->end || sam->loopstart >= sam->loopend || sam->loopstart <= sam->start) { /* loop is fowled?? (cluck cluck :) */
signature.asc
Description: This is a digitally signed message part