mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-26 05:40:49 +00:00
Refactor sample cache loader
- move sample reading to fluid_sffile - refactor sample cache to use fluid_list and separate long functions into smaller ones - include sample start and count in cache key, in preparation for lazy loading - make defsfont use new sample cache loader interface
This commit is contained in:
parent
5bc2d33bb9
commit
4932b4af90
5 changed files with 288 additions and 228 deletions
|
@ -286,7 +286,7 @@ int delete_fluid_defsfont(fluid_defsfont_t* sfont)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfont->sampledata != NULL) {
|
if (sfont->sampledata != NULL) {
|
||||||
fluid_cached_sampledata_unload(sfont->sampledata);
|
fluid_samplecache_unload(sfont->sampledata);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (sfont->preset_stack_size > 0)
|
while (sfont->preset_stack_size > 0)
|
||||||
|
@ -347,8 +347,11 @@ int fluid_defsfont_load(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* f
|
||||||
sfont->sample24size = sfdata->sample24size;
|
sfont->sample24size = sfdata->sample24size;
|
||||||
|
|
||||||
/* load sample data in one block */
|
/* load sample data in one block */
|
||||||
if (fluid_defsfont_load_sampledata(sfont, fcbs) != FLUID_OK)
|
if (fluid_samplecache_load(sfdata, 0, sfdata->samplesize / 2, sfont->mlock,
|
||||||
|
&sfont->sampledata, &sfont->sample24data) == FLUID_FAILED)
|
||||||
|
{
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create all the sample headers */
|
/* Create all the sample headers */
|
||||||
p = sfdata->sample;
|
p = sfdata->sample;
|
||||||
|
@ -443,11 +446,21 @@ int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset
|
||||||
int
|
int
|
||||||
fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* fcbs)
|
fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* fcbs)
|
||||||
{
|
{
|
||||||
return fluid_cached_sampledata_load(sfont->filename,
|
SFData *sfdata;
|
||||||
sfont->samplepos, sfont->samplesize, &sfont->sampledata,
|
int ret;
|
||||||
sfont->sample24pos, sfont->sample24size, &sfont->sample24data,
|
|
||||||
sfont->mlock,
|
sfdata = fluid_sffile_load(sfont->filename, fcbs);
|
||||||
fcbs);
|
if (sfdata == NULL) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file");
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load sample data in one block */
|
||||||
|
ret = fluid_samplecache_load(sfdata, 0, sfdata->samplesize / 2, sfont->mlock,
|
||||||
|
&sfont->sampledata, &sfont->sample24data);
|
||||||
|
|
||||||
|
fluid_sffile_close (sfdata);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -21,287 +21,238 @@
|
||||||
* 02110-1301, USA
|
* 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* CACHED SAMPLE DATA LOADER
|
||||||
|
*
|
||||||
|
* This is a wrapper around fluid_sffile_read_sample_data that attempts to cache the read
|
||||||
|
* data across all FluidSynth instances in a global (process-wide) list.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "fluid_samplecache.h"
|
#include "fluid_samplecache.h"
|
||||||
#include "fluid_sys.h"
|
#include "fluid_sys.h"
|
||||||
#include "fluidsynth.h"
|
#include "fluidsynth.h"
|
||||||
|
#include "fluid_list.h"
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
*
|
|
||||||
* CACHED SAMPLEDATA LOADER
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct _fluid_cached_sampledata_t fluid_cached_sampledata_t;
|
typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
|
||||||
|
|
||||||
struct _fluid_cached_sampledata_t
|
struct _fluid_samplecache_entry_t
|
||||||
{
|
{
|
||||||
fluid_cached_sampledata_t *next;
|
/* The follwing members all form the cache key */
|
||||||
|
|
||||||
char *filename;
|
char *filename;
|
||||||
time_t modification_time;
|
time_t modification_time;
|
||||||
|
unsigned int sf_samplepos;
|
||||||
|
unsigned int sf_samplesize;
|
||||||
|
unsigned int sf_sample24pos;
|
||||||
|
unsigned int sf_sample24size;
|
||||||
|
unsigned int sample_start;
|
||||||
|
unsigned int sample_count;
|
||||||
|
/* End of cache key members */
|
||||||
|
|
||||||
|
short *sample_data;
|
||||||
|
char *sample_data24;
|
||||||
|
|
||||||
int num_references;
|
int num_references;
|
||||||
int mlock;
|
int mlocked;
|
||||||
|
|
||||||
short *sampledata;
|
|
||||||
unsigned int samplesize;
|
|
||||||
|
|
||||||
char *sample24data;
|
|
||||||
unsigned int sample24size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static fluid_list_t *samplecache_list = NULL;
|
||||||
|
static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
|
||||||
|
|
||||||
static fluid_cached_sampledata_t *all_cached_sampledata = NULL;
|
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_count);
|
||||||
static fluid_mutex_t cached_sampledata_mutex = FLUID_MUTEX_INIT;
|
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_count);
|
||||||
|
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
|
||||||
|
|
||||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
|
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
|
||||||
|
|
||||||
|
|
||||||
/* PUBLIC INTERFACE */
|
/* PUBLIC INTERFACE */
|
||||||
|
|
||||||
int fluid_cached_sampledata_load(char *filename,
|
int fluid_samplecache_load(SFData *sf,
|
||||||
unsigned int samplepos,
|
unsigned int sample_start, unsigned int sample_count,
|
||||||
unsigned int samplesize,
|
int try_mlock, short **sample_data, char **sample_data24)
|
||||||
short **sampledata,
|
|
||||||
unsigned int sample24pos,
|
|
||||||
unsigned int sample24size,
|
|
||||||
char **sample24data,
|
|
||||||
int try_mlock,
|
|
||||||
const fluid_file_callbacks_t *fcbs)
|
|
||||||
{
|
{
|
||||||
fluid_file fd = NULL;
|
fluid_samplecache_entry_t *entry;
|
||||||
short *loaded_sampledata = NULL;
|
|
||||||
char *loaded_sample24data = NULL;
|
|
||||||
fluid_cached_sampledata_t *cached_sampledata = NULL;
|
|
||||||
time_t modification_time;
|
|
||||||
|
|
||||||
fluid_mutex_lock(cached_sampledata_mutex);
|
fluid_mutex_lock(samplecache_mutex);
|
||||||
|
|
||||||
if (fluid_get_file_modification_time(filename, &modification_time) == FLUID_FAILED)
|
entry = get_samplecache_entry(sf, sample_start, sample_count);
|
||||||
|
if (entry == NULL)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
entry = new_samplecache_entry(sf, sample_start, sample_count);
|
||||||
modification_time = 0;
|
if (entry == NULL)
|
||||||
}
|
|
||||||
|
|
||||||
for (cached_sampledata = all_cached_sampledata; cached_sampledata;
|
|
||||||
cached_sampledata = cached_sampledata->next)
|
|
||||||
{
|
|
||||||
if (FLUID_STRCMP(filename, cached_sampledata->filename))
|
|
||||||
continue;
|
|
||||||
if (cached_sampledata->modification_time != modification_time)
|
|
||||||
continue;
|
|
||||||
if (cached_sampledata->samplesize != samplesize || cached_sampledata->sample24size != sample24size)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (try_mlock && !cached_sampledata->mlock)
|
|
||||||
{
|
{
|
||||||
if (fluid_mlock(cached_sampledata->sampledata, samplesize) != 0)
|
return FLUID_FAILED;
|
||||||
FLUID_LOG(FLUID_WARN,
|
|
||||||
"Failed to pin the sample data to RAM; swapping is possible.");
|
|
||||||
else
|
|
||||||
cached_sampledata->mlock = try_mlock;
|
|
||||||
|
|
||||||
if (cached_sampledata->sample24data != NULL)
|
|
||||||
if (fluid_mlock(cached_sampledata->sample24data, sample24size) != 0)
|
|
||||||
FLUID_LOG(FLUID_WARN,
|
|
||||||
"Failed to pin the sample24 data to RAM; swapping is possible.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached_sampledata->num_references++;
|
samplecache_list = fluid_list_prepend(samplecache_list, entry);
|
||||||
loaded_sampledata = cached_sampledata->sampledata;
|
|
||||||
loaded_sample24data = cached_sampledata->sample24data;
|
|
||||||
goto success_exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = fcbs->fopen(filename);
|
if (try_mlock && !entry->mlocked)
|
||||||
if (fd == NULL)
|
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Can't open soundfont file");
|
/* Lock the memory to disable paging. It's okay if this fails. It
|
||||||
goto error_exit;
|
* probably means that the user doesn't have the required permission. */
|
||||||
}
|
entry->mlocked = (fluid_mlock(entry->sample_data, entry->sample_count * 2) == 0);
|
||||||
if (fcbs->fseek(fd, samplepos, SEEK_SET) == FLUID_FAILED)
|
if (entry->sample_data24 != NULL)
|
||||||
{
|
|
||||||
perror("error");
|
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to seek position in data file");
|
|
||||||
goto error_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded_sampledata = (short *)FLUID_MALLOC(samplesize);
|
|
||||||
if (loaded_sampledata == NULL)
|
|
||||||
{
|
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
||||||
goto error_exit;
|
|
||||||
}
|
|
||||||
if (fcbs->fread(loaded_sampledata, samplesize, fd) == FLUID_FAILED)
|
|
||||||
{
|
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to read sample data");
|
|
||||||
goto error_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sample24pos > 0)
|
|
||||||
{
|
|
||||||
if (fcbs->fseek(fd, sample24pos, SEEK_SET) == FLUID_FAILED)
|
|
||||||
{
|
{
|
||||||
perror("error");
|
entry->mlocked &= (fluid_mlock(entry->sample_data24, entry->sample_count) == 0);
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to seek position in data file");
|
|
||||||
goto error_exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loaded_sample24data = (char *)FLUID_MALLOC(sample24size);
|
if (!entry->mlocked)
|
||||||
if (loaded_sample24data == NULL)
|
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory when allocating 24bit sample, ignoring");
|
|
||||||
}
|
|
||||||
else if (fcbs->fread(loaded_sample24data, sample24size, fd) == FLUID_FAILED)
|
|
||||||
{
|
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to read sample24 data");
|
|
||||||
FLUID_FREE(loaded_sample24data);
|
|
||||||
loaded_sample24data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fcbs->fclose(fd);
|
|
||||||
fd = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
cached_sampledata = (fluid_cached_sampledata_t *)FLUID_MALLOC(sizeof(fluid_cached_sampledata_t));
|
|
||||||
if (cached_sampledata == NULL)
|
|
||||||
{
|
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
|
||||||
goto error_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lock the memory to disable paging. It's okay if this fails. It
|
|
||||||
probably means that the user doesn't have the required permission. */
|
|
||||||
cached_sampledata->mlock = 0;
|
|
||||||
if (try_mlock)
|
|
||||||
{
|
|
||||||
if (fluid_mlock(loaded_sampledata, samplesize) != 0)
|
|
||||||
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
|
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
|
||||||
else
|
|
||||||
cached_sampledata->mlock = try_mlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If this machine is big endian, the sample have to byte swapped */
|
|
||||||
if (FLUID_IS_BIG_ENDIAN)
|
|
||||||
{
|
|
||||||
unsigned char *cbuf;
|
|
||||||
unsigned char hi, lo;
|
|
||||||
unsigned int i, j;
|
|
||||||
short s;
|
|
||||||
cbuf = (unsigned char *)loaded_sampledata;
|
|
||||||
for (i = 0, j = 0; j < samplesize; i++)
|
|
||||||
{
|
|
||||||
lo = cbuf[j++];
|
|
||||||
hi = cbuf[j++];
|
|
||||||
s = (hi << 8) | lo;
|
|
||||||
loaded_sampledata[i] = s;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cached_sampledata->filename = FLUID_STRDUP(filename);
|
entry->num_references++;
|
||||||
if (cached_sampledata->filename == NULL)
|
*sample_data = entry->sample_data;
|
||||||
{
|
*sample_data24 = entry->sample_data24;
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
|
||||||
goto error_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
cached_sampledata->modification_time = modification_time;
|
fluid_mutex_unlock(samplecache_mutex);
|
||||||
cached_sampledata->num_references = 1;
|
|
||||||
cached_sampledata->sampledata = loaded_sampledata;
|
|
||||||
cached_sampledata->samplesize = samplesize;
|
|
||||||
cached_sampledata->sample24data = loaded_sample24data;
|
|
||||||
cached_sampledata->sample24size = sample24size;
|
|
||||||
|
|
||||||
cached_sampledata->next = all_cached_sampledata;
|
|
||||||
all_cached_sampledata = cached_sampledata;
|
|
||||||
|
|
||||||
|
|
||||||
success_exit:
|
|
||||||
fluid_mutex_unlock(cached_sampledata_mutex);
|
|
||||||
*sampledata = loaded_sampledata;
|
|
||||||
*sample24data = loaded_sample24data;
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
|
|
||||||
error_exit:
|
|
||||||
if (fd != NULL)
|
|
||||||
{
|
|
||||||
fcbs->fclose(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
FLUID_FREE(loaded_sampledata);
|
|
||||||
FLUID_FREE(loaded_sample24data);
|
|
||||||
|
|
||||||
if (cached_sampledata != NULL)
|
|
||||||
{
|
|
||||||
FLUID_FREE(cached_sampledata->filename);
|
|
||||||
}
|
|
||||||
FLUID_FREE(cached_sampledata);
|
|
||||||
|
|
||||||
fluid_mutex_unlock(cached_sampledata_mutex);
|
|
||||||
*sampledata = NULL;
|
|
||||||
*sample24data = NULL;
|
|
||||||
return FLUID_FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fluid_cached_sampledata_unload(const short *sampledata)
|
int fluid_samplecache_unload(const short *sample_data)
|
||||||
{
|
{
|
||||||
fluid_cached_sampledata_t *prev = NULL;
|
fluid_list_t *entry_list;
|
||||||
fluid_cached_sampledata_t *cached_sampledata;
|
fluid_samplecache_entry_t *entry;
|
||||||
|
|
||||||
fluid_mutex_lock(cached_sampledata_mutex);
|
fluid_mutex_lock(samplecache_mutex);
|
||||||
cached_sampledata = all_cached_sampledata;
|
|
||||||
|
|
||||||
while (cached_sampledata != NULL)
|
entry_list = samplecache_list;
|
||||||
|
while (entry_list)
|
||||||
{
|
{
|
||||||
if (sampledata == cached_sampledata->sampledata)
|
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
|
||||||
|
|
||||||
|
if (sample_data == entry->sample_data)
|
||||||
{
|
{
|
||||||
|
entry->num_references--;
|
||||||
|
|
||||||
cached_sampledata->num_references--;
|
if (entry->num_references == 0)
|
||||||
|
|
||||||
if (cached_sampledata->num_references == 0)
|
|
||||||
{
|
{
|
||||||
if (cached_sampledata->mlock)
|
if (entry->mlocked)
|
||||||
{
|
{
|
||||||
fluid_munlock(cached_sampledata->sampledata, cached_sampledata->samplesize);
|
fluid_munlock(entry->sample_data, entry->sample_count * 2);
|
||||||
fluid_munlock(cached_sampledata->sample24data, cached_sampledata->sample24size);
|
fluid_munlock(entry->sample_data24, entry->sample_count);
|
||||||
}
|
|
||||||
FLUID_FREE(cached_sampledata->sampledata);
|
|
||||||
FLUID_FREE(cached_sampledata->sample24data);
|
|
||||||
FLUID_FREE(cached_sampledata->filename);
|
|
||||||
|
|
||||||
if (prev != NULL)
|
|
||||||
{
|
|
||||||
prev->next = cached_sampledata->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
all_cached_sampledata = cached_sampledata->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_FREE(cached_sampledata);
|
fluid_list_remove(samplecache_list, entry);
|
||||||
|
delete_samplecache_entry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto success_exit;
|
goto success_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = cached_sampledata;
|
entry_list = fluid_list_next(entry_list);
|
||||||
cached_sampledata = cached_sampledata->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_LOG(FLUID_ERR, "Trying to free sampledata not found in cache.");
|
FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache.");
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
|
|
||||||
success_exit:
|
success_exit:
|
||||||
fluid_mutex_unlock(cached_sampledata_mutex);
|
fluid_mutex_unlock(samplecache_mutex);
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
|
|
||||||
error_exit:
|
error_exit:
|
||||||
fluid_mutex_unlock(cached_sampledata_mutex);
|
fluid_mutex_unlock(samplecache_mutex);
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Private functions */
|
/* Private functions */
|
||||||
|
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
|
||||||
|
unsigned int sample_start,
|
||||||
|
unsigned int sample_count)
|
||||||
|
{
|
||||||
|
fluid_samplecache_entry_t *entry;
|
||||||
|
|
||||||
|
entry = FLUID_NEW(fluid_samplecache_entry_t);
|
||||||
|
if (entry == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
FLUID_MEMSET(entry, 0, sizeof(*entry));
|
||||||
|
|
||||||
|
entry->filename = FLUID_STRDUP(sf->fname);
|
||||||
|
if (entry->filename == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||||
|
entry->modification_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->sf_samplepos = sf->samplepos;
|
||||||
|
entry->sf_samplesize = sf->samplesize;
|
||||||
|
entry->sf_sample24pos = sf->sample24pos;
|
||||||
|
entry->sf_sample24size = sf->sample24size;
|
||||||
|
entry->sample_start = sample_start;
|
||||||
|
entry->sample_count = sample_count;
|
||||||
|
|
||||||
|
if (fluid_sffile_read_sample_data(sf, sample_start, sample_count,
|
||||||
|
&entry->sample_data, &entry->sample_data24) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
error_exit:
|
||||||
|
delete_samplecache_entry(entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
|
||||||
|
{
|
||||||
|
fluid_return_if_fail(entry != NULL);
|
||||||
|
|
||||||
|
FLUID_FREE(entry->filename);
|
||||||
|
FLUID_FREE(entry->sample_data);
|
||||||
|
FLUID_FREE(entry->sample_data24);
|
||||||
|
FLUID_FREE(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
|
||||||
|
unsigned int sample_start,
|
||||||
|
unsigned int sample_count)
|
||||||
|
{
|
||||||
|
time_t mtime;
|
||||||
|
fluid_list_t *entry_list;
|
||||||
|
fluid_samplecache_entry_t *entry;
|
||||||
|
|
||||||
|
if (fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||||
|
mtime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_list = samplecache_list;
|
||||||
|
while (entry_list)
|
||||||
|
{
|
||||||
|
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
|
||||||
|
|
||||||
|
if ((FLUID_STRCMP(sf->fname, entry->filename) == 0) &&
|
||||||
|
(mtime == entry->modification_time) &&
|
||||||
|
(sf->samplepos == entry->sf_samplepos) &&
|
||||||
|
(sf->samplesize == entry->sf_samplesize) &&
|
||||||
|
(sf->sample24pos == entry->sf_sample24pos) &&
|
||||||
|
(sf->sample24size == entry->sf_sample24size) &&
|
||||||
|
(sample_start == entry->sample_start) &&
|
||||||
|
(sample_count == entry->sample_count))
|
||||||
|
{
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_list = fluid_list_next(entry_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
|
static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,17 +23,12 @@
|
||||||
#define _FLUID_SAMPLECACHE_H
|
#define _FLUID_SAMPLECACHE_H
|
||||||
|
|
||||||
#include "fluid_sfont.h"
|
#include "fluid_sfont.h"
|
||||||
|
#include "fluid_sffile.h"
|
||||||
|
|
||||||
int fluid_cached_sampledata_load(char *filename,
|
int fluid_samplecache_load(SFData *sf,
|
||||||
unsigned int samplepos,
|
unsigned int sample_start, unsigned int sample_count,
|
||||||
unsigned int samplesize,
|
int try_mlock, short **data, char **data24);
|
||||||
short **sampledata,
|
|
||||||
unsigned int sample24pos,
|
|
||||||
unsigned int sample24size,
|
|
||||||
char **sample24data,
|
|
||||||
int try_mlock,
|
|
||||||
const fluid_file_callbacks_t *fcbs);
|
|
||||||
|
|
||||||
int fluid_cached_sampledata_unload(const short *sampledata);
|
int fluid_samplecache_unload(const short *sample_data);
|
||||||
|
|
||||||
#endif /* _FLUID_SAMPLECACHE_H */
|
#endif /* _FLUID_SAMPLECACHE_H */
|
||||||
|
|
|
@ -353,6 +353,105 @@ error_exit:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load sample data from the soundfont file
|
||||||
|
*
|
||||||
|
* @param sf SFFile instance
|
||||||
|
* @param start start offset of sample data (in sample words from start of sample data chunk)
|
||||||
|
* @param count number of samples to read (in sample words)
|
||||||
|
* @param data pointer to sample data pointer, set on success
|
||||||
|
* @param data24 pointer to 24-bit sample data pointer if 24-bit data present, set on success
|
||||||
|
*
|
||||||
|
* @return FLUID_OK on success, otherwise FLUID_FAILED
|
||||||
|
*/
|
||||||
|
int fluid_sffile_read_sample_data(SFData *sf, unsigned int start, unsigned int count,
|
||||||
|
short **data, char **data24)
|
||||||
|
{
|
||||||
|
unsigned int end;
|
||||||
|
short *loaded_data = NULL;
|
||||||
|
char *loaded_data24 = NULL;
|
||||||
|
|
||||||
|
fluid_return_val_if_fail(count != 0, FLUID_FAILED);
|
||||||
|
|
||||||
|
end = start + count;
|
||||||
|
|
||||||
|
if (((start * 2) > sf->samplesize) || ((end * 2) > sf->samplesize))
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf->sample24pos && ((start > sf->sample24size) || (end > sf->sample24size)))
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load 16-bit sample data */
|
||||||
|
if (sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * 2), SEEK_SET) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
perror("error");
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to seek position in data file");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded_data = (short *)FLUID_MALLOC(count * 2);
|
||||||
|
if (loaded_data == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf->fcbs->fread(loaded_data, count * 2, sf->sffd) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to read sample data");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this machine is big endian, byte swap the 16 bit samples */
|
||||||
|
if (FLUID_IS_BIG_ENDIAN)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
loaded_data[i] = FLUID_LE16TOH(loaded_data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optionally load additional 8 bit sample data for 24-bit support */
|
||||||
|
if (sf->sample24pos)
|
||||||
|
{
|
||||||
|
if (sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
perror("error");
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to seek position in data file");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded_data24 = (char *)FLUID_MALLOC(count);
|
||||||
|
if (loaded_data24 == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf->fcbs->fread(loaded_data24, count, sf->sffd) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = loaded_data;
|
||||||
|
*data24 = loaded_data24;
|
||||||
|
|
||||||
|
return FLUID_OK;
|
||||||
|
|
||||||
|
error_exit:
|
||||||
|
FLUID_FREE(loaded_data);
|
||||||
|
FLUID_FREE(loaded_data24);
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a SoundFont file and free the SFData structure.
|
* Close a SoundFont file and free the SFData structure.
|
||||||
*
|
*
|
||||||
|
|
|
@ -206,5 +206,7 @@ struct _SFShdr
|
||||||
/* Public functions */
|
/* Public functions */
|
||||||
SFData *fluid_sffile_load(const char *fname, const fluid_file_callbacks_t *fcbs);
|
SFData *fluid_sffile_load(const char *fname, const fluid_file_callbacks_t *fcbs);
|
||||||
void fluid_sffile_close(SFData *sf);
|
void fluid_sffile_close(SFData *sf);
|
||||||
|
int fluid_sffile_read_sample_data(SFData *sf, unsigned int start, unsigned int count,
|
||||||
|
short **data, char **data24);
|
||||||
|
|
||||||
#endif /* _FLUID_SFFILE_H */
|
#endif /* _FLUID_SFFILE_H */
|
||||||
|
|
Loading…
Reference in a new issue