mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 23:11:41 +00:00
Merge pull request #183 from fabiangreffrath/sf3-fonts
Add support for sound fonts in SF3 format that contain Ogg Vorbis compressed samples
This commit is contained in:
commit
070dc29d20
2 changed files with 166 additions and 19 deletions
|
@ -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 @since 1.1.7 */
|
||||
#define FLUID_SAMPLETYPE_ROM 0x8000 /**< Flag for #fluid_sample_t \a sampletype field, ROM sample, causes sample to be ignored */
|
||||
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
/* Todo: Get rid of that 'include' */
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* SFONT LOADER
|
||||
|
@ -1801,6 +1805,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;
|
||||
}
|
||||
|
@ -1817,6 +1829,62 @@ fluid_sample_in_rom(fluid_sample_t* sample)
|
|||
/*
|
||||
* 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_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;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont)
|
||||
{
|
||||
|
@ -1831,6 +1899,71 @@ fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defs
|
|||
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
|
||||
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 =
|
||||
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;
|
||||
|
||||
fixup_sample_loop(sample);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sample->sampletype & FLUID_SAMPLETYPE_ROM) {
|
||||
sample->valid = 0;
|
||||
FLUID_LOG(FLUID_WARN, "Ignoring sample %s: can't use ROM samples", sample->name);
|
||||
|
@ -2157,7 +2290,17 @@ process_info (int size, SFData * sf, FILE * fd)
|
|||
return (FAIL);
|
||||
}
|
||||
|
||||
if (sf->version.major > 2) {
|
||||
if (sf->version.major == 3) {
|
||||
#if !LIBSNDFILE_SUPPORT
|
||||
FLUID_LOG (FLUID_WARN,
|
||||
_("Sound font version is %d.%d but fluidsynth was compiled without"
|
||||
" support for (v3.x)"),
|
||||
sf->version.major,
|
||||
sf->version.minor);
|
||||
return (FAIL);
|
||||
#endif
|
||||
}
|
||||
else if (sf->version.major > 2) {
|
||||
FLUID_LOG (FLUID_WARN,
|
||||
_("Sound font version is %d.%d which is newer than"
|
||||
" what this version of fluidsynth was designed for (v2.0x)"),
|
||||
|
@ -3181,44 +3324,47 @@ fixup_sample (SFData * sf)
|
|||
|
||||
/* if sample is not a ROM sample and end is over the sample data chunk
|
||||
or sam start is greater than 4 less than the end (at least 4 samples) */
|
||||
if ((!(sam->sampletype & FLUID_SAMPLETYPE_ROM)
|
||||
&& sam->end > sdtachunk_size) || sam->start > (sam->end - 4))
|
||||
{
|
||||
FLUID_LOG (FLUID_WARN, _("Sample '%s' start/end file positions are invalid,"
|
||||
" disabling and will not be saved"), sam->name);
|
||||
if ((!(sam->sampletype & FLUID_SAMPLETYPE_ROM) && sam->end > sdtachunk_size)
|
||||
|| sam->start > (sam->end - 4))
|
||||
{
|
||||
FLUID_LOG (FLUID_WARN, _("Sample '%s' start/end file positions are invalid,"
|
||||
" disabling and will not be saved"), sam->name);
|
||||
|
||||
/* disable sample by setting all sample markers to 0 */
|
||||
sam->start = sam->end = sam->loopstart = sam->loopend = 0;
|
||||
/* disable sample by setting all sample markers to 0 */
|
||||
sam->start = sam->end = sam->loopstart = sam->loopend = 0;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
/* compressed samples get fixed up after decompression */
|
||||
else if (sam->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
|
||||
{}
|
||||
else if (invalid_loopstart || invalid_loopend || loopend_end_mismatch)
|
||||
{
|
||||
{
|
||||
/* loop is fowled?? (cluck cluck :) */
|
||||
invalid_loops |= TRUE;
|
||||
|
||||
/* force incorrect loop points into the sample range, ignore padding */
|
||||
/* force incorrect loop points into the sample range, ignore padding */
|
||||
if(invalid_loopstart)
|
||||
{
|
||||
{
|
||||
FLUID_LOG (FLUID_DBG, _("Sample '%s' has unusable loop start '%d',"
|
||||
" setting to sample start at '%d'+1"), sam->name, sam->loopstart, sam->start);
|
||||
sam->loopstart = sam->start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(invalid_loopend)
|
||||
{
|
||||
{
|
||||
FLUID_LOG (FLUID_DBG, _("Sample '%s' has unusable loop stop '%d',"
|
||||
" setting to sample stop at '%d'-1"), sam->name, sam->loopend, sam->end);
|
||||
/* since sam->end points after valid sample data, set loopend to last sample available */
|
||||
sam->loopend = sam->end - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(loopend_end_mismatch)
|
||||
{
|
||||
{
|
||||
FLUID_LOG (FLUID_DBG, _("Sample '%s' has invalid loop stop '%d',"
|
||||
" sample stop at '%d', using it anyway"), sam->name, sam->loopend, sam->end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* convert sample end, loopstart, loopend to offsets from sam->start */
|
||||
sam->end -= sam->start + 1; /* marks last sample, contrary to SF spec. */
|
||||
|
|
Loading…
Reference in a new issue