Enable decompressed Ogg Vorbis samples to be stored in sample cache

This change moves the Ogg Vorbis decompression to fluid_sffile, so that
this is the only place where we have to deal with compressed audio.

It also changes the way the samples are loaded for SF3 files: previously,
the compressed data was copied into memory, then the individual samples
were decompressed (resulting in both compressed and decompressed data to
stay in memory). Also, decompressed data wasn't cached, so previous loads
of the same file ran the decompressed again for each sample.

After this change, the vorbis decompression is changed so that it reads the
compressed data directly from the Soundfont file. And the resulting WAV
data is stored in the sample cache.
This commit is contained in:
Marcus Weseloh 2018-04-15 19:50:36 +02:00
parent f52bbf53a4
commit a985c68a13
8 changed files with 432 additions and 299 deletions

View file

@ -21,11 +21,6 @@
#include "fluid_sfont.h"
#include "fluid_sys.h"
#if LIBSNDFILE_SUPPORT
#include <sndfile.h>
#endif
void * default_fopen(const char * path)
{
@ -605,16 +600,6 @@ int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size)
* to the data word after the last sample. FIXME: why? */
unsigned int sample_end = sample->end + 1;
/* Checking loops on compressed samples makes no sense at all and is really
* a programming error. Disable the loop to be on the safe side. */
if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
{
FLUID_LOG(FLUID_ERR, "Sample '%s': checking loop on compressed sample, disabling loop",
sample->name);
sample->loopstart = sample->loopend = 0;
return TRUE;
}
if (sample->loopstart == sample->loopend)
{
/* Some SoundFonts disable loops by setting loopstart = loopend. While
@ -670,128 +655,3 @@ int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size)
return modified;
}
#if LIBSNDFILE_SUPPORT
// virtual file access rountines to allow for handling
// samples as virtual files in memory
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:
sample->userdata = (void *)offset;
break;
case SEEK_CUR:
sample->userdata = (void *)((sf_count_t)sample->userdata + offset);
break;
case SEEK_END:
sample->userdata = (void *)(sfvio_get_filelen(user_data) + offset);
break;
}
return (sf_count_t)sample->userdata;
}
static sf_count_t
sfvio_read(void* ptr, sf_count_t count, void* user_data)
{
fluid_sample_t *sample = (fluid_sample_t *)user_data;
sf_count_t remain = sfvio_get_filelen(user_data) - (sf_count_t)sample->userdata;
if (count > remain)
count = remain;
memcpy(ptr, (char *)sample->data + sample->start + (sf_count_t)sample->userdata, count);
sample->userdata = (void *)((sf_count_t)sample->userdata + count);
return count;
}
static sf_count_t
sfvio_tell (void* user_data)
{
fluid_sample_t *sample = (fluid_sample_t *)user_data;
return (sf_count_t)sample->userdata;
}
int fluid_sample_decompress_vorbis(fluid_sample_t *sample)
{
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
g_assert(sample->userdata == NULL);
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 = 0;
sample->loopstart = sample->loopend = 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->auto_free = TRUE;
sample->start = 0;
sample->end = sfinfo.frames - 1;
return FLUID_OK;
}
#else
int fluid_sample_decompress_vorbis(fluid_sample_t *sample)
{
return FLUID_FAILED;
}
#endif