2003-03-11 16:56:45 +00:00
|
|
|
/* FluidSynth - A Software Synthesizer
|
|
|
|
*
|
|
|
|
* Copyright (C) 2003 Peter Hanappe and others.
|
|
|
|
*
|
2003-08-19 20:57:00 +00:00
|
|
|
* SoundFont file loading code borrowed from Smurf SoundFont Editor
|
|
|
|
* Copyright (C) 1999-2001 Josh Green
|
|
|
|
*
|
2003-03-11 16:56:45 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
2017-07-12 15:45:23 +00:00
|
|
|
* modify it under the terms of the GNU Lesser General Public License
|
2017-07-12 15:53:03 +00:00
|
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
2003-03-11 16:56:45 +00:00
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2017-07-12 15:45:23 +00:00
|
|
|
* Lesser General Public License for more details.
|
2007-03-04 16:45:05 +00:00
|
|
|
*
|
2017-07-12 15:54:54 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2003-03-11 16:56:45 +00:00
|
|
|
* License along with this library; if not, write to the Free
|
2011-08-15 12:57:10 +00:00
|
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301, USA
|
2003-03-11 16:56:45 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "fluid_defsfont.h"
|
2003-05-29 15:43:52 +00:00
|
|
|
/* Todo: Get rid of that 'include' */
|
2003-03-11 16:56:45 +00:00
|
|
|
#include "fluid_sys.h"
|
2003-05-29 15:43:52 +00:00
|
|
|
|
2017-05-04 07:56:11 +00:00
|
|
|
#if LIBSNDFILE_SUPPORT
|
|
|
|
#include <sndfile.h>
|
|
|
|
#endif
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* SFONT LOADER
|
|
|
|
*/
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
fluid_sfloader_t* loader;
|
|
|
|
|
|
|
|
loader = FLUID_NEW(fluid_sfloader_t);
|
|
|
|
if (loader == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
loader->data = settings;
|
2003-03-11 16:56:45 +00:00
|
|
|
loader->free = delete_fluid_defsfloader;
|
|
|
|
loader->load = fluid_defsfloader_load;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
return loader;
|
|
|
|
}
|
|
|
|
|
|
|
|
int delete_fluid_defsfloader(fluid_sfloader_t* loader)
|
|
|
|
{
|
|
|
|
if (loader) {
|
|
|
|
FLUID_FREE(loader);
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename)
|
|
|
|
{
|
|
|
|
fluid_defsfont_t* defsfont;
|
|
|
|
fluid_sfont_t* sfont;
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
defsfont = new_fluid_defsfont(loader->data);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
if (defsfont == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fluid_defsfont_load(defsfont, filename) == FLUID_FAILED) {
|
|
|
|
delete_fluid_defsfont(defsfont);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfont = FLUID_NEW(fluid_sfont_t);
|
|
|
|
if (sfont == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfont->data = defsfont;
|
|
|
|
sfont->free = fluid_defsfont_sfont_delete;
|
|
|
|
sfont->get_name = fluid_defsfont_sfont_get_name;
|
|
|
|
sfont->get_preset = fluid_defsfont_sfont_get_preset;
|
|
|
|
sfont->iteration_start = fluid_defsfont_sfont_iteration_start;
|
|
|
|
sfont->iteration_next = fluid_defsfont_sfont_iteration_next;
|
|
|
|
|
|
|
|
return sfont;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* PUBLIC INTERFACE
|
|
|
|
*/
|
|
|
|
|
|
|
|
int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont)
|
|
|
|
{
|
|
|
|
if (delete_fluid_defsfont(sfont->data) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
FLUID_FREE(sfont);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-20 10:55:55 +00:00
|
|
|
const char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data);
|
|
|
|
}
|
|
|
|
|
2011-08-06 17:25:57 +00:00
|
|
|
fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s)
|
|
|
|
{
|
|
|
|
/* This function is here just to avoid an ABI/SONAME bump, see ticket #98. Should never be used. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_preset_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
|
|
|
|
{
|
2013-05-12 10:21:43 +00:00
|
|
|
fluid_preset_t* preset = NULL;
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_t* defpreset;
|
2013-05-12 10:21:43 +00:00
|
|
|
fluid_defsfont_t* defsfont = sfont->data;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
2013-05-12 10:21:43 +00:00
|
|
|
defpreset = fluid_defsfont_get_preset(defsfont, bank, prenum);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
if (defpreset == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-12 10:21:43 +00:00
|
|
|
if (defsfont->preset_stack_size > 0) {
|
|
|
|
defsfont->preset_stack_size--;
|
|
|
|
preset = defsfont->preset_stack[defsfont->preset_stack_size];
|
|
|
|
}
|
|
|
|
if (!preset)
|
|
|
|
preset = FLUID_NEW(fluid_preset_t);
|
|
|
|
if (!preset) {
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-08-30 00:55:23 +00:00
|
|
|
preset->sfont = sfont;
|
2003-03-11 16:56:45 +00:00
|
|
|
preset->data = defpreset;
|
|
|
|
preset->free = fluid_defpreset_preset_delete;
|
|
|
|
preset->get_name = fluid_defpreset_preset_get_name;
|
|
|
|
preset->get_banknum = fluid_defpreset_preset_get_banknum;
|
|
|
|
preset->get_num = fluid_defpreset_preset_get_num;
|
|
|
|
preset->noteon = fluid_defpreset_preset_noteon;
|
|
|
|
preset->notify = NULL;
|
|
|
|
|
|
|
|
return preset;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_defsfont_iteration_start((fluid_defsfont_t*) sfont->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset)
|
|
|
|
{
|
|
|
|
preset->free = fluid_defpreset_preset_delete;
|
|
|
|
preset->get_name = fluid_defpreset_preset_get_name;
|
|
|
|
preset->get_banknum = fluid_defpreset_preset_get_banknum;
|
|
|
|
preset->get_num = fluid_defpreset_preset_get_num;
|
|
|
|
preset->noteon = fluid_defpreset_preset_noteon;
|
|
|
|
preset->notify = NULL;
|
|
|
|
|
|
|
|
return fluid_defsfont_iteration_next((fluid_defsfont_t*) sfont->data, preset);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
|
|
|
{
|
2013-05-12 10:21:43 +00:00
|
|
|
fluid_defpreset_t* defpreset = preset ? preset->data : NULL;
|
|
|
|
fluid_defsfont_t* sfont = defpreset ? defpreset->sfont : NULL;
|
2007-09-02 23:23:47 +00:00
|
|
|
|
2013-05-12 10:21:43 +00:00
|
|
|
if (sfont && sfont->preset_stack_size < sfont->preset_stack_capacity) {
|
|
|
|
sfont->preset_stack[sfont->preset_stack_size] = preset;
|
|
|
|
sfont->preset_stack_size++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
FLUID_FREE(preset);
|
2007-09-02 23:23:47 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-20 10:55:55 +00:00
|
|
|
const char* fluid_defpreset_preset_get_name(fluid_preset_t* preset)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
2007-03-04 16:45:05 +00:00
|
|
|
return fluid_defpreset_get_name((fluid_defpreset_t*) preset->data);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset)
|
|
|
|
{
|
2007-03-04 16:45:05 +00:00
|
|
|
return fluid_defpreset_get_banknum((fluid_defpreset_t*) preset->data);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fluid_defpreset_preset_get_num(fluid_preset_t* preset)
|
|
|
|
{
|
2007-03-04 16:45:05 +00:00
|
|
|
return fluid_defpreset_get_num((fluid_defpreset_t*) preset->data);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth,
|
2003-03-11 16:56:45 +00:00
|
|
|
int chan, int key, int vel)
|
|
|
|
{
|
2007-03-04 16:45:05 +00:00
|
|
|
return fluid_defpreset_noteon((fluid_defpreset_t*) preset->data, synth, chan, key, vel);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2012-10-12 08:51:13 +00:00
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* CACHED SAMPLEDATA LOADER
|
|
|
|
*/
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
typedef struct _fluid_cached_sampledata_t {
|
2012-10-12 08:51:13 +00:00
|
|
|
struct _fluid_cached_sampledata_t *next;
|
|
|
|
|
|
|
|
char* filename;
|
|
|
|
time_t modification_time;
|
|
|
|
int num_references;
|
2012-12-08 06:25:21 +00:00
|
|
|
int mlock;
|
2012-10-12 08:51:13 +00:00
|
|
|
|
|
|
|
const short* sampledata;
|
|
|
|
unsigned int samplesize;
|
|
|
|
} fluid_cached_sampledata_t;
|
|
|
|
|
|
|
|
static fluid_cached_sampledata_t* all_cached_sampledata = NULL;
|
|
|
|
static fluid_mutex_t cached_sampledata_mutex = FLUID_MUTEX_INIT;
|
|
|
|
|
|
|
|
static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
|
|
|
|
{
|
|
|
|
#if defined(WIN32) || defined(__OS2__)
|
|
|
|
*modification_time = 0;
|
|
|
|
return FLUID_OK;
|
|
|
|
#else
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
if (stat(filename, &buf) == -1) {
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
*modification_time = buf.st_mtime;
|
|
|
|
return FLUID_OK;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
static int fluid_cached_sampledata_load(char *filename, unsigned int samplepos,
|
|
|
|
unsigned int samplesize, short **sampledata, int try_mlock)
|
2012-10-12 08:51:13 +00:00
|
|
|
{
|
|
|
|
fluid_file fd = NULL;
|
|
|
|
short *loaded_sampledata = NULL;
|
|
|
|
fluid_cached_sampledata_t* cached_sampledata = NULL;
|
|
|
|
time_t modification_time;
|
|
|
|
|
|
|
|
fluid_mutex_lock(cached_sampledata_mutex);
|
|
|
|
|
|
|
|
if (fluid_get_file_modification_time(filename, &modification_time) == FLUID_FAILED) {
|
|
|
|
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
|
|
|
modification_time = 0;
|
|
|
|
}
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
for (cached_sampledata = all_cached_sampledata; cached_sampledata; cached_sampledata = cached_sampledata->next) {
|
|
|
|
if (strcmp(filename, cached_sampledata->filename))
|
|
|
|
continue;
|
|
|
|
if (cached_sampledata->modification_time != modification_time)
|
|
|
|
continue;
|
|
|
|
if (cached_sampledata->samplesize != samplesize) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Cached size of soundfont doesn't match actual size of soundfont (cached: %u. actual: %u)",
|
|
|
|
cached_sampledata->samplesize, samplesize);
|
|
|
|
continue;
|
2012-10-12 08:51:13 +00:00
|
|
|
}
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
if (try_mlock && !cached_sampledata->mlock) {
|
2012-12-08 06:36:53 +00:00
|
|
|
if (fluid_mlock(cached_sampledata->sampledata, samplesize) != 0)
|
2012-12-08 06:25:21 +00:00
|
|
|
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
|
|
|
|
else
|
|
|
|
cached_sampledata->mlock = try_mlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
cached_sampledata->num_references++;
|
|
|
|
loaded_sampledata = (short*) cached_sampledata->sampledata;
|
|
|
|
goto success_exit;
|
2012-10-12 08:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fd = FLUID_FOPEN(filename, "rb");
|
|
|
|
if (fd == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Can't open soundfont file");
|
|
|
|
goto error_exit;
|
|
|
|
}
|
|
|
|
if (FLUID_FSEEK(fd, samplepos, SEEK_SET) == -1) {
|
|
|
|
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 (FLUID_FREAD(loaded_sampledata, 1, samplesize, fd) < samplesize) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Failed to read sample data");
|
|
|
|
goto error_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
FLUID_FCLOSE(fd);
|
|
|
|
fd = NULL;
|
|
|
|
|
2012-12-08 06:25:21 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-10-12 08:51:13 +00:00
|
|
|
/* Lock the memory to disable paging. It's okay if this fails. It
|
|
|
|
probably means that the user doesn't have to required permission. */
|
2012-12-08 06:25:21 +00:00
|
|
|
cached_sampledata->mlock = 0;
|
|
|
|
if (try_mlock) {
|
2012-12-08 06:36:53 +00:00
|
|
|
if (fluid_mlock(loaded_sampledata, samplesize) != 0)
|
2012-12-08 06:25:21 +00:00
|
|
|
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
|
|
|
|
else
|
|
|
|
cached_sampledata->mlock = try_mlock;
|
2012-10-12 08:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 = (char*) FLUID_MALLOC(strlen(filename) + 1);
|
|
|
|
if (cached_sampledata->filename == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
|
|
|
goto error_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(cached_sampledata->filename, "%s", filename);
|
|
|
|
cached_sampledata->modification_time = modification_time;
|
|
|
|
cached_sampledata->num_references = 1;
|
|
|
|
cached_sampledata->sampledata = loaded_sampledata;
|
|
|
|
cached_sampledata->samplesize = samplesize;
|
|
|
|
|
|
|
|
cached_sampledata->next = all_cached_sampledata;
|
|
|
|
all_cached_sampledata = cached_sampledata;
|
|
|
|
|
|
|
|
|
|
|
|
success_exit:
|
|
|
|
fluid_mutex_unlock(cached_sampledata_mutex);
|
|
|
|
*sampledata = loaded_sampledata;
|
|
|
|
return FLUID_OK;
|
|
|
|
|
|
|
|
error_exit:
|
|
|
|
if (fd != NULL) {
|
|
|
|
FLUID_FCLOSE(fd);
|
|
|
|
}
|
|
|
|
if (loaded_sampledata != NULL) {
|
|
|
|
FLUID_FREE(loaded_sampledata);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cached_sampledata != NULL) {
|
|
|
|
if (cached_sampledata->filename != NULL) {
|
|
|
|
FLUID_FREE(cached_sampledata->filename);
|
|
|
|
}
|
|
|
|
FLUID_FREE(cached_sampledata);
|
|
|
|
}
|
|
|
|
|
|
|
|
fluid_mutex_unlock(cached_sampledata_mutex);
|
|
|
|
*sampledata = NULL;
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fluid_cached_sampledata_unload(const short *sampledata)
|
|
|
|
{
|
|
|
|
fluid_cached_sampledata_t* prev = NULL;
|
|
|
|
fluid_cached_sampledata_t* cached_sampledata;
|
|
|
|
|
|
|
|
fluid_mutex_lock(cached_sampledata_mutex);
|
|
|
|
cached_sampledata = all_cached_sampledata;
|
|
|
|
|
|
|
|
while (cached_sampledata != NULL) {
|
|
|
|
if (sampledata == cached_sampledata->sampledata) {
|
|
|
|
|
|
|
|
cached_sampledata->num_references--;
|
|
|
|
|
|
|
|
if (cached_sampledata->num_references == 0) {
|
2012-12-08 06:25:21 +00:00
|
|
|
if (cached_sampledata->mlock)
|
|
|
|
fluid_munlock(cached_sampledata->sampledata, cached_sampledata->samplesize);
|
2012-10-12 08:51:13 +00:00
|
|
|
FLUID_FREE((short*) cached_sampledata->sampledata);
|
|
|
|
FLUID_FREE(cached_sampledata->filename);
|
|
|
|
|
|
|
|
if (prev != NULL) {
|
|
|
|
prev->next = cached_sampledata->next;
|
|
|
|
} else {
|
|
|
|
all_cached_sampledata = cached_sampledata->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
FLUID_FREE(cached_sampledata);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto success_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = cached_sampledata;
|
|
|
|
cached_sampledata = cached_sampledata->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
FLUID_LOG(FLUID_ERR, "Trying to free sampledata not found in cache.");
|
|
|
|
goto error_exit;
|
|
|
|
|
|
|
|
success_exit:
|
|
|
|
fluid_mutex_unlock(cached_sampledata_mutex);
|
|
|
|
return FLUID_OK;
|
|
|
|
|
|
|
|
error_exit:
|
|
|
|
fluid_mutex_unlock(cached_sampledata_mutex);
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* SFONT
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_fluid_defsfont
|
|
|
|
*/
|
2012-12-08 06:25:21 +00:00
|
|
|
fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
fluid_defsfont_t* sfont;
|
2013-05-12 10:21:43 +00:00
|
|
|
int i;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
sfont = FLUID_NEW(fluid_defsfont_t);
|
|
|
|
if (sfont == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfont->filename = NULL;
|
|
|
|
sfont->samplepos = 0;
|
|
|
|
sfont->samplesize = 0;
|
|
|
|
sfont->sample = NULL;
|
|
|
|
sfont->sampledata = NULL;
|
|
|
|
sfont->preset = NULL;
|
2012-12-08 06:25:21 +00:00
|
|
|
fluid_settings_getint(settings, "synth.lock-memory", &sfont->mlock);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
2013-05-12 10:21:43 +00:00
|
|
|
/* Initialise preset cache, so we don't have to call malloc on program changes.
|
|
|
|
Usually, we have at most one preset per channel plus one temporarily used,
|
|
|
|
so optimise for that case. */
|
|
|
|
fluid_settings_getint(settings, "synth.midi-channels", &sfont->preset_stack_capacity);
|
|
|
|
sfont->preset_stack_capacity++;
|
|
|
|
sfont->preset_stack_size = 0;
|
|
|
|
sfont->preset_stack = FLUID_ARRAY(fluid_preset_t*, sfont->preset_stack_capacity);
|
|
|
|
if (!sfont->preset_stack) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
FLUID_FREE(sfont);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < sfont->preset_stack_capacity; i++) {
|
|
|
|
sfont->preset_stack[i] = FLUID_NEW(fluid_preset_t);
|
|
|
|
if (!sfont->preset_stack[i]) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
delete_fluid_defsfont(sfont);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
sfont->preset_stack_size++;
|
|
|
|
}
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
return sfont;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delete_fluid_defsfont
|
|
|
|
*/
|
|
|
|
int delete_fluid_defsfont(fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_list_t *list;
|
|
|
|
fluid_defpreset_t* preset;
|
|
|
|
fluid_sample_t* sample;
|
|
|
|
|
|
|
|
/* Check that no samples are currently used */
|
|
|
|
for (list = sfont->sample; list; list = fluid_list_next(list)) {
|
|
|
|
sample = (fluid_sample_t*) fluid_list_get(list);
|
|
|
|
if (fluid_sample_refcount(sample) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sfont->filename != NULL) {
|
|
|
|
FLUID_FREE(sfont->filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (list = sfont->sample; list; list = fluid_list_next(list)) {
|
|
|
|
delete_fluid_sample((fluid_sample_t*) fluid_list_get(list));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sfont->sample) {
|
|
|
|
delete_fluid_list(sfont->sample);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sfont->sampledata != NULL) {
|
2012-10-12 08:51:13 +00:00
|
|
|
fluid_cached_sampledata_unload(sfont->sampledata);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
2013-05-12 10:21:43 +00:00
|
|
|
while (sfont->preset_stack_size > 0)
|
|
|
|
FLUID_FREE(sfont->preset_stack[--sfont->preset_stack_size]);
|
|
|
|
FLUID_FREE(sfont->preset_stack);
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
preset = sfont->preset;
|
|
|
|
while (preset != NULL) {
|
|
|
|
sfont->preset = preset->next;
|
|
|
|
delete_fluid_defpreset(preset);
|
|
|
|
preset = sfont->preset;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_FREE(sfont);
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defsfont_get_name
|
|
|
|
*/
|
2017-09-20 10:55:55 +00:00
|
|
|
const char* fluid_defsfont_get_name(fluid_defsfont_t* sfont)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
return sfont->filename;
|
|
|
|
}
|
|
|
|
|
2009-01-29 23:05:59 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/*
|
|
|
|
* fluid_defsfont_load
|
|
|
|
*/
|
|
|
|
int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file)
|
|
|
|
{
|
|
|
|
SFData* sfdata;
|
|
|
|
fluid_list_t *p;
|
|
|
|
SFPreset* sfpreset;
|
|
|
|
SFSample* sfsample;
|
|
|
|
fluid_sample_t* sample;
|
2015-05-19 05:20:34 +00:00
|
|
|
fluid_defpreset_t* preset = NULL;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
sfont->filename = FLUID_MALLOC(1 + FLUID_STRLEN(file));
|
|
|
|
if (sfont->filename == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
FLUID_STRCPY(sfont->filename, file);
|
|
|
|
|
|
|
|
/* The actual loading is done in the sfont and sffile files */
|
|
|
|
sfdata = sfload_file(file);
|
|
|
|
if (sfdata == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file");
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep track of the position and size of the sample data because
|
|
|
|
it's loaded separately (and might be unoaded/reloaded in future) */
|
|
|
|
sfont->samplepos = sfdata->samplepos;
|
|
|
|
sfont->samplesize = sfdata->samplesize;
|
|
|
|
|
|
|
|
/* load sample data in one block */
|
2006-12-10 16:02:04 +00:00
|
|
|
if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK)
|
|
|
|
goto err_exit;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/* Create all the sample headers */
|
|
|
|
p = sfdata->sample;
|
|
|
|
while (p != NULL) {
|
|
|
|
sfsample = (SFSample *) p->data;
|
2006-12-10 16:02:04 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
sample = new_fluid_sample();
|
2006-12-10 16:02:04 +00:00
|
|
|
if (sample == NULL) goto err_exit;
|
|
|
|
|
|
|
|
if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK)
|
|
|
|
goto err_exit;
|
|
|
|
|
2011-02-27 20:35:24 +00:00
|
|
|
/* Store reference to FluidSynth sample in SFSample for later IZone fixups */
|
|
|
|
sfsample->fluid_sample = sample;
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defsfont_add_sample(sfont, sample);
|
2003-06-28 21:09:44 +00:00
|
|
|
fluid_voice_optimize_sample(sample);
|
2003-03-11 16:56:45 +00:00
|
|
|
p = fluid_list_next(p);
|
|
|
|
}
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
/* Load all the presets */
|
2003-03-11 16:56:45 +00:00
|
|
|
p = sfdata->preset;
|
|
|
|
while (p != NULL) {
|
|
|
|
sfpreset = (SFPreset *) p->data;
|
|
|
|
preset = new_fluid_defpreset(sfont);
|
2006-12-10 16:02:04 +00:00
|
|
|
if (preset == NULL) goto err_exit;
|
|
|
|
|
|
|
|
if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK)
|
|
|
|
goto err_exit;
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defsfont_add_preset(sfont, preset);
|
|
|
|
p = fluid_list_next(p);
|
|
|
|
}
|
2006-12-10 16:02:04 +00:00
|
|
|
sfont_close (sfdata);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
return FLUID_OK;
|
2006-12-10 16:02:04 +00:00
|
|
|
|
|
|
|
err_exit:
|
|
|
|
sfont_close (sfdata);
|
2015-05-19 05:20:34 +00:00
|
|
|
if (preset != NULL)
|
|
|
|
delete_fluid_defpreset(preset);
|
2006-12-10 16:02:04 +00:00
|
|
|
return FLUID_FAILED;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* fluid_defsfont_add_sample
|
|
|
|
*
|
|
|
|
* Add a sample to the SoundFont
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
sfont->sample = fluid_list_append(sfont->sample, sample);
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fluid_defsfont_add_preset
|
|
|
|
*
|
|
|
|
* Add a preset to the SoundFont
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
fluid_defpreset_t *cur, *prev;
|
|
|
|
if (sfont->preset == NULL) {
|
|
|
|
preset->next = NULL;
|
|
|
|
sfont->preset = preset;
|
|
|
|
} else {
|
|
|
|
/* sort them as we go along. very basic sorting trick. */
|
|
|
|
cur = sfont->preset;
|
|
|
|
prev = NULL;
|
|
|
|
while (cur != NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
if ((preset->bank < cur->bank)
|
2003-03-11 16:56:45 +00:00
|
|
|
|| ((preset->bank == cur->bank) && (preset->num < cur->num))) {
|
|
|
|
if (prev == NULL) {
|
|
|
|
preset->next = cur;
|
|
|
|
sfont->preset = preset;
|
|
|
|
} else {
|
|
|
|
preset->next = cur;
|
|
|
|
prev->next = preset;
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
preset->next = NULL;
|
|
|
|
prev->next = preset;
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defsfont_load_sampledata
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
|
|
|
fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
2012-12-08 06:25:21 +00:00
|
|
|
return fluid_cached_sampledata_load(sfont->filename, sfont->samplepos,
|
|
|
|
sfont->samplesize, &sfont->sampledata, sfont->mlock);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defsfont_get_preset
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int num)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
fluid_defpreset_t* preset = sfont->preset;
|
|
|
|
while (preset != NULL) {
|
|
|
|
if ((preset->bank == bank) && ((preset->num == num))) {
|
|
|
|
return preset;
|
|
|
|
}
|
|
|
|
preset = preset->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defsfont_iteration_start
|
|
|
|
*/
|
|
|
|
void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
sfont->iter_cur = sfont->preset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defsfont_iteration_next
|
|
|
|
*/
|
|
|
|
int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset)
|
|
|
|
{
|
|
|
|
if (sfont->iter_cur == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
preset->data = (void*) sfont->iter_cur;
|
|
|
|
sfont->iter_cur = fluid_defpreset_next(sfont->iter_cur);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* PRESET
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_fluid_defpreset
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_defpreset_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
new_fluid_defpreset(fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_defpreset_t* preset = FLUID_NEW(fluid_defpreset_t);
|
|
|
|
if (preset == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
preset->next = NULL;
|
|
|
|
preset->sfont = sfont;
|
|
|
|
preset->name[0] = 0;
|
|
|
|
preset->bank = 0;
|
|
|
|
preset->num = 0;
|
|
|
|
preset->global_zone = NULL;
|
|
|
|
preset->zone = NULL;
|
|
|
|
return preset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delete_fluid_defpreset
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
delete_fluid_defpreset(fluid_defpreset_t* preset)
|
|
|
|
{
|
|
|
|
int err = FLUID_OK;
|
|
|
|
fluid_preset_zone_t* zone;
|
|
|
|
if (preset->global_zone != NULL) {
|
|
|
|
if (delete_fluid_preset_zone(preset->global_zone) != FLUID_OK) {
|
|
|
|
err = FLUID_FAILED;
|
|
|
|
}
|
|
|
|
preset->global_zone = NULL;
|
|
|
|
}
|
|
|
|
zone = preset->zone;
|
|
|
|
while (zone != NULL) {
|
|
|
|
preset->zone = zone->next;
|
|
|
|
if (delete_fluid_preset_zone(zone) != FLUID_OK) {
|
|
|
|
err = FLUID_FAILED;
|
|
|
|
}
|
|
|
|
zone = preset->zone;
|
|
|
|
}
|
|
|
|
FLUID_FREE(preset);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_get_banknum(fluid_defpreset_t* preset)
|
|
|
|
{
|
|
|
|
return preset->bank;
|
|
|
|
}
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_get_num(fluid_defpreset_t* preset)
|
|
|
|
{
|
|
|
|
return preset->num;
|
|
|
|
}
|
|
|
|
|
2017-09-20 10:55:55 +00:00
|
|
|
const char*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_get_name(fluid_defpreset_t* preset)
|
|
|
|
{
|
|
|
|
return preset->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_next
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_defpreset_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_next(fluid_defpreset_t* preset)
|
|
|
|
{
|
|
|
|
return preset->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_noteon
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
|
|
|
fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
fluid_preset_zone_t *preset_zone, *global_preset_zone;
|
|
|
|
fluid_inst_t* inst;
|
2012-09-23 09:08:45 +00:00
|
|
|
fluid_inst_zone_t *inst_zone, *global_inst_zone;
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_sample_t* sample;
|
|
|
|
fluid_voice_t* voice;
|
|
|
|
fluid_mod_t * mod;
|
|
|
|
fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
|
|
|
|
int mod_list_count;
|
|
|
|
int i;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
global_preset_zone = fluid_defpreset_get_global_zone(preset);
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* run thru all the zones of this preset */
|
|
|
|
preset_zone = fluid_defpreset_get_zone(preset);
|
|
|
|
while (preset_zone != NULL) {
|
|
|
|
|
|
|
|
/* check if the note falls into the key and velocity range of this
|
|
|
|
preset */
|
|
|
|
if (fluid_preset_zone_inside_range(preset_zone, key, vel)) {
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
inst = fluid_preset_zone_get_inst(preset_zone);
|
|
|
|
global_inst_zone = fluid_inst_get_global_zone(inst);
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* run thru all the zones of this instrument */
|
|
|
|
inst_zone = fluid_inst_get_zone(inst);
|
2003-04-28 23:01:44 +00:00
|
|
|
while (inst_zone != NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* make sure this instrument zone has a valid sample */
|
|
|
|
sample = fluid_inst_zone_get_sample(inst_zone);
|
2013-07-16 10:46:55 +00:00
|
|
|
if ((sample == NULL) || fluid_sample_in_rom(sample)) {
|
2003-03-11 16:56:45 +00:00
|
|
|
inst_zone = fluid_inst_zone_next(inst_zone);
|
|
|
|
continue;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* check if the note falls into the key and velocity range of this
|
|
|
|
instrument */
|
|
|
|
|
|
|
|
if (fluid_inst_zone_inside_range(inst_zone, key, vel) && (sample != NULL)) {
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* this is a good zone. allocate a new synthesis process and
|
|
|
|
initialize it */
|
|
|
|
|
|
|
|
voice = fluid_synth_alloc_voice(synth, sample, chan, key, vel);
|
|
|
|
if (voice == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
return FLUID_FAILED;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Instrument level, generators */
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
for (i = 0; i < GEN_LAST; i++) {
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
/* SF 2.01 section 9.4 'bullet' 4:
|
2003-03-11 16:56:45 +00:00
|
|
|
*
|
|
|
|
* A generator in a local instrument zone supersedes a
|
|
|
|
* global instrument zone generator. Both cases supersede
|
|
|
|
* the default generator -> voice_gen_set */
|
|
|
|
|
|
|
|
if (inst_zone->gen[i].flags){
|
|
|
|
fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);
|
|
|
|
|
2004-03-03 11:14:25 +00:00
|
|
|
} else if ((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags)) {
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
/* The generator has not been defined in this instrument.
|
|
|
|
* Do nothing, leave it at the default.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* for all generators */
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* global instrument zone, modulators: Put them all into a
|
|
|
|
* list. */
|
|
|
|
|
|
|
|
mod_list_count = 0;
|
|
|
|
|
|
|
|
if (global_inst_zone){
|
|
|
|
mod = global_inst_zone->mod;
|
|
|
|
while (mod){
|
|
|
|
mod_list[mod_list_count++] = mod;
|
|
|
|
mod = mod->next;
|
|
|
|
}
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* local instrument zone, modulators.
|
|
|
|
* Replace modulators with the same definition in the list:
|
|
|
|
* SF 2.01 page 69, 'bullet' 8
|
|
|
|
*/
|
|
|
|
mod = inst_zone->mod;
|
|
|
|
|
|
|
|
while (mod){
|
|
|
|
|
|
|
|
/* 'Identical' modulators will be deleted by setting their
|
|
|
|
* list entry to NULL. The list length is known, NULL
|
|
|
|
* entries will be ignored later. SF2.01 section 9.5.1
|
|
|
|
* page 69, 'bullet' 3 defines 'identical'. */
|
|
|
|
|
|
|
|
for (i = 0; i < mod_list_count; i++){
|
2008-09-15 04:17:24 +00:00
|
|
|
if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){
|
2003-03-11 16:56:45 +00:00
|
|
|
mod_list[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Finally add the new modulator to to the list. */
|
|
|
|
mod_list[mod_list_count++] = mod;
|
|
|
|
mod = mod->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add instrument modulators (global / local) to the voice. */
|
|
|
|
for (i = 0; i < mod_list_count; i++){
|
|
|
|
|
|
|
|
mod = mod_list[i];
|
|
|
|
|
|
|
|
if (mod != NULL){ /* disabled modulators CANNOT be skipped. */
|
|
|
|
|
|
|
|
/* Instrument modulators -supersede- existing (default)
|
|
|
|
* modulators. SF 2.01 page 69, 'bullet' 6 */
|
|
|
|
fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Preset level, generators */
|
|
|
|
|
|
|
|
for (i = 0; i < GEN_LAST; i++) {
|
|
|
|
|
|
|
|
/* SF 2.01 section 8.5 page 58: If some generators are
|
|
|
|
* encountered at preset level, they should be ignored */
|
2007-03-04 16:45:05 +00:00
|
|
|
if ((i != GEN_STARTADDROFS)
|
|
|
|
&& (i != GEN_ENDADDROFS)
|
|
|
|
&& (i != GEN_STARTLOOPADDROFS)
|
|
|
|
&& (i != GEN_ENDLOOPADDROFS)
|
|
|
|
&& (i != GEN_STARTADDRCOARSEOFS)
|
|
|
|
&& (i != GEN_ENDADDRCOARSEOFS)
|
2003-03-11 16:56:45 +00:00
|
|
|
&& (i != GEN_STARTLOOPADDRCOARSEOFS)
|
|
|
|
&& (i != GEN_KEYNUM)
|
|
|
|
&& (i != GEN_VELOCITY)
|
|
|
|
&& (i != GEN_ENDLOOPADDRCOARSEOFS)
|
|
|
|
&& (i != GEN_SAMPLEMODE)
|
|
|
|
&& (i != GEN_EXCLUSIVECLASS)
|
|
|
|
&& (i != GEN_OVERRIDEROOTKEY)) {
|
|
|
|
|
|
|
|
/* SF 2.01 section 9.4 'bullet' 9: A generator in a
|
|
|
|
* local preset zone supersedes a global preset zone
|
|
|
|
* generator. The effect is -added- to the destination
|
|
|
|
* summing node -> voice_gen_incr */
|
|
|
|
|
2004-03-03 11:14:25 +00:00
|
|
|
if (preset_zone->gen[i].flags) {
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);
|
2004-03-03 11:14:25 +00:00
|
|
|
} else if ((global_preset_zone != NULL) && global_preset_zone->gen[i].flags) {
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val);
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
|
|
|
/* The generator has not been defined in this preset
|
|
|
|
* Do nothing, leave it unchanged.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
} /* if available at preset level */
|
|
|
|
} /* for all generators */
|
2007-03-04 16:45:05 +00:00
|
|
|
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Global preset zone, modulators: put them all into a
|
|
|
|
* list. */
|
|
|
|
mod_list_count = 0;
|
|
|
|
if (global_preset_zone){
|
|
|
|
mod = global_preset_zone->mod;
|
|
|
|
while (mod){
|
|
|
|
mod_list[mod_list_count++] = mod;
|
|
|
|
mod = mod->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process the modulators of the local preset zone. Kick
|
|
|
|
* out all identical modulators from the global preset zone
|
|
|
|
* (SF 2.01 page 69, second-last bullet) */
|
|
|
|
|
|
|
|
mod = preset_zone->mod;
|
|
|
|
while (mod){
|
|
|
|
for (i = 0; i < mod_list_count; i++){
|
2008-09-15 04:17:24 +00:00
|
|
|
if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){
|
2003-03-11 16:56:45 +00:00
|
|
|
mod_list[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Finally add the new modulator to the list. */
|
|
|
|
mod_list[mod_list_count++] = mod;
|
|
|
|
mod = mod->next;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Add preset modulators (global / local) to the voice. */
|
|
|
|
for (i = 0; i < mod_list_count; i++){
|
|
|
|
mod = mod_list[i];
|
|
|
|
if ((mod != NULL) && (mod->amount != 0)) { /* disabled modulators can be skipped. */
|
|
|
|
|
|
|
|
/* Preset modulators -add- to existing instrument /
|
|
|
|
* default modulators. SF2.01 page 70 first bullet on
|
|
|
|
* page */
|
|
|
|
fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD);
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
}
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/* add the synthesis process to the synthesis loop. */
|
|
|
|
fluid_synth_start_voice(synth, voice);
|
|
|
|
|
|
|
|
/* Store the ID of the first voice that was created by this noteon event.
|
|
|
|
* Exclusive class may only terminate older voices.
|
|
|
|
* That avoids killing voices, which have just been created.
|
|
|
|
* (a noteon event can create several voice processes with the same exclusive
|
|
|
|
* class - for example when using stereo samples)
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
inst_zone = fluid_inst_zone_next(inst_zone);
|
|
|
|
}
|
2003-04-28 23:01:44 +00:00
|
|
|
}
|
2003-03-11 16:56:45 +00:00
|
|
|
preset_zone = fluid_preset_zone_next(preset_zone);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_set_global_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone)
|
|
|
|
{
|
|
|
|
preset->global_zone = zone;
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_import_sfont
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
|
|
|
fluid_defpreset_import_sfont(fluid_defpreset_t* preset,
|
|
|
|
SFPreset* sfpreset,
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_list_t *p;
|
|
|
|
SFZone* sfzone;
|
|
|
|
fluid_preset_zone_t* zone;
|
|
|
|
int count;
|
|
|
|
char zone_name[256];
|
2017-07-08 18:52:10 +00:00
|
|
|
if (FLUID_STRLEN(sfpreset->name) > 0) {
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_STRCPY(preset->name, sfpreset->name);
|
|
|
|
} else {
|
2017-10-06 18:52:07 +00:00
|
|
|
FLUID_SNPRINTF(preset->name, sizeof(preset->name), "Bank%d,Pre%d", sfpreset->bank, sfpreset->prenum);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
preset->bank = sfpreset->bank;
|
|
|
|
preset->num = sfpreset->prenum;
|
|
|
|
p = sfpreset->zone;
|
|
|
|
count = 0;
|
|
|
|
while (p != NULL) {
|
|
|
|
sfzone = (SFZone *) p->data;
|
2017-10-06 18:52:07 +00:00
|
|
|
FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", preset->name, count);
|
2003-03-11 16:56:45 +00:00
|
|
|
zone = new_fluid_preset_zone(zone_name);
|
|
|
|
if (zone == NULL) {
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
if (fluid_preset_zone_import_sfont(zone, sfzone, sfont) != FLUID_OK) {
|
2013-07-17 07:56:21 +00:00
|
|
|
delete_fluid_preset_zone(zone);
|
2003-03-11 16:56:45 +00:00
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
if ((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL)) {
|
|
|
|
fluid_defpreset_set_global_zone(preset, zone);
|
|
|
|
} else if (fluid_defpreset_add_zone(preset, zone) != FLUID_OK) {
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
p = fluid_list_next(p);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_add_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone)
|
|
|
|
{
|
|
|
|
if (preset->zone == NULL) {
|
|
|
|
zone->next = NULL;
|
|
|
|
preset->zone = zone;
|
|
|
|
} else {
|
|
|
|
zone->next = preset->zone;
|
|
|
|
preset->zone = zone;
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_get_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_preset_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_get_zone(fluid_defpreset_t* preset)
|
|
|
|
{
|
|
|
|
return preset->zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_defpreset_get_global_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_preset_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_defpreset_get_global_zone(fluid_defpreset_t* preset)
|
|
|
|
{
|
2007-03-04 16:45:05 +00:00
|
|
|
return preset->global_zone;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_preset_zone_next
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_preset_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_preset_zone_next(fluid_preset_zone_t* preset)
|
|
|
|
{
|
|
|
|
return preset->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_fluid_preset_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_preset_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
new_fluid_preset_zone(char *name)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
fluid_preset_zone_t* zone = NULL;
|
|
|
|
zone = FLUID_NEW(fluid_preset_zone_t);
|
|
|
|
if (zone == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
zone->next = NULL;
|
|
|
|
size = 1 + FLUID_STRLEN(name);
|
|
|
|
zone->name = FLUID_MALLOC(size);
|
|
|
|
if (zone->name == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_FREE(zone);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
FLUID_STRCPY(zone->name, name);
|
|
|
|
zone->inst = NULL;
|
|
|
|
zone->keylo = 0;
|
|
|
|
zone->keyhi = 128;
|
|
|
|
zone->vello = 0;
|
|
|
|
zone->velhi = 128;
|
|
|
|
|
|
|
|
/* Flag all generators as unused (default, they will be set when they are found
|
|
|
|
* in the sound font).
|
|
|
|
* This also sets the generator values to default, but that is of no concern here.*/
|
|
|
|
fluid_gen_set_default_values(&zone->gen[0]);
|
|
|
|
zone->mod = NULL; /* list of modulators */
|
|
|
|
return zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* PRESET_ZONE
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delete_fluid_preset_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
delete_fluid_preset_zone(fluid_preset_zone_t* zone)
|
|
|
|
{
|
2006-11-23 18:49:36 +00:00
|
|
|
fluid_mod_t *mod, *tmp;
|
|
|
|
|
|
|
|
mod = zone->mod;
|
|
|
|
while (mod) /* delete the modulators */
|
|
|
|
{
|
|
|
|
tmp = mod;
|
|
|
|
mod = mod->next;
|
|
|
|
fluid_mod_delete (tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zone->name) FLUID_FREE (zone->name);
|
|
|
|
if (zone->inst) delete_fluid_inst (zone->inst);
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_FREE(zone);
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_preset_zone_import_sfont
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_list_t *r;
|
|
|
|
SFGen* sfgen;
|
|
|
|
int count;
|
|
|
|
for (count = 0, r = sfzone->gen; r != NULL; count++) {
|
|
|
|
sfgen = (SFGen *) r->data;
|
|
|
|
switch (sfgen->id) {
|
2007-03-04 16:45:05 +00:00
|
|
|
case GEN_KEYRANGE:
|
2003-03-11 16:56:45 +00:00
|
|
|
zone->keylo = (int) sfgen->amount.range.lo;
|
|
|
|
zone->keyhi = (int) sfgen->amount.range.hi;
|
|
|
|
break;
|
2007-03-04 16:45:05 +00:00
|
|
|
case GEN_VELRANGE:
|
2003-03-11 16:56:45 +00:00
|
|
|
zone->vello = (int) sfgen->amount.range.lo;
|
|
|
|
zone->velhi = (int) sfgen->amount.range.hi;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* FIXME: some generators have an unsigne word amount value but i don't know which ones */
|
|
|
|
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
|
|
|
zone->gen[sfgen->id].flags = GEN_SET;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r = fluid_list_next(r);
|
|
|
|
}
|
|
|
|
if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) {
|
|
|
|
zone->inst = (fluid_inst_t*) new_fluid_inst();
|
|
|
|
if (zone->inst == NULL) {
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
if (fluid_inst_import_sfont(zone->inst, (SFInst *) sfzone->instsamp->data, sfont) != FLUID_OK) {
|
2007-03-04 16:45:05 +00:00
|
|
|
return FLUID_FAILED;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
}
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/* Import the modulators (only SF2.1 and higher) */
|
|
|
|
for (count = 0, r = sfzone->mod; r != NULL; count++) {
|
|
|
|
|
|
|
|
SFMod* mod_src = (SFMod *)r->data;
|
|
|
|
fluid_mod_t * mod_dest = fluid_mod_new();
|
|
|
|
int type;
|
|
|
|
|
|
|
|
if (mod_dest == NULL){
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
|
|
|
|
|
|
|
|
/* *** Amount *** */
|
|
|
|
mod_dest->amount = mod_src->amount;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Source *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
|
2003-03-11 16:56:45 +00:00
|
|
|
mod_dest->flags1 = 0;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
|
|
|
if (mod_src->src & (1<<7)){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_CC;
|
|
|
|
} else {
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_GC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
|
|
|
if (mod_src->src & (1<<8)){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_NEGATIVE;
|
|
|
|
} else {
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_POSITIVE;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
|
|
|
if (mod_src->src & (1<<9)){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_BIPOLAR;
|
|
|
|
} else {
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_UNIPOLAR;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* modulator source types: SF2.01 section 8.2.1 page 52 */
|
|
|
|
type=(mod_src->src) >> 10;
|
|
|
|
type &= 63; /* type is a 6-bit value */
|
|
|
|
if (type == 0){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_LINEAR;
|
|
|
|
} else if (type == 1){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_CONCAVE;
|
|
|
|
} else if (type == 2){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_CONVEX;
|
|
|
|
} else if (type == 3){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_SWITCH;
|
|
|
|
} else {
|
2007-03-04 16:45:05 +00:00
|
|
|
/* This shouldn't happen - unknown type!
|
2003-03-11 16:56:45 +00:00
|
|
|
* Deactivate the modulator by setting the amount to 0. */
|
|
|
|
mod_dest->amount=0;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Dest *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
mod_dest->dest = mod_src->dest; /* index of controlled generator */
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Amount source *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, p.50 */
|
2003-03-11 16:56:45 +00:00
|
|
|
mod_dest->flags2 = 0;
|
2005-06-12 01:19:37 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
|
|
|
if (mod_src->amtsrc & (1<<7)){
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_CC;
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_GC;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
|
|
|
if (mod_src->amtsrc & (1<<8)){
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_POSITIVE;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
|
|
|
if (mod_src->amtsrc & (1<<9)){
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* modulator source types: SF2.01 section 8.2.1 page 52 */
|
|
|
|
type = (mod_src->amtsrc) >> 10;
|
|
|
|
type &= 63; /* type is a 6-bit value */
|
|
|
|
if (type == 0){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_LINEAR;
|
|
|
|
} else if (type == 1){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_CONCAVE;
|
|
|
|
} else if (type == 2){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_CONVEX;
|
|
|
|
} else if (type == 3){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_SWITCH;
|
|
|
|
} else {
|
2007-03-04 16:45:05 +00:00
|
|
|
/* This shouldn't happen - unknown type!
|
2003-03-11 16:56:45 +00:00
|
|
|
* Deactivate the modulator by setting the amount to 0. */
|
|
|
|
mod_dest->amount=0;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Transform *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
/* SF2.01 only uses the 'linear' transform (0).
|
2003-03-11 16:56:45 +00:00
|
|
|
* Deactivate the modulator by setting the amount to 0 in any other case.
|
|
|
|
*/
|
|
|
|
if (mod_src->trans !=0){
|
|
|
|
mod_dest->amount = 0;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Store the new modulator in the zone The order of modulators
|
|
|
|
* will make a difference, at least in an instrument context: The
|
|
|
|
* second modulator overwrites the first one, if they only differ
|
|
|
|
* in amount. */
|
|
|
|
if (count == 0){
|
|
|
|
zone->mod = mod_dest;
|
|
|
|
} else {
|
|
|
|
fluid_mod_t * last_mod = zone->mod;
|
|
|
|
|
|
|
|
/* Find the end of the list */
|
|
|
|
while (last_mod->next != NULL){
|
|
|
|
last_mod=last_mod->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_mod->next = mod_dest;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
r = fluid_list_next(r);
|
|
|
|
} /* foreach modulator */
|
|
|
|
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_preset_zone_get_inst
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_inst_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_preset_zone_get_inst(fluid_preset_zone_t* zone)
|
|
|
|
{
|
|
|
|
return zone->inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_preset_zone_inside_range
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel)
|
|
|
|
{
|
|
|
|
return ((zone->keylo <= key) &&
|
|
|
|
(zone->keyhi >= key) &&
|
|
|
|
(zone->vello <= vel) &&
|
|
|
|
(zone->velhi >= vel));
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* INST
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_fluid_inst
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_inst_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
new_fluid_inst()
|
|
|
|
{
|
|
|
|
fluid_inst_t* inst = FLUID_NEW(fluid_inst_t);
|
|
|
|
if (inst == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
inst->name[0] = 0;
|
|
|
|
inst->global_zone = NULL;
|
|
|
|
inst->zone = NULL;
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delete_fluid_inst
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
delete_fluid_inst(fluid_inst_t* inst)
|
|
|
|
{
|
|
|
|
fluid_inst_zone_t* zone;
|
|
|
|
int err = FLUID_OK;
|
|
|
|
if (inst->global_zone != NULL) {
|
|
|
|
if (delete_fluid_inst_zone(inst->global_zone) != FLUID_OK) {
|
|
|
|
err = FLUID_FAILED;
|
|
|
|
}
|
|
|
|
inst->global_zone = NULL;
|
|
|
|
}
|
|
|
|
zone = inst->zone;
|
|
|
|
while (zone != NULL) {
|
|
|
|
inst->zone = zone->next;
|
|
|
|
if (delete_fluid_inst_zone(zone) != FLUID_OK) {
|
|
|
|
err = FLUID_FAILED;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
zone = inst->zone;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
FLUID_FREE(inst);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_set_global_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone)
|
|
|
|
{
|
|
|
|
inst->global_zone = zone;
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_import_sfont
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_list_t *p;
|
|
|
|
SFZone* sfzone;
|
|
|
|
fluid_inst_zone_t* zone;
|
|
|
|
char zone_name[256];
|
|
|
|
int count;
|
|
|
|
|
|
|
|
p = sfinst->zone;
|
2017-07-08 18:52:10 +00:00
|
|
|
if (FLUID_STRLEN(sfinst->name) > 0) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_STRCPY(inst->name, sfinst->name);
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
|
|
|
FLUID_STRCPY(inst->name, "<untitled>");
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
while (p != NULL) {
|
|
|
|
|
|
|
|
sfzone = (SFZone *) p->data;
|
2017-10-06 18:52:07 +00:00
|
|
|
FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", inst->name, count);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
zone = new_fluid_inst_zone(zone_name);
|
|
|
|
if (zone == NULL) {
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fluid_inst_zone_import_sfont(zone, sfzone, sfont) != FLUID_OK) {
|
2013-07-17 07:56:21 +00:00
|
|
|
delete_fluid_inst_zone(zone);
|
2003-03-11 16:56:45 +00:00
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((count == 0) && (fluid_inst_zone_get_sample(zone) == NULL)) {
|
|
|
|
fluid_inst_set_global_zone(inst, zone);
|
|
|
|
|
|
|
|
} else if (fluid_inst_add_zone(inst, zone) != FLUID_OK) {
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = fluid_list_next(p);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_add_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone)
|
|
|
|
{
|
|
|
|
if (inst->zone == NULL) {
|
|
|
|
zone->next = NULL;
|
|
|
|
inst->zone = zone;
|
|
|
|
} else {
|
|
|
|
zone->next = inst->zone;
|
|
|
|
inst->zone = zone;
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_get_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_inst_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_get_zone(fluid_inst_t* inst)
|
|
|
|
{
|
|
|
|
return inst->zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_get_global_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_inst_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_get_global_zone(fluid_inst_t* inst)
|
|
|
|
{
|
2007-03-04 16:45:05 +00:00
|
|
|
return inst->global_zone;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* INST_ZONE
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_fluid_inst_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_inst_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
new_fluid_inst_zone(char* name)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
fluid_inst_zone_t* zone = NULL;
|
|
|
|
zone = FLUID_NEW(fluid_inst_zone_t);
|
|
|
|
if (zone == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
zone->next = NULL;
|
|
|
|
size = 1 + FLUID_STRLEN(name);
|
|
|
|
zone->name = FLUID_MALLOC(size);
|
|
|
|
if (zone->name == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_FREE(zone);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
FLUID_STRCPY(zone->name, name);
|
|
|
|
zone->sample = NULL;
|
2003-04-28 23:01:44 +00:00
|
|
|
zone->keylo = 0;
|
2003-03-11 16:56:45 +00:00
|
|
|
zone->keyhi = 128;
|
|
|
|
zone->vello = 0;
|
|
|
|
zone->velhi = 128;
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
/* Flag the generators as unused.
|
2003-03-11 16:56:45 +00:00
|
|
|
* This also sets the generator values to default, but they will be overwritten anyway, if used.*/
|
|
|
|
fluid_gen_set_default_values(&zone->gen[0]);
|
|
|
|
zone->mod=NULL; /* list of modulators */
|
|
|
|
return zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delete_fluid_inst_zone
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
delete_fluid_inst_zone(fluid_inst_zone_t* zone)
|
|
|
|
{
|
2006-11-23 18:49:36 +00:00
|
|
|
fluid_mod_t *mod, *tmp;
|
|
|
|
|
|
|
|
mod = zone->mod;
|
|
|
|
while (mod) /* delete the modulators */
|
|
|
|
{
|
|
|
|
tmp = mod;
|
|
|
|
mod = mod->next;
|
|
|
|
fluid_mod_delete (tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zone->name) FLUID_FREE (zone->name);
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_FREE(zone);
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_zone_next
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_inst_zone_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_zone_next(fluid_inst_zone_t* zone)
|
|
|
|
{
|
|
|
|
return zone->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_zone_import_sfont
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
fluid_list_t *r;
|
|
|
|
SFGen* sfgen;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
for (count = 0, r = sfzone->gen; r != NULL; count++) {
|
|
|
|
sfgen = (SFGen *) r->data;
|
|
|
|
switch (sfgen->id) {
|
2007-03-04 16:45:05 +00:00
|
|
|
case GEN_KEYRANGE:
|
2003-03-11 16:56:45 +00:00
|
|
|
zone->keylo = (int) sfgen->amount.range.lo;
|
|
|
|
zone->keyhi = (int) sfgen->amount.range.hi;
|
|
|
|
break;
|
2007-03-04 16:45:05 +00:00
|
|
|
case GEN_VELRANGE:
|
2003-03-11 16:56:45 +00:00
|
|
|
zone->vello = (int) sfgen->amount.range.lo;
|
|
|
|
zone->velhi = (int) sfgen->amount.range.hi;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* FIXME: some generators have an unsigned word amount value but
|
|
|
|
i don't know which ones */
|
|
|
|
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
|
|
|
zone->gen[sfgen->id].flags = GEN_SET;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r = fluid_list_next(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME */
|
|
|
|
/* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */
|
|
|
|
/* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */
|
|
|
|
/* } */
|
|
|
|
|
2011-02-27 20:35:24 +00:00
|
|
|
/* fixup sample pointer */
|
|
|
|
if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
|
|
|
|
zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/* Import the modulators (only SF2.1 and higher) */
|
|
|
|
for (count = 0, r = sfzone->mod; r != NULL; count++) {
|
|
|
|
SFMod* mod_src = (SFMod *) r->data;
|
|
|
|
int type;
|
|
|
|
fluid_mod_t* mod_dest;
|
|
|
|
|
|
|
|
mod_dest = fluid_mod_new();
|
|
|
|
if (mod_dest == NULL){
|
|
|
|
return FLUID_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Amount *** */
|
|
|
|
mod_dest->amount = mod_src->amount;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Source *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
|
2003-03-11 16:56:45 +00:00
|
|
|
mod_dest->flags1 = 0;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
|
|
|
if (mod_src->src & (1<<7)){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_CC;
|
|
|
|
} else {
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_GC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
|
|
|
if (mod_src->src & (1<<8)){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_NEGATIVE;
|
|
|
|
} else {
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_POSITIVE;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
|
|
|
if (mod_src->src & (1<<9)){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_BIPOLAR;
|
|
|
|
} else {
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_UNIPOLAR;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* modulator source types: SF2.01 section 8.2.1 page 52 */
|
|
|
|
type = (mod_src->src) >> 10;
|
|
|
|
type &= 63; /* type is a 6-bit value */
|
|
|
|
if (type == 0){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_LINEAR;
|
|
|
|
} else if (type == 1){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_CONCAVE;
|
|
|
|
} else if (type == 2){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_CONVEX;
|
|
|
|
} else if (type == 3){
|
|
|
|
mod_dest->flags1 |= FLUID_MOD_SWITCH;
|
|
|
|
} else {
|
2007-03-04 16:45:05 +00:00
|
|
|
/* This shouldn't happen - unknown type!
|
2003-03-11 16:56:45 +00:00
|
|
|
* Deactivate the modulator by setting the amount to 0. */
|
|
|
|
mod_dest->amount = 0;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Dest *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
mod_dest->dest=mod_src->dest; /* index of controlled generator */
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Amount source *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
mod_dest->src2=mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, page 50 */
|
2003-03-11 16:56:45 +00:00
|
|
|
mod_dest->flags2 = 0;
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
|
|
|
if (mod_src->amtsrc & (1<<7)){
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_CC;
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_GC;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
|
|
|
if (mod_src->amtsrc & (1<<8)){
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_POSITIVE;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
|
|
|
if (mod_src->amtsrc & (1<<9)){
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
2005-06-12 01:19:37 +00:00
|
|
|
mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* modulator source types: SF2.01 section 8.2.1 page 52 */
|
|
|
|
type=(mod_src->amtsrc) >> 10;
|
|
|
|
type &= 63; /* type is a 6-bit value */
|
|
|
|
if (type == 0){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_LINEAR;
|
|
|
|
} else if (type == 1){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_CONCAVE;
|
|
|
|
} else if (type == 2){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_CONVEX;
|
|
|
|
} else if (type == 3){
|
|
|
|
mod_dest->flags2 |= FLUID_MOD_SWITCH;
|
|
|
|
} else {
|
2007-03-04 16:45:05 +00:00
|
|
|
/* This shouldn't happen - unknown type!
|
2003-03-11 16:56:45 +00:00
|
|
|
* Deactivate the modulator by setting the amount to 0. */
|
|
|
|
mod_dest->amount = 0;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* *** Transform *** */
|
2007-03-04 16:45:05 +00:00
|
|
|
/* SF2.01 only uses the 'linear' transform (0).
|
2003-03-11 16:56:45 +00:00
|
|
|
* Deactivate the modulator by setting the amount to 0 in any other case.
|
|
|
|
*/
|
|
|
|
if (mod_src->trans !=0){
|
|
|
|
mod_dest->amount = 0;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
|
|
|
/* Store the new modulator in the zone
|
|
|
|
* The order of modulators will make a difference, at least in an instrument context:
|
2003-03-11 16:56:45 +00:00
|
|
|
* The second modulator overwrites the first one, if they only differ in amount. */
|
|
|
|
if (count == 0){
|
|
|
|
zone->mod=mod_dest;
|
|
|
|
} else {
|
|
|
|
fluid_mod_t * last_mod=zone->mod;
|
|
|
|
/* Find the end of the list */
|
|
|
|
while (last_mod->next != NULL){
|
|
|
|
last_mod=last_mod->next;
|
|
|
|
}
|
|
|
|
last_mod->next=mod_dest;
|
|
|
|
}
|
2007-03-04 16:45:05 +00:00
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
r = fluid_list_next(r);
|
|
|
|
} /* foreach modulator */
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_zone_get_sample
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_sample_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_zone_get_sample(fluid_inst_zone_t* zone)
|
|
|
|
{
|
|
|
|
return zone->sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_inst_zone_inside_range
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel)
|
|
|
|
{
|
|
|
|
return ((zone->keylo <= key) &&
|
|
|
|
(zone->keyhi >= key) &&
|
|
|
|
(zone->vello <= vel) &&
|
|
|
|
(zone->velhi >= vel));
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* SAMPLE
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_fluid_sample
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
fluid_sample_t*
|
2003-03-11 16:56:45 +00:00
|
|
|
new_fluid_sample()
|
|
|
|
{
|
|
|
|
fluid_sample_t* sample = NULL;
|
|
|
|
|
|
|
|
sample = FLUID_NEW(fluid_sample_t);
|
|
|
|
if (sample == NULL) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2003-03-11 16:56:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(sample, 0, sizeof(fluid_sample_t));
|
|
|
|
sample->valid = 1;
|
|
|
|
|
|
|
|
return sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delete_fluid_sample
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
delete_fluid_sample(fluid_sample_t* sample)
|
|
|
|
{
|
2017-05-04 07:56:11 +00:00
|
|
|
if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
|
|
|
|
{
|
|
|
|
#if LIBSNDFILE_SUPPORT
|
|
|
|
if (sample->data)
|
|
|
|
FLUID_FREE(sample->data);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
FLUID_FREE(sample);
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_sample_in_rom
|
|
|
|
*/
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_sample_in_rom(fluid_sample_t* sample)
|
|
|
|
{
|
|
|
|
return (sample->sampletype & FLUID_SAMPLETYPE_ROM);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fluid_sample_import_sfont
|
|
|
|
*/
|
2017-05-04 07:56:11 +00:00
|
|
|
#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);
|
2017-08-03 21:48:44 +00:00
|
|
|
}
|
2017-05-04 07:56:11 +00:00
|
|
|
|
|
|
|
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:
|
2017-08-03 21:46:50 +00:00
|
|
|
sample->userdata = (void *)offset;
|
2017-05-04 07:56:11 +00:00
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
2017-08-04 09:20:13 +00:00
|
|
|
sample->userdata = (void *)((sf_count_t)sample->userdata + offset);
|
2017-05-04 07:56:11 +00:00
|
|
|
break;
|
|
|
|
case SEEK_END:
|
2017-08-03 21:46:50 +00:00
|
|
|
sample->userdata = (void *)(sfvio_get_filelen(user_data) + offset);
|
2017-05-04 07:56:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-08-03 21:46:50 +00:00
|
|
|
return (sf_count_t)sample->userdata;
|
2017-08-03 21:48:44 +00:00
|
|
|
}
|
2017-05-04 07:56:11 +00:00
|
|
|
|
|
|
|
static sf_count_t
|
|
|
|
sfvio_read(void* ptr, sf_count_t count, void* user_data)
|
|
|
|
{
|
|
|
|
fluid_sample_t *sample = (fluid_sample_t *)user_data;
|
2017-08-04 10:07:16 +00:00
|
|
|
sf_count_t remain = sfvio_get_filelen(user_data) - (sf_count_t)sample->userdata;
|
|
|
|
|
|
|
|
if (count > remain)
|
|
|
|
count = remain;
|
2017-05-04 07:56:11 +00:00
|
|
|
|
2017-08-03 21:46:50 +00:00
|
|
|
memcpy(ptr, (char *)sample->data + sample->start + (sf_count_t)sample->userdata, count);
|
2017-08-04 09:20:13 +00:00
|
|
|
sample->userdata = (void *)((sf_count_t)sample->userdata + count);
|
2017-05-04 07:56:11 +00:00
|
|
|
|
|
|
|
return count;
|
2017-08-03 21:48:44 +00:00
|
|
|
}
|
2017-05-04 07:56:11 +00:00
|
|
|
|
|
|
|
static sf_count_t
|
|
|
|
sfvio_tell (void* user_data)
|
|
|
|
{
|
2017-08-03 21:46:50 +00:00
|
|
|
fluid_sample_t *sample = (fluid_sample_t *)user_data;
|
|
|
|
|
|
|
|
return (sf_count_t)sample->userdata;
|
2017-08-03 21:48:44 +00:00
|
|
|
}
|
2017-05-04 07:56:11 +00:00
|
|
|
#endif
|
|
|
|
|
2007-03-04 16:45:05 +00:00
|
|
|
int
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont)
|
|
|
|
{
|
|
|
|
FLUID_STRCPY(sample->name, sfsample->name);
|
|
|
|
sample->data = sfont->sampledata;
|
|
|
|
sample->start = sfsample->start;
|
|
|
|
sample->end = sfsample->start + sfsample->end;
|
|
|
|
sample->loopstart = sfsample->start + sfsample->loopstart;
|
|
|
|
sample->loopend = sfsample->start + sfsample->loopend;
|
|
|
|
sample->samplerate = sfsample->samplerate;
|
|
|
|
sample->origpitch = sfsample->origpitch;
|
|
|
|
sample->pitchadj = sfsample->pitchadj;
|
|
|
|
sample->sampletype = sfsample->sampletype;
|
|
|
|
|
2017-05-04 07:56:11 +00:00
|
|
|
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;
|
2017-08-12 13:55:47 +00:00
|
|
|
int inv_loop = FALSE;
|
2017-05-04 07:56:11 +00:00
|
|
|
|
|
|
|
// initialize file position indicator and SF_INFO structure
|
2017-08-04 10:07:16 +00:00
|
|
|
g_assert(sample->userdata == NULL);
|
2017-05-04 07:56:11 +00:00
|
|
|
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;
|
|
|
|
|
2017-08-11 12:43:00 +00:00
|
|
|
/* loop is fowled?? (cluck cluck :) */
|
2017-08-12 13:55:47 +00:00
|
|
|
if (sample->loopend-1 > sample->end /* loopend may point one sample after valid sample data, as this one will never be played */
|
|
|
|
|| sample->loopstart >= sample->loopend)
|
2017-08-11 12:43:00 +00:00
|
|
|
{
|
2017-08-12 13:55:47 +00:00
|
|
|
FLUID_LOG (FLUID_DBG, _("Vorbis sample '%s' has unusable loop stop '%d',"
|
|
|
|
" setting to sample end '%d'+1"), sample->name, sample->loopend, sample->end);
|
|
|
|
|
|
|
|
/* though illegal, loopend may be set to loopstart to disable loop */
|
|
|
|
/* is it worth informing the user? */
|
|
|
|
inv_loop |= (sample->loopend != sample->loopstart);
|
|
|
|
sample->loopend = sample->end+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sample->loopstart < sample->start
|
|
|
|
|| sample->loopstart >= sample->loopend)
|
|
|
|
{
|
|
|
|
FLUID_LOG (FLUID_DBG, _("Vorbis sample '%s' has unusable loop start '%d',"
|
|
|
|
" setting to sample start '%d'"), sample->name, sample->loopstart, sample->start);
|
2017-08-11 16:43:22 +00:00
|
|
|
sample->loopstart = sample->start;
|
2017-08-12 13:55:47 +00:00
|
|
|
inv_loop |= TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(inv_loop)
|
|
|
|
{
|
|
|
|
FLUID_LOG (FLUID_WARN, _("Vorbis sample '%s' has invalid loop points"), sample->name);
|
2017-08-11 12:43:00 +00:00
|
|
|
}
|
2017-05-04 07:56:11 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
if (sample->sampletype & FLUID_SAMPLETYPE_ROM) {
|
|
|
|
sample->valid = 0;
|
2017-08-12 13:55:47 +00:00
|
|
|
FLUID_LOG(FLUID_WARN, "Ignoring sample '%s': can't use ROM samples", sample->name);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
2003-06-28 21:09:44 +00:00
|
|
|
if (sample->end - sample->start < 8) {
|
2003-03-11 16:56:45 +00:00
|
|
|
sample->valid = 0;
|
2017-08-12 13:55:47 +00:00
|
|
|
FLUID_LOG(FLUID_WARN, "Ignoring sample '%s': too few sample data points", sample->name);
|
2003-03-11 16:56:45 +00:00
|
|
|
} else {
|
|
|
|
/* if (sample->loopstart < sample->start + 8) { */
|
|
|
|
/* FLUID_LOG(FLUID_WARN, "Fixing sample %s: at least 8 data points required before loop start", sample->name); */
|
|
|
|
/* sample->loopstart = sample->start + 8; */
|
|
|
|
/* } */
|
|
|
|
/* if (sample->loopend > sample->end - 8) { */
|
|
|
|
/* FLUID_LOG(FLUID_WARN, "Fixing sample %s: at least 8 data points required after loop end", sample->name); */
|
|
|
|
/* sample->loopend = sample->end - 8; */
|
|
|
|
/* } */
|
|
|
|
}
|
|
|
|
return FLUID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-08-19 20:57:00 +00:00
|
|
|
/*=================================sfload.c========================
|
|
|
|
Borrowed from Smurf SoundFont Editor by Josh Green
|
|
|
|
=================================================================*/
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
functions for loading data from sfont files, with appropriate byte swapping
|
|
|
|
on big endian machines. Sfont IDs are not swapped because the ID read is
|
|
|
|
equivalent to the matching ID list in memory regardless of LE/BE machine
|
|
|
|
*/
|
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define READCHUNK(var,fd) do { \
|
2003-03-11 16:56:45 +00:00
|
|
|
if (!safe_fread(var, 8, fd)) \
|
2009-10-13 03:41:19 +00:00
|
|
|
return(FAIL); \
|
2017-10-25 14:11:43 +00:00
|
|
|
((SFChunk *)(var))->size = FLUID_LE32TOH(((SFChunk *)(var))->size); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define READD(var,fd) do { \
|
2017-10-25 14:11:43 +00:00
|
|
|
uint32 _temp; \
|
2009-10-13 03:41:19 +00:00
|
|
|
if (!safe_fread(&_temp, 4, fd)) \
|
|
|
|
return(FAIL); \
|
2017-10-25 14:11:43 +00:00
|
|
|
var = FLUID_LE32TOH(_temp); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define READW(var,fd) do { \
|
2017-10-25 14:11:43 +00:00
|
|
|
uint16 _temp; \
|
2009-10-13 03:41:19 +00:00
|
|
|
if (!safe_fread(&_temp, 2, fd)) \
|
|
|
|
return(FAIL); \
|
2017-10-25 14:11:43 +00:00
|
|
|
var = FLUID_LE16TOH(_temp); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define READID(var,fd) do { \
|
2009-10-13 03:41:19 +00:00
|
|
|
if (!safe_fread(var, 4, fd)) \
|
|
|
|
return(FAIL); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define READSTR(var,fd) do { \
|
2009-10-13 03:41:19 +00:00
|
|
|
if (!safe_fread(var, 20, fd)) \
|
|
|
|
return(FAIL); \
|
|
|
|
(*var)[20] = '\0'; \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define READB(var,fd) do { \
|
2003-03-11 16:56:45 +00:00
|
|
|
if (!safe_fread(&var, 1, fd)) \
|
|
|
|
return(FAIL); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define FSKIP(size,fd) do { \
|
2003-03-11 16:56:45 +00:00
|
|
|
if (!safe_fseek(fd, size, SEEK_CUR)) \
|
|
|
|
return(FAIL); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2009-10-13 03:41:19 +00:00
|
|
|
|
2017-10-22 12:39:06 +00:00
|
|
|
#define FSKIPW(fd) do { \
|
2003-03-11 16:56:45 +00:00
|
|
|
if (!safe_fseek(fd, 2, SEEK_CUR)) \
|
|
|
|
return(FAIL); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/* removes and advances a fluid_list_t pointer */
|
2017-10-22 12:39:06 +00:00
|
|
|
#define SLADVREM(list, item) do { \
|
2003-03-11 16:56:45 +00:00
|
|
|
fluid_list_t *_temp = item; \
|
|
|
|
item = fluid_list_next(item); \
|
|
|
|
list = fluid_list_remove_link(list, _temp); \
|
|
|
|
delete1_fluid_list(_temp); \
|
2017-10-22 12:39:06 +00:00
|
|
|
} while(0)
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
static int chunkid (unsigned int id);
|
|
|
|
static int load_body (unsigned int size, SFData * sf, FILE * fd);
|
|
|
|
static int read_listchunk (SFChunk * chunk, FILE * fd);
|
|
|
|
static int process_info (int size, SFData * sf, FILE * fd);
|
2011-02-28 07:14:27 +00:00
|
|
|
static int process_sdta (unsigned int size, SFData * sf, FILE * fd);
|
2003-03-11 16:56:45 +00:00
|
|
|
static int pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk,
|
|
|
|
int * size, FILE * fd);
|
|
|
|
static int process_pdta (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_phdr (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_pbag (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_pmod (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_pgen (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_ihdr (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_ibag (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_imod (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_igen (int size, SFData * sf, FILE * fd);
|
|
|
|
static int load_shdr (unsigned int size, SFData * sf, FILE * fd);
|
|
|
|
static int fixup_pgen (SFData * sf);
|
|
|
|
static int fixup_igen (SFData * sf);
|
|
|
|
static int fixup_sample (SFData * sf);
|
|
|
|
|
2017-10-21 10:47:59 +00:00
|
|
|
static const char idlist[] = {
|
2003-03-11 16:56:45 +00:00
|
|
|
"RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"
|
|
|
|
"ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdr"
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int sdtachunk_size;
|
|
|
|
|
|
|
|
/* sound font file load functions */
|
|
|
|
static int
|
|
|
|
chunkid (unsigned int id)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int *p;
|
|
|
|
|
|
|
|
p = (unsigned int *) & idlist;
|
|
|
|
for (i = 0; i < sizeof (idlist) / sizeof (int); i++, p += 1)
|
|
|
|
if (*p == id)
|
|
|
|
return (i + 1);
|
|
|
|
|
|
|
|
return (UNKN_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
SFData *
|
|
|
|
sfload_file (const char * fname)
|
|
|
|
{
|
|
|
|
SFData *sf = NULL;
|
|
|
|
FILE *fd;
|
|
|
|
int fsize = 0;
|
|
|
|
int err = FALSE;
|
|
|
|
|
|
|
|
if (!(fd = fopen (fname, "rb")))
|
|
|
|
{
|
|
|
|
FLUID_LOG (FLUID_ERR, _("Unable to open file \"%s\""), fname);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2006-11-23 18:49:36 +00:00
|
|
|
if (!(sf = FLUID_NEW (SFData)))
|
|
|
|
{
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
2014-09-25 11:39:55 +00:00
|
|
|
fclose(fd);
|
2006-11-23 18:49:36 +00:00
|
|
|
err = TRUE;
|
|
|
|
}
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
if (!err)
|
|
|
|
{
|
|
|
|
memset (sf, 0, sizeof (SFData)); /* zero sfdata */
|
|
|
|
sf->fname = FLUID_STRDUP (fname); /* copy file name */
|
|
|
|
sf->sffd = fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get size of file */
|
|
|
|
if (!err && fseek (fd, 0L, SEEK_END) == -1)
|
|
|
|
{ /* seek to end of file */
|
|
|
|
err = TRUE;
|
|
|
|
FLUID_LOG (FLUID_ERR, _("Seek to end of file failed"));
|
|
|
|
}
|
|
|
|
if (!err && (fsize = ftell (fd)) == -1)
|
|
|
|
{ /* position = size */
|
|
|
|
err = TRUE;
|
|
|
|
FLUID_LOG (FLUID_ERR, _("Get end of file position failed"));
|
|
|
|
}
|
|
|
|
if (!err)
|
|
|
|
rewind (fd);
|
|
|
|
|
|
|
|
if (!err && !load_body (fsize, sf, fd))
|
|
|
|
err = TRUE; /* load the sfont */
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
if (sf)
|
|
|
|
sfont_close (sf);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (sf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
load_body (unsigned int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
SFChunk chunk;
|
|
|
|
|
|
|
|
READCHUNK (&chunk, fd); /* load RIFF chunk */
|
|
|
|
if (chunkid (chunk.id) != RIFF_ID) { /* error if not RIFF */
|
|
|
|
FLUID_LOG (FLUID_ERR, _("Not a RIFF file"));
|
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
READID (&chunk.id, fd); /* load file ID */
|
|
|
|
if (chunkid (chunk.id) != SFBK_ID) { /* error if not SFBK_ID */
|
2009-10-13 03:41:19 +00:00
|
|
|
FLUID_LOG (FLUID_ERR, _("Not a SoundFont file"));
|
2003-03-11 16:56:45 +00:00
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chunk.size != size - 8) {
|
2009-10-13 03:41:19 +00:00
|
|
|
gerr (ErrCorr, _("SoundFont file size mismatch"));
|
2003-03-11 16:56:45 +00:00
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process INFO block */
|
|
|
|
if (!read_listchunk (&chunk, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (chunkid (chunk.id) != INFO_ID)
|
|
|
|
return (gerr (ErrCorr, _("Invalid ID found when expecting INFO chunk")));
|
|
|
|
if (!process_info (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
/* Process sample chunk */
|
|
|
|
if (!read_listchunk (&chunk, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (chunkid (chunk.id) != SDTA_ID)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Invalid ID found when expecting SAMPLE chunk")));
|
|
|
|
if (!process_sdta (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
/* process HYDRA chunk */
|
|
|
|
if (!read_listchunk (&chunk, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (chunkid (chunk.id) != PDTA_ID)
|
|
|
|
return (gerr (ErrCorr, _("Invalid ID found when expecting HYDRA chunk")));
|
|
|
|
if (!process_pdta (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!fixup_pgen (sf))
|
|
|
|
return (FAIL);
|
|
|
|
if (!fixup_igen (sf))
|
|
|
|
return (FAIL);
|
|
|
|
if (!fixup_sample (sf))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
/* sort preset list by bank, preset # */
|
|
|
|
sf->preset = fluid_list_sort (sf->preset,
|
|
|
|
(fluid_compare_func_t) sfont_preset_compare_func);
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_listchunk (SFChunk * chunk, FILE * fd)
|
|
|
|
{
|
|
|
|
READCHUNK (chunk, fd); /* read list chunk */
|
|
|
|
if (chunkid (chunk->id) != LIST_ID) /* error if ! list chunk */
|
|
|
|
return (gerr (ErrCorr, _("Invalid chunk id in level 0 parse")));
|
|
|
|
READID (&chunk->id, fd); /* read id string */
|
|
|
|
chunk->size -= 4;
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
process_info (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
SFChunk chunk;
|
|
|
|
unsigned char id;
|
|
|
|
char *item;
|
|
|
|
unsigned short ver;
|
|
|
|
|
|
|
|
while (size > 0)
|
|
|
|
{
|
|
|
|
READCHUNK (&chunk, fd);
|
|
|
|
size -= 8;
|
|
|
|
|
|
|
|
id = chunkid (chunk.id);
|
|
|
|
|
|
|
|
if (id == IFIL_ID)
|
|
|
|
{ /* sound font version chunk? */
|
|
|
|
if (chunk.size != 4)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Sound font version info chunk has invalid size")));
|
|
|
|
|
|
|
|
READW (ver, fd);
|
|
|
|
sf->version.major = ver;
|
|
|
|
READW (ver, fd);
|
|
|
|
sf->version.minor = ver;
|
|
|
|
|
|
|
|
if (sf->version.major < 2) {
|
|
|
|
FLUID_LOG (FLUID_ERR,
|
|
|
|
_("Sound font version is %d.%d which is not"
|
2007-03-04 16:45:05 +00:00
|
|
|
" supported, convert to version 2.0x"),
|
2003-03-11 16:56:45 +00:00
|
|
|
sf->version.major,
|
|
|
|
sf->version.minor);
|
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
|
2017-08-07 16:23:46 +00:00
|
|
|
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);
|
2017-05-04 07:56:11 +00:00
|
|
|
#endif
|
2017-08-07 16:23:46 +00:00
|
|
|
}
|
|
|
|
else if (sf->version.major > 2) {
|
2007-03-04 16:45:05 +00:00
|
|
|
FLUID_LOG (FLUID_WARN,
|
2003-03-11 16:56:45 +00:00
|
|
|
_("Sound font version is %d.%d which is newer than"
|
2017-08-05 19:14:19 +00:00
|
|
|
" what this version of fluidsynth was designed for (v2.0x)"),
|
2003-03-11 16:56:45 +00:00
|
|
|
sf->version.major,
|
|
|
|
sf->version.minor);
|
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (id == IVER_ID)
|
|
|
|
{ /* ROM version chunk? */
|
|
|
|
if (chunk.size != 4)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("ROM version info chunk has invalid size")));
|
|
|
|
|
|
|
|
READW (ver, fd);
|
|
|
|
sf->romver.major = ver;
|
|
|
|
READW (ver, fd);
|
|
|
|
sf->romver.minor = ver;
|
|
|
|
}
|
|
|
|
else if (id != UNKN_ID)
|
|
|
|
{
|
|
|
|
if ((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536)
|
|
|
|
|| (chunk.size % 2))
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("INFO sub chunk %.4s has invalid chunk size"
|
|
|
|
" of %d bytes"), &chunk.id, chunk.size));
|
|
|
|
|
|
|
|
/* alloc for chunk id and da chunk */
|
2006-11-23 18:49:36 +00:00
|
|
|
if (!(item = FLUID_MALLOC (chunk.size + 1)))
|
|
|
|
{
|
|
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
|
|
return (FAIL);
|
|
|
|
}
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
/* attach to INFO list, sfont_close will cleanup if FAIL occurs */
|
|
|
|
sf->info = fluid_list_append (sf->info, item);
|
|
|
|
|
|
|
|
*(unsigned char *) item = id;
|
|
|
|
if (!safe_fread (&item[1], chunk.size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
/* force terminate info item (don't forget uint8 info ID) */
|
|
|
|
*(item + chunk.size) = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return (gerr (ErrCorr, _("Invalid chunk id in INFO chunk")));
|
|
|
|
size -= chunk.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size < 0)
|
|
|
|
return (gerr (ErrCorr, _("INFO chunk size mismatch")));
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-02-28 07:14:27 +00:00
|
|
|
process_sdta (unsigned int size, SFData * sf, FILE * fd)
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
|
|
|
SFChunk chunk;
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
return (OK); /* no sample data? */
|
|
|
|
|
|
|
|
/* read sub chunk */
|
|
|
|
READCHUNK (&chunk, fd);
|
|
|
|
size -= 8;
|
|
|
|
|
|
|
|
if (chunkid (chunk.id) != SMPL_ID)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Expected SMPL chunk found invalid id instead")));
|
|
|
|
|
2011-01-04 21:22:56 +00:00
|
|
|
/* SDTA chunk may also contain sm24 chunk for 24 bit samples
|
|
|
|
* (not yet supported), only an error if SMPL chunk size is
|
|
|
|
* greater than SDTA. */
|
|
|
|
if (chunk.size > size)
|
2003-03-11 16:56:45 +00:00
|
|
|
return (gerr (ErrCorr, _("SDTA chunk size mismatch")));
|
|
|
|
|
|
|
|
/* sample data follows */
|
|
|
|
sf->samplepos = ftell (fd);
|
|
|
|
|
|
|
|
/* used in fixup_sample() to check validity of sample headers */
|
|
|
|
sdtachunk_size = chunk.size;
|
|
|
|
sf->samplesize = chunk.size;
|
|
|
|
|
2011-01-04 21:22:56 +00:00
|
|
|
FSKIP (size, fd);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk,
|
|
|
|
int * size, FILE * fd)
|
|
|
|
{
|
|
|
|
unsigned int id;
|
2017-10-21 10:47:59 +00:00
|
|
|
const char *expstr;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
expstr = CHNKIDSTR (expid); /* in case we need it */
|
|
|
|
|
|
|
|
READCHUNK (chunk, fd);
|
|
|
|
*size -= 8;
|
|
|
|
|
|
|
|
if ((id = chunkid (chunk->id)) != expid)
|
|
|
|
return (gerr (ErrCorr, _("Expected"
|
|
|
|
" PDTA sub-chunk \"%.4s\" found invalid id instead"), expstr));
|
|
|
|
|
|
|
|
if (chunk->size % reclen) /* valid chunk size? */
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("\"%.4s\" chunk size is not a multiple of %d bytes"), expstr,
|
|
|
|
reclen));
|
|
|
|
if ((*size -= chunk->size) < 0)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("\"%.4s\" chunk size exceeds remaining PDTA chunk size"), expstr));
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
process_pdta (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
SFChunk chunk;
|
|
|
|
|
|
|
|
if (!pdtahelper (PHDR_ID, SFPHDRSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_phdr (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (PBAG_ID, SFBAGSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_pbag (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (PMOD_ID, SFMODSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_pmod (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (PGEN_ID, SFGENSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_pgen (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (IHDR_ID, SFIHDRSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_ihdr (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (IBAG_ID, SFBAGSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_ibag (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (IMOD_ID, SFMODSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_imod (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (IGEN_ID, SFGENSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_igen (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
if (!pdtahelper (SHDR_ID, SFSHDRSIZE, &chunk, &size, fd))
|
|
|
|
return (FAIL);
|
|
|
|
if (!load_shdr (chunk.size, sf, fd))
|
|
|
|
return (FAIL);
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* preset header loader */
|
|
|
|
static int
|
|
|
|
load_phdr (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
int i, i2;
|
|
|
|
SFPreset *p, *pr = NULL; /* ptr to current & previous preset */
|
|
|
|
unsigned short zndx, pzndx = 0;
|
|
|
|
|
|
|
|
if (size % SFPHDRSIZE || size == 0)
|
|
|
|
return (gerr (ErrCorr, _("Preset header chunk size is invalid")));
|
|
|
|
|
|
|
|
i = size / SFPHDRSIZE - 1;
|
|
|
|
if (i == 0)
|
|
|
|
{ /* at least one preset + term record */
|
|
|
|
FLUID_LOG (FLUID_WARN, _("File contains no presets"));
|
|
|
|
FSKIP (SFPHDRSIZE, fd);
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i > 0; i--)
|
|
|
|
{ /* load all preset headers */
|
|
|
|
p = FLUID_NEW (SFPreset);
|
|
|
|
sf->preset = fluid_list_append (sf->preset, p);
|
|
|
|
p->zone = NULL; /* In case of failure, sfont_close can cleanup */
|
|
|
|
READSTR (&p->name, fd); /* possible read failure ^ */
|
|
|
|
READW (p->prenum, fd);
|
|
|
|
READW (p->bank, fd);
|
|
|
|
READW (zndx, fd);
|
|
|
|
READD (p->libr, fd);
|
|
|
|
READD (p->genre, fd);
|
|
|
|
READD (p->morph, fd);
|
|
|
|
|
|
|
|
if (pr)
|
|
|
|
{ /* not first preset? */
|
|
|
|
if (zndx < pzndx)
|
|
|
|
return (gerr (ErrCorr, _("Preset header indices not monotonic")));
|
|
|
|
i2 = zndx - pzndx;
|
|
|
|
while (i2--)
|
|
|
|
{
|
|
|
|
pr->zone = fluid_list_prepend (pr->zone, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (zndx > 0) /* 1st preset, warn if ofs >0 */
|
|
|
|
FLUID_LOG (FLUID_WARN, _("%d preset zones not referenced, discarding"), zndx);
|
|
|
|
pr = p; /* update preset ptr */
|
|
|
|
pzndx = zndx;
|
|
|
|
}
|
|
|
|
|
|
|
|
FSKIP (24, fd);
|
|
|
|
READW (zndx, fd); /* Read terminal generator index */
|
|
|
|
FSKIP (12, fd);
|
|
|
|
|
|
|
|
if (zndx < pzndx)
|
|
|
|
return (gerr (ErrCorr, _("Preset header indices not monotonic")));
|
|
|
|
i2 = zndx - pzndx;
|
|
|
|
while (i2--)
|
|
|
|
{
|
|
|
|
pr->zone = fluid_list_prepend (pr->zone, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* preset bag loader */
|
|
|
|
static int
|
|
|
|
load_pbag (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2;
|
|
|
|
SFZone *z, *pz = NULL;
|
|
|
|
unsigned short genndx, modndx;
|
|
|
|
unsigned short pgenndx = 0, pmodndx = 0;
|
|
|
|
unsigned short i;
|
|
|
|
|
|
|
|
if (size % SFBAGSIZE || size == 0) /* size is multiple of SFBAGSIZE? */
|
|
|
|
return (gerr (ErrCorr, _("Preset bag chunk size is invalid")));
|
|
|
|
|
|
|
|
p = sf->preset;
|
|
|
|
while (p)
|
|
|
|
{ /* traverse through presets */
|
|
|
|
p2 = ((SFPreset *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse preset's zones */
|
|
|
|
if ((size -= SFBAGSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr, _("Preset bag chunk size mismatch")));
|
|
|
|
z = FLUID_NEW (SFZone);
|
|
|
|
p2->data = z;
|
|
|
|
z->gen = NULL; /* Init gen and mod before possible failure, */
|
|
|
|
z->mod = NULL; /* to ensure proper cleanup (sfont_close) */
|
|
|
|
READW (genndx, fd); /* possible read failure ^ */
|
|
|
|
READW (modndx, fd);
|
|
|
|
z->instsamp = NULL;
|
|
|
|
|
|
|
|
if (pz)
|
|
|
|
{ /* if not first zone */
|
|
|
|
if (genndx < pgenndx)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Preset bag generator indices not monotonic")));
|
|
|
|
if (modndx < pmodndx)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Preset bag modulator indices not monotonic")));
|
|
|
|
i = genndx - pgenndx;
|
|
|
|
while (i--)
|
|
|
|
pz->gen = fluid_list_prepend (pz->gen, NULL);
|
|
|
|
i = modndx - pmodndx;
|
|
|
|
while (i--)
|
|
|
|
pz->mod = fluid_list_prepend (pz->mod, NULL);
|
|
|
|
}
|
|
|
|
pz = z; /* update previous zone ptr */
|
|
|
|
pgenndx = genndx; /* update previous zone gen index */
|
|
|
|
pmodndx = modndx; /* update previous zone mod index */
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
}
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
size -= SFBAGSIZE;
|
|
|
|
if (size != 0)
|
|
|
|
return (gerr (ErrCorr, _("Preset bag chunk size mismatch")));
|
|
|
|
|
|
|
|
READW (genndx, fd);
|
|
|
|
READW (modndx, fd);
|
|
|
|
|
|
|
|
if (!pz)
|
|
|
|
{
|
|
|
|
if (genndx > 0)
|
|
|
|
FLUID_LOG (FLUID_WARN, _("No preset generators and terminal index not 0"));
|
|
|
|
if (modndx > 0)
|
|
|
|
FLUID_LOG (FLUID_WARN, _("No preset modulators and terminal index not 0"));
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (genndx < pgenndx)
|
|
|
|
return (gerr (ErrCorr, _("Preset bag generator indices not monotonic")));
|
|
|
|
if (modndx < pmodndx)
|
|
|
|
return (gerr (ErrCorr, _("Preset bag modulator indices not monotonic")));
|
|
|
|
i = genndx - pgenndx;
|
|
|
|
while (i--)
|
|
|
|
pz->gen = fluid_list_prepend (pz->gen, NULL);
|
|
|
|
i = modndx - pmodndx;
|
|
|
|
while (i--)
|
|
|
|
pz->mod = fluid_list_prepend (pz->mod, NULL);
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* preset modulator loader */
|
|
|
|
static int
|
|
|
|
load_pmod (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2, *p3;
|
|
|
|
SFMod *m;
|
|
|
|
|
|
|
|
p = sf->preset;
|
|
|
|
while (p)
|
|
|
|
{ /* traverse through all presets */
|
|
|
|
p2 = ((SFPreset *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse this preset's zones */
|
|
|
|
p3 = ((SFZone *) (p2->data))->mod;
|
|
|
|
while (p3)
|
|
|
|
{ /* load zone's modulators */
|
|
|
|
if ((size -= SFMODSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Preset modulator chunk size mismatch")));
|
|
|
|
m = FLUID_NEW (SFMod);
|
|
|
|
p3->data = m;
|
|
|
|
READW (m->src, fd);
|
|
|
|
READW (m->dest, fd);
|
|
|
|
READW (m->amount, fd);
|
|
|
|
READW (m->amtsrc, fd);
|
|
|
|
READW (m->trans, fd);
|
|
|
|
p3 = fluid_list_next (p3);
|
|
|
|
}
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
}
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If there isn't even a terminal record
|
|
|
|
Hmmm, the specs say there should be one, but..
|
|
|
|
*/
|
|
|
|
if (size == 0)
|
|
|
|
return (OK);
|
|
|
|
|
|
|
|
size -= SFMODSIZE;
|
|
|
|
if (size != 0)
|
|
|
|
return (gerr (ErrCorr, _("Preset modulator chunk size mismatch")));
|
|
|
|
FSKIP (SFMODSIZE, fd); /* terminal mod */
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------
|
|
|
|
* preset generator loader
|
|
|
|
* generator (per preset) loading rules:
|
|
|
|
* Zones with no generators or modulators shall be annihilated
|
|
|
|
* Global zone must be 1st zone, discard additional ones (instrumentless zones)
|
|
|
|
*
|
|
|
|
* generator (per zone) loading rules (in order of decreasing precedence):
|
|
|
|
* KeyRange is 1st in list (if exists), else discard
|
|
|
|
* if a VelRange exists only preceded by a KeyRange, else discard
|
|
|
|
* if a generator follows an instrument discard it
|
|
|
|
* if a duplicate generator exists replace previous one
|
|
|
|
* ------------------------------------------------------------------- */
|
|
|
|
static int
|
|
|
|
load_pgen (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
|
|
|
|
SFZone *z;
|
|
|
|
SFGen *g;
|
|
|
|
SFGenAmount genval;
|
|
|
|
unsigned short genid;
|
|
|
|
int level, skip, drop, gzone, discarded;
|
|
|
|
|
|
|
|
p = sf->preset;
|
|
|
|
while (p)
|
|
|
|
{ /* traverse through all presets */
|
|
|
|
gzone = FALSE;
|
|
|
|
discarded = FALSE;
|
|
|
|
p2 = ((SFPreset *) (p->data))->zone;
|
|
|
|
if (p2)
|
|
|
|
hz = &p2;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse preset's zones */
|
|
|
|
level = 0;
|
|
|
|
z = (SFZone *) (p2->data);
|
|
|
|
p3 = z->gen;
|
|
|
|
while (p3)
|
|
|
|
{ /* load zone's generators */
|
|
|
|
dup = NULL;
|
|
|
|
skip = FALSE;
|
|
|
|
drop = FALSE;
|
|
|
|
if ((size -= SFGENSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Preset generator chunk size mismatch")));
|
|
|
|
|
|
|
|
READW (genid, fd);
|
|
|
|
|
|
|
|
if (genid == Gen_KeyRange)
|
|
|
|
{ /* nothing precedes */
|
|
|
|
if (level == 0)
|
|
|
|
{
|
|
|
|
level = 1;
|
|
|
|
READB (genval.range.lo, fd);
|
|
|
|
READB (genval.range.hi, fd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
else if (genid == Gen_VelRange)
|
|
|
|
{ /* only KeyRange precedes */
|
|
|
|
if (level <= 1)
|
|
|
|
{
|
|
|
|
level = 2;
|
|
|
|
READB (genval.range.lo, fd);
|
|
|
|
READB (genval.range.hi, fd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
else if (genid == Gen_Instrument)
|
|
|
|
{ /* inst is last gen */
|
|
|
|
level = 3;
|
|
|
|
READW (genval.uword, fd);
|
2017-10-21 16:32:17 +00:00
|
|
|
((SFZone *) (p2->data))->instsamp = FLUID_INT_TO_POINTER (genval.uword + 1);
|
2003-03-11 16:56:45 +00:00
|
|
|
break; /* break out of generator loop */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
level = 2;
|
|
|
|
if (gen_validp (genid))
|
|
|
|
{ /* generator valid? */
|
|
|
|
READW (genval.sword, fd);
|
|
|
|
dup = gen_inlist (genid, z->gen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!skip)
|
|
|
|
{
|
|
|
|
if (!dup)
|
|
|
|
{ /* if gen ! dup alloc new */
|
|
|
|
g = FLUID_NEW (SFGen);
|
|
|
|
p3->data = g;
|
|
|
|
g->id = genid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g = (SFGen *) (dup->data); /* ptr to orig gen */
|
|
|
|
drop = TRUE;
|
|
|
|
}
|
|
|
|
g->amount = genval;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* Skip this generator */
|
|
|
|
discarded = TRUE;
|
|
|
|
drop = TRUE;
|
|
|
|
FSKIPW (fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!drop)
|
|
|
|
p3 = fluid_list_next (p3); /* next gen */
|
|
|
|
else
|
|
|
|
SLADVREM (z->gen, p3); /* drop place holder */
|
|
|
|
|
|
|
|
} /* generator loop */
|
|
|
|
|
|
|
|
if (level == 3)
|
|
|
|
SLADVREM (z->gen, p3); /* zone has inst? */
|
|
|
|
else
|
|
|
|
{ /* congratulations its a global zone */
|
|
|
|
if (!gzone)
|
|
|
|
{ /* Prior global zones? */
|
|
|
|
gzone = TRUE;
|
|
|
|
|
|
|
|
/* if global zone is not 1st zone, relocate */
|
|
|
|
if (*hz != p2)
|
|
|
|
{
|
|
|
|
void* save = p2->data;
|
|
|
|
FLUID_LOG (FLUID_WARN,
|
|
|
|
_("Preset \"%s\": Global zone is not first zone"),
|
|
|
|
((SFPreset *) (p->data))->name);
|
|
|
|
SLADVREM (*hz, p2);
|
|
|
|
*hz = fluid_list_prepend (*hz, save);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* previous global zone exists, discard */
|
|
|
|
FLUID_LOG (FLUID_WARN,
|
|
|
|
_("Preset \"%s\": Discarding invalid global zone"),
|
|
|
|
((SFPreset *) (p->data))->name);
|
|
|
|
sfont_zone_delete (sf, hz, (SFZone *) (p2->data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (p3)
|
|
|
|
{ /* Kill any zones following an instrument */
|
|
|
|
discarded = TRUE;
|
|
|
|
if ((size -= SFGENSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Preset generator chunk size mismatch")));
|
|
|
|
FSKIP (SFGENSIZE, fd);
|
|
|
|
SLADVREM (z->gen, p3);
|
|
|
|
}
|
|
|
|
|
|
|
|
p2 = fluid_list_next (p2); /* next zone */
|
|
|
|
}
|
|
|
|
if (discarded)
|
|
|
|
FLUID_LOG(FLUID_WARN,
|
|
|
|
_("Preset \"%s\": Some invalid generators were discarded"),
|
|
|
|
((SFPreset *) (p->data))->name);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in case there isn't a terminal record */
|
|
|
|
if (size == 0)
|
|
|
|
return (OK);
|
|
|
|
|
|
|
|
size -= SFGENSIZE;
|
|
|
|
if (size != 0)
|
|
|
|
return (gerr (ErrCorr, _("Preset generator chunk size mismatch")));
|
|
|
|
FSKIP (SFGENSIZE, fd); /* terminal gen */
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* instrument header loader */
|
|
|
|
static int
|
|
|
|
load_ihdr (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
int i, i2;
|
|
|
|
SFInst *p, *pr = NULL; /* ptr to current & previous instrument */
|
|
|
|
unsigned short zndx, pzndx = 0;
|
|
|
|
|
|
|
|
if (size % SFIHDRSIZE || size == 0) /* chunk size is valid? */
|
|
|
|
return (gerr (ErrCorr, _("Instrument header has invalid size")));
|
|
|
|
|
|
|
|
size = size / SFIHDRSIZE - 1;
|
|
|
|
if (size == 0)
|
|
|
|
{ /* at least one preset + term record */
|
|
|
|
FLUID_LOG (FLUID_WARN, _("File contains no instruments"));
|
|
|
|
FSKIP (SFIHDRSIZE, fd);
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{ /* load all instrument headers */
|
|
|
|
p = FLUID_NEW (SFInst);
|
|
|
|
sf->inst = fluid_list_append (sf->inst, p);
|
|
|
|
p->zone = NULL; /* For proper cleanup if fail (sfont_close) */
|
|
|
|
READSTR (&p->name, fd); /* Possible read failure ^ */
|
|
|
|
READW (zndx, fd);
|
|
|
|
|
|
|
|
if (pr)
|
|
|
|
{ /* not first instrument? */
|
|
|
|
if (zndx < pzndx)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Instrument header indices not monotonic")));
|
|
|
|
i2 = zndx - pzndx;
|
|
|
|
while (i2--)
|
|
|
|
pr->zone = fluid_list_prepend (pr->zone, NULL);
|
|
|
|
}
|
|
|
|
else if (zndx > 0) /* 1st inst, warn if ofs >0 */
|
|
|
|
FLUID_LOG (FLUID_WARN, _("%d instrument zones not referenced, discarding"),
|
|
|
|
zndx);
|
|
|
|
pzndx = zndx;
|
|
|
|
pr = p; /* update instrument ptr */
|
|
|
|
}
|
|
|
|
|
|
|
|
FSKIP (20, fd);
|
|
|
|
READW (zndx, fd);
|
|
|
|
|
|
|
|
if (zndx < pzndx)
|
|
|
|
return (gerr (ErrCorr, _("Instrument header indices not monotonic")));
|
|
|
|
i2 = zndx - pzndx;
|
|
|
|
while (i2--)
|
|
|
|
pr->zone = fluid_list_prepend (pr->zone, NULL);
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* instrument bag loader */
|
|
|
|
static int
|
|
|
|
load_ibag (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2;
|
|
|
|
SFZone *z, *pz = NULL;
|
|
|
|
unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (size % SFBAGSIZE || size == 0) /* size is multiple of SFBAGSIZE? */
|
|
|
|
return (gerr (ErrCorr, _("Instrument bag chunk size is invalid")));
|
|
|
|
|
|
|
|
p = sf->inst;
|
|
|
|
while (p)
|
|
|
|
{ /* traverse through inst */
|
|
|
|
p2 = ((SFInst *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* load this inst's zones */
|
|
|
|
if ((size -= SFBAGSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr, _("Instrument bag chunk size mismatch")));
|
|
|
|
z = FLUID_NEW (SFZone);
|
|
|
|
p2->data = z;
|
|
|
|
z->gen = NULL; /* In case of failure, */
|
|
|
|
z->mod = NULL; /* sfont_close can clean up */
|
|
|
|
READW (genndx, fd); /* READW = possible read failure */
|
|
|
|
READW (modndx, fd);
|
|
|
|
z->instsamp = NULL;
|
|
|
|
|
|
|
|
if (pz)
|
|
|
|
{ /* if not first zone */
|
|
|
|
if (genndx < pgenndx)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Instrument generator indices not monotonic")));
|
|
|
|
if (modndx < pmodndx)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Instrument modulator indices not monotonic")));
|
|
|
|
i = genndx - pgenndx;
|
|
|
|
while (i--)
|
|
|
|
pz->gen = fluid_list_prepend (pz->gen, NULL);
|
|
|
|
i = modndx - pmodndx;
|
|
|
|
while (i--)
|
|
|
|
pz->mod = fluid_list_prepend (pz->mod, NULL);
|
|
|
|
}
|
|
|
|
pz = z; /* update previous zone ptr */
|
|
|
|
pgenndx = genndx;
|
|
|
|
pmodndx = modndx;
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
}
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
size -= SFBAGSIZE;
|
|
|
|
if (size != 0)
|
|
|
|
return (gerr (ErrCorr, _("Instrument chunk size mismatch")));
|
|
|
|
|
|
|
|
READW (genndx, fd);
|
|
|
|
READW (modndx, fd);
|
|
|
|
|
|
|
|
if (!pz)
|
|
|
|
{ /* in case that all are no zoners */
|
|
|
|
if (genndx > 0)
|
|
|
|
FLUID_LOG (FLUID_WARN,
|
|
|
|
_("No instrument generators and terminal index not 0"));
|
|
|
|
if (modndx > 0)
|
|
|
|
FLUID_LOG (FLUID_WARN,
|
|
|
|
_("No instrument modulators and terminal index not 0"));
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (genndx < pgenndx)
|
|
|
|
return (gerr (ErrCorr, _("Instrument generator indices not monotonic")));
|
|
|
|
if (modndx < pmodndx)
|
|
|
|
return (gerr (ErrCorr, _("Instrument modulator indices not monotonic")));
|
|
|
|
i = genndx - pgenndx;
|
|
|
|
while (i--)
|
|
|
|
pz->gen = fluid_list_prepend (pz->gen, NULL);
|
|
|
|
i = modndx - pmodndx;
|
|
|
|
while (i--)
|
|
|
|
pz->mod = fluid_list_prepend (pz->mod, NULL);
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* instrument modulator loader */
|
|
|
|
static int
|
|
|
|
load_imod (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2, *p3;
|
|
|
|
SFMod *m;
|
|
|
|
|
|
|
|
p = sf->inst;
|
|
|
|
while (p)
|
|
|
|
{ /* traverse through all inst */
|
|
|
|
p2 = ((SFInst *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse this inst's zones */
|
|
|
|
p3 = ((SFZone *) (p2->data))->mod;
|
|
|
|
while (p3)
|
|
|
|
{ /* load zone's modulators */
|
|
|
|
if ((size -= SFMODSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Instrument modulator chunk size mismatch")));
|
|
|
|
m = FLUID_NEW (SFMod);
|
|
|
|
p3->data = m;
|
|
|
|
READW (m->src, fd);
|
|
|
|
READW (m->dest, fd);
|
|
|
|
READW (m->amount, fd);
|
|
|
|
READW (m->amtsrc, fd);
|
|
|
|
READW (m->trans, fd);
|
|
|
|
p3 = fluid_list_next (p3);
|
|
|
|
}
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
}
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If there isn't even a terminal record
|
|
|
|
Hmmm, the specs say there should be one, but..
|
|
|
|
*/
|
|
|
|
if (size == 0)
|
|
|
|
return (OK);
|
|
|
|
|
|
|
|
size -= SFMODSIZE;
|
|
|
|
if (size != 0)
|
|
|
|
return (gerr (ErrCorr, _("Instrument modulator chunk size mismatch")));
|
|
|
|
FSKIP (SFMODSIZE, fd); /* terminal mod */
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* load instrument generators (see load_pgen for loading rules) */
|
|
|
|
static int
|
|
|
|
load_igen (int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
|
|
|
|
SFZone *z;
|
|
|
|
SFGen *g;
|
|
|
|
SFGenAmount genval;
|
|
|
|
unsigned short genid;
|
|
|
|
int level, skip, drop, gzone, discarded;
|
|
|
|
|
|
|
|
p = sf->inst;
|
|
|
|
while (p)
|
|
|
|
{ /* traverse through all instruments */
|
|
|
|
gzone = FALSE;
|
|
|
|
discarded = FALSE;
|
|
|
|
p2 = ((SFInst *) (p->data))->zone;
|
|
|
|
if (p2)
|
|
|
|
hz = &p2;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse this instrument's zones */
|
|
|
|
level = 0;
|
|
|
|
z = (SFZone *) (p2->data);
|
|
|
|
p3 = z->gen;
|
|
|
|
while (p3)
|
|
|
|
{ /* load zone's generators */
|
|
|
|
dup = NULL;
|
|
|
|
skip = FALSE;
|
|
|
|
drop = FALSE;
|
|
|
|
if ((size -= SFGENSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr, _("IGEN chunk size mismatch")));
|
|
|
|
|
|
|
|
READW (genid, fd);
|
|
|
|
|
|
|
|
if (genid == Gen_KeyRange)
|
|
|
|
{ /* nothing precedes */
|
|
|
|
if (level == 0)
|
|
|
|
{
|
|
|
|
level = 1;
|
|
|
|
READB (genval.range.lo, fd);
|
|
|
|
READB (genval.range.hi, fd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
else if (genid == Gen_VelRange)
|
|
|
|
{ /* only KeyRange precedes */
|
|
|
|
if (level <= 1)
|
|
|
|
{
|
|
|
|
level = 2;
|
|
|
|
READB (genval.range.lo, fd);
|
|
|
|
READB (genval.range.hi, fd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
else if (genid == Gen_SampleId)
|
|
|
|
{ /* sample is last gen */
|
|
|
|
level = 3;
|
|
|
|
READW (genval.uword, fd);
|
2017-10-21 16:32:17 +00:00
|
|
|
((SFZone *) (p2->data))->instsamp = FLUID_INT_TO_POINTER (genval.uword + 1);
|
2003-03-11 16:56:45 +00:00
|
|
|
break; /* break out of generator loop */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
level = 2;
|
|
|
|
if (gen_valid (genid))
|
|
|
|
{ /* gen valid? */
|
|
|
|
READW (genval.sword, fd);
|
|
|
|
dup = gen_inlist (genid, z->gen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!skip)
|
|
|
|
{
|
|
|
|
if (!dup)
|
|
|
|
{ /* if gen ! dup alloc new */
|
|
|
|
g = FLUID_NEW (SFGen);
|
|
|
|
p3->data = g;
|
|
|
|
g->id = genid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g = (SFGen *) (dup->data);
|
|
|
|
drop = TRUE;
|
|
|
|
}
|
|
|
|
g->amount = genval;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* skip this generator */
|
|
|
|
discarded = TRUE;
|
|
|
|
drop = TRUE;
|
|
|
|
FSKIPW (fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!drop)
|
|
|
|
p3 = fluid_list_next (p3); /* next gen */
|
|
|
|
else
|
|
|
|
SLADVREM (z->gen, p3);
|
|
|
|
|
|
|
|
} /* generator loop */
|
|
|
|
|
|
|
|
if (level == 3)
|
|
|
|
SLADVREM (z->gen, p3); /* zone has sample? */
|
|
|
|
else
|
|
|
|
{ /* its a global zone */
|
|
|
|
if (!gzone)
|
|
|
|
{
|
|
|
|
gzone = TRUE;
|
|
|
|
|
|
|
|
/* if global zone is not 1st zone, relocate */
|
|
|
|
if (*hz != p2)
|
|
|
|
{
|
|
|
|
void* save = p2->data;
|
|
|
|
FLUID_LOG (FLUID_WARN,
|
|
|
|
_("Instrument \"%s\": Global zone is not first zone"),
|
|
|
|
((SFPreset *) (p->data))->name);
|
|
|
|
SLADVREM (*hz, p2);
|
|
|
|
*hz = fluid_list_prepend (*hz, save);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* previous global zone exists, discard */
|
|
|
|
FLUID_LOG (FLUID_WARN,
|
|
|
|
_("Instrument \"%s\": Discarding invalid global zone"),
|
|
|
|
((SFInst *) (p->data))->name);
|
|
|
|
sfont_zone_delete (sf, hz, (SFZone *) (p2->data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (p3)
|
|
|
|
{ /* Kill any zones following a sample */
|
|
|
|
discarded = TRUE;
|
|
|
|
if ((size -= SFGENSIZE) < 0)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Instrument generator chunk size mismatch")));
|
|
|
|
FSKIP (SFGENSIZE, fd);
|
|
|
|
SLADVREM (z->gen, p3);
|
|
|
|
}
|
|
|
|
|
|
|
|
p2 = fluid_list_next (p2); /* next zone */
|
|
|
|
}
|
|
|
|
if (discarded)
|
|
|
|
FLUID_LOG(FLUID_WARN,
|
|
|
|
_("Instrument \"%s\": Some invalid generators were discarded"),
|
|
|
|
((SFInst *) (p->data))->name);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for those non-terminal record cases, grr! */
|
|
|
|
if (size == 0)
|
|
|
|
return (OK);
|
|
|
|
|
|
|
|
size -= SFGENSIZE;
|
|
|
|
if (size != 0)
|
|
|
|
return (gerr (ErrCorr, _("IGEN chunk size mismatch")));
|
|
|
|
FSKIP (SFGENSIZE, fd); /* terminal gen */
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sample header loader */
|
|
|
|
static int
|
|
|
|
load_shdr (unsigned int size, SFData * sf, FILE * fd)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
SFSample *p;
|
|
|
|
|
|
|
|
if (size % SFSHDRSIZE || size == 0) /* size is multiple of SHDR size? */
|
|
|
|
return (gerr (ErrCorr, _("Sample header has invalid size")));
|
|
|
|
|
|
|
|
size = size / SFSHDRSIZE - 1;
|
|
|
|
if (size == 0)
|
|
|
|
{ /* at least one sample + term record? */
|
|
|
|
FLUID_LOG (FLUID_WARN, _("File contains no samples"));
|
|
|
|
FSKIP (SFSHDRSIZE, fd);
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* load all sample headers */
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
p = FLUID_NEW (SFSample);
|
|
|
|
sf->sample = fluid_list_append (sf->sample, p);
|
|
|
|
READSTR (&p->name, fd);
|
|
|
|
READD (p->start, fd);
|
|
|
|
READD (p->end, fd); /* - end, loopstart and loopend */
|
|
|
|
READD (p->loopstart, fd); /* - will be checked and turned into */
|
|
|
|
READD (p->loopend, fd); /* - offsets in fixup_sample() */
|
|
|
|
READD (p->samplerate, fd);
|
|
|
|
READB (p->origpitch, fd);
|
|
|
|
READB (p->pitchadj, fd);
|
|
|
|
FSKIPW (fd); /* skip sample link */
|
|
|
|
READW (p->sampletype, fd);
|
|
|
|
p->samfile = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FSKIP (SFSHDRSIZE, fd); /* skip terminal shdr */
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "fixup" (inst # -> inst ptr) instrument references in preset list */
|
|
|
|
static int
|
|
|
|
fixup_pgen (SFData * sf)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2, *p3;
|
|
|
|
SFZone *z;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
p = sf->preset;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
p2 = ((SFPreset *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse this preset's zones */
|
|
|
|
z = (SFZone *) (p2->data);
|
2017-10-21 16:33:27 +00:00
|
|
|
if ((i = FLUID_POINTER_TO_INT (z->instsamp)))
|
2003-03-11 16:56:45 +00:00
|
|
|
{ /* load instrument # */
|
|
|
|
p3 = fluid_list_nth (sf->inst, i - 1);
|
|
|
|
if (!p3)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Preset %03d %03d: Invalid instrument reference"),
|
|
|
|
((SFPreset *) (p->data))->bank,
|
|
|
|
((SFPreset *) (p->data))->prenum));
|
|
|
|
z->instsamp = p3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
z->instsamp = NULL;
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
}
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "fixup" (sample # -> sample ptr) sample references in instrument list */
|
|
|
|
static int
|
|
|
|
fixup_igen (SFData * sf)
|
|
|
|
{
|
|
|
|
fluid_list_t *p, *p2, *p3;
|
|
|
|
SFZone *z;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
p = sf->inst;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
p2 = ((SFInst *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* traverse instrument's zones */
|
|
|
|
z = (SFZone *) (p2->data);
|
2017-10-21 16:33:27 +00:00
|
|
|
if ((i = FLUID_POINTER_TO_INT (z->instsamp)))
|
2003-03-11 16:56:45 +00:00
|
|
|
{ /* load sample # */
|
|
|
|
p3 = fluid_list_nth (sf->sample, i - 1);
|
|
|
|
if (!p3)
|
|
|
|
return (gerr (ErrCorr,
|
|
|
|
_("Instrument \"%s\": Invalid sample reference"),
|
|
|
|
((SFInst *) (p->data))->name));
|
|
|
|
z->instsamp = p3;
|
|
|
|
}
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
}
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert sample end, loopstart and loopend to offsets and check if valid */
|
|
|
|
static int
|
|
|
|
fixup_sample (SFData * sf)
|
|
|
|
{
|
|
|
|
fluid_list_t *p;
|
|
|
|
SFSample *sam;
|
2017-08-03 18:59:19 +00:00
|
|
|
int invalid_loops=FALSE;
|
2017-08-04 16:57:31 +00:00
|
|
|
int invalid_loopstart;
|
|
|
|
int invalid_loopend, loopend_end_mismatch;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
p = sf->sample;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
sam = (SFSample *) (p->data);
|
2017-08-04 09:18:56 +00:00
|
|
|
|
2017-08-12 13:55:47 +00:00
|
|
|
/* The SoundFont 2.4 spec defines the loopstart index as the first sample point of the loop */
|
2017-08-04 16:57:31 +00:00
|
|
|
invalid_loopstart = (sam->loopstart < sam->start) || (sam->loopstart >= sam->loopend);
|
2017-08-12 13:55:47 +00:00
|
|
|
/* while loopend is the first point AFTER the last sample of the loop.
|
2017-08-04 16:33:48 +00:00
|
|
|
* this is as it should be. however we cannot be sure whether any of sam.loopend or sam.end
|
|
|
|
* is correct. hours of thinking through this have concluded, that it would be best practice
|
|
|
|
* to mangle with loops as little as necessary by only making sure loopend is within
|
|
|
|
* sdtachunk_size. incorrect soundfont shall preferably fail loudly. */
|
2017-08-04 16:57:31 +00:00
|
|
|
invalid_loopend = (sam->loopend > sdtachunk_size) || (sam->loopstart >= sam->loopend);
|
2017-08-04 09:18:56 +00:00
|
|
|
|
2017-08-04 16:57:31 +00:00
|
|
|
loopend_end_mismatch = (sam->loopend > sam->end);
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
/* 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) */
|
2017-08-11 11:40:56 +00:00
|
|
|
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);
|
2003-03-11 16:56:45 +00:00
|
|
|
|
2017-08-11 11:40:56 +00:00
|
|
|
/* disable sample by setting all sample markers to 0 */
|
|
|
|
sam->start = sam->end = sam->loopstart = sam->loopend = 0;
|
2003-03-11 16:56:45 +00:00
|
|
|
|
2017-08-11 11:40:56 +00:00
|
|
|
return (OK);
|
|
|
|
}
|
2017-05-04 07:56:11 +00:00
|
|
|
else if (sam->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
|
2017-08-11 13:05:19 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* compressed samples get fixed up after decompression
|
|
|
|
*
|
|
|
|
* however we cant use the logic below, because uncompressed samples are stored in individual buffers
|
|
|
|
*/
|
|
|
|
}
|
2017-08-12 13:55:47 +00:00
|
|
|
else if (invalid_loopstart || invalid_loopend || loopend_end_mismatch) /* loop is fowled?? (cluck cluck :) */
|
2003-03-11 16:56:45 +00:00
|
|
|
{
|
2017-08-12 13:55:47 +00:00
|
|
|
/* though illegal, loopend may be set to loopstart to disable loop */
|
|
|
|
/* is it worth informing the user? */
|
|
|
|
invalid_loops |= (sam->loopend != sam->loopstart);
|
2017-08-03 18:59:19 +00:00
|
|
|
|
2017-08-11 11:40:56 +00:00
|
|
|
/* force incorrect loop points into the sample range, ignore padding */
|
2017-08-04 16:57:31 +00:00
|
|
|
if(invalid_loopstart)
|
2017-08-11 11:40:56 +00:00
|
|
|
{
|
2017-08-04 16:57:31 +00:00
|
|
|
FLUID_LOG (FLUID_DBG, _("Sample '%s' has unusable loop start '%d',"
|
2017-08-11 16:37:47 +00:00
|
|
|
" setting to sample start at '%d'"), sam->name, sam->loopstart, sam->start);
|
|
|
|
sam->loopstart = sam->start;
|
2017-08-11 11:40:56 +00:00
|
|
|
}
|
2017-08-04 09:18:56 +00:00
|
|
|
|
2017-08-04 16:57:31 +00:00
|
|
|
if(invalid_loopend)
|
2017-08-11 11:40:56 +00:00
|
|
|
{
|
2017-08-06 08:46:52 +00:00
|
|
|
FLUID_LOG (FLUID_DBG, _("Sample '%s' has unusable loop stop '%d',"
|
2017-08-12 13:55:47 +00:00
|
|
|
" setting to sample stop at '%d'"), sam->name, sam->loopend, sam->end);
|
|
|
|
/* since at this time sam->end points after valid sample data (will correct that few lines below),
|
|
|
|
* set loopend to that first invalid sample, since it should never be played, but instead the last
|
|
|
|
* valid sample will be played */
|
|
|
|
sam->loopend = sam->end;
|
2017-08-11 11:40:56 +00:00
|
|
|
}
|
2017-08-04 16:57:31 +00:00
|
|
|
|
|
|
|
if(loopend_end_mismatch)
|
2017-08-11 11:40:56 +00:00
|
|
|
{
|
2017-08-04 16:57:31 +00:00
|
|
|
FLUID_LOG (FLUID_DBG, _("Sample '%s' has invalid loop stop '%d',"
|
2017-08-06 08:46:52 +00:00
|
|
|
" sample stop at '%d', using it anyway"), sam->name, sam->loopend, sam->end);
|
2017-08-11 11:40:56 +00:00
|
|
|
}
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* convert sample end, loopstart, loopend to offsets from sam->start */
|
|
|
|
sam->end -= sam->start + 1; /* marks last sample, contrary to SF spec. */
|
|
|
|
sam->loopstart -= sam->start;
|
|
|
|
sam->loopend -= sam->start;
|
|
|
|
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
|
2017-08-03 18:59:19 +00:00
|
|
|
if(invalid_loops)
|
|
|
|
{
|
|
|
|
FLUID_LOG (FLUID_WARN, _("Found samples with invalid loops, audible glitches possible."));
|
|
|
|
}
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
2003-08-19 20:57:00 +00:00
|
|
|
/*=================================sfont.c========================
|
|
|
|
Smurf SoundFont Editor
|
|
|
|
================================================================*/
|
2003-03-11 16:56:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* optimum chunk area sizes (could be more optimum) */
|
|
|
|
#define PRESET_CHUNK_OPTIMUM_AREA 256
|
|
|
|
#define INST_CHUNK_OPTIMUM_AREA 256
|
|
|
|
#define SAMPLE_CHUNK_OPTIMUM_AREA 256
|
|
|
|
#define ZONE_CHUNK_OPTIMUM_AREA 256
|
|
|
|
#define MOD_CHUNK_OPTIMUM_AREA 256
|
|
|
|
#define GEN_CHUNK_OPTIMUM_AREA 256
|
|
|
|
|
2017-10-21 10:47:59 +00:00
|
|
|
static const unsigned short badgen[] = {
|
|
|
|
Gen_Unused1, Gen_Unused2, Gen_Unused3, Gen_Unused4,
|
2003-03-11 16:56:45 +00:00
|
|
|
Gen_Reserved1, Gen_Reserved2, Gen_Reserved3, 0
|
|
|
|
};
|
|
|
|
|
2017-10-21 10:47:59 +00:00
|
|
|
static const unsigned short badpgen[] = {
|
|
|
|
Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
|
2003-03-11 16:56:45 +00:00
|
|
|
Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_EndAddrCoarseOfs,
|
|
|
|
Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
|
|
|
|
Gen_EndLoopAddrCoarseOfs, Gen_SampleModes, Gen_ExclusiveClass,
|
|
|
|
Gen_OverrideRootKey, 0
|
|
|
|
};
|
|
|
|
|
2006-12-10 16:02:04 +00:00
|
|
|
/* close SoundFont file and delete a SoundFont structure */
|
2003-03-11 16:56:45 +00:00
|
|
|
void
|
|
|
|
sfont_close (SFData * sf)
|
|
|
|
{
|
2006-12-10 16:02:04 +00:00
|
|
|
fluid_list_t *p, *p2;
|
|
|
|
|
2003-03-11 16:56:45 +00:00
|
|
|
if (sf->sffd)
|
|
|
|
fclose (sf->sffd);
|
|
|
|
|
|
|
|
if (sf->fname)
|
|
|
|
free (sf->fname);
|
|
|
|
|
|
|
|
p = sf->info;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
free (p->data);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
delete_fluid_list(sf->info);
|
|
|
|
sf->info = NULL;
|
|
|
|
|
|
|
|
p = sf->preset;
|
|
|
|
while (p)
|
|
|
|
{ /* loop over presets */
|
|
|
|
p2 = ((SFPreset *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* loop over preset's zones */
|
|
|
|
sfont_free_zone (p2->data);
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
} /* free preset's zone list */
|
|
|
|
delete_fluid_list (((SFPreset *) (p->data))->zone);
|
|
|
|
FLUID_FREE (p->data); /* free preset chunk */
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
delete_fluid_list (sf->preset);
|
|
|
|
sf->preset = NULL;
|
|
|
|
|
|
|
|
p = sf->inst;
|
|
|
|
while (p)
|
|
|
|
{ /* loop over instruments */
|
|
|
|
p2 = ((SFInst *) (p->data))->zone;
|
|
|
|
while (p2)
|
|
|
|
{ /* loop over inst's zones */
|
|
|
|
sfont_free_zone (p2->data);
|
|
|
|
p2 = fluid_list_next (p2);
|
|
|
|
} /* free inst's zone list */
|
|
|
|
delete_fluid_list (((SFInst *) (p->data))->zone);
|
|
|
|
FLUID_FREE (p->data);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
2006-11-23 18:49:36 +00:00
|
|
|
delete_fluid_list (sf->inst);
|
|
|
|
sf->inst = NULL;
|
|
|
|
|
|
|
|
p = sf->sample;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
FLUID_FREE (p->data);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
2003-03-11 16:56:45 +00:00
|
|
|
delete_fluid_list (sf->sample);
|
|
|
|
sf->sample = NULL;
|
2006-11-23 18:49:36 +00:00
|
|
|
|
|
|
|
FLUID_FREE (sf);
|
2003-03-11 16:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free all elements of a zone (Preset or Instrument) */
|
|
|
|
void
|
|
|
|
sfont_free_zone (SFZone * zone)
|
|
|
|
{
|
|
|
|
fluid_list_t *p;
|
|
|
|
|
|
|
|
if (!zone)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p = zone->gen;
|
|
|
|
while (p)
|
|
|
|
{ /* Free gen chunks for this zone */
|
|
|
|
if (p->data)
|
|
|
|
FLUID_FREE (p->data);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
delete_fluid_list (zone->gen); /* free genlist */
|
|
|
|
|
|
|
|
p = zone->mod;
|
|
|
|
while (p)
|
|
|
|
{ /* Free mod chunks for this zone */
|
|
|
|
if (p->data)
|
|
|
|
FLUID_FREE (p->data);
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
delete_fluid_list (zone->mod); /* free modlist */
|
|
|
|
|
|
|
|
FLUID_FREE (zone); /* free zone chunk */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* preset sort function, first by bank, then by preset # */
|
|
|
|
int
|
|
|
|
sfont_preset_compare_func (void* a, void* b)
|
|
|
|
{
|
|
|
|
int aval, bval;
|
|
|
|
|
|
|
|
aval = (int) (((SFPreset *) a)->bank) << 16 | ((SFPreset *) a)->prenum;
|
|
|
|
bval = (int) (((SFPreset *) b)->bank) << 16 | ((SFPreset *) b)->prenum;
|
|
|
|
|
|
|
|
return (aval - bval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete zone from zone list */
|
|
|
|
void
|
|
|
|
sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone)
|
|
|
|
{
|
|
|
|
*zlist = fluid_list_remove (*zlist, (void*) zone);
|
|
|
|
sfont_free_zone (zone);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find generator in gen list */
|
|
|
|
fluid_list_t *
|
|
|
|
gen_inlist (int gen, fluid_list_t * genlist)
|
|
|
|
{ /* is generator in gen list? */
|
|
|
|
fluid_list_t *p;
|
|
|
|
|
|
|
|
p = genlist;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
if (p->data == NULL)
|
|
|
|
return (NULL);
|
|
|
|
if (gen == ((SFGen *) p->data)->id)
|
|
|
|
break;
|
|
|
|
p = fluid_list_next (p);
|
|
|
|
}
|
|
|
|
return (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check validity of instrument generator */
|
|
|
|
int
|
|
|
|
gen_valid (int gen)
|
|
|
|
{ /* is generator id valid? */
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (gen > Gen_MaxValid)
|
|
|
|
return (FALSE);
|
|
|
|
while (badgen[i] && badgen[i] != gen)
|
|
|
|
i++;
|
|
|
|
return (badgen[i] == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check validity of preset generator */
|
|
|
|
int
|
|
|
|
gen_validp (int gen)
|
|
|
|
{ /* is preset generator valid? */
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (!gen_valid (gen))
|
|
|
|
return (FALSE);
|
|
|
|
while (badpgen[i] && badpgen[i] != (unsigned short) gen)
|
|
|
|
i++;
|
|
|
|
return (badpgen[i] == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*================================util.c===========================*/
|
|
|
|
|
|
|
|
/* Logging function, returns FAIL to use as a return value in calling funcs */
|
|
|
|
int
|
|
|
|
gerr (int ev, char * fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start (args, fmt);
|
|
|
|
vprintf(fmt, args);
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
safe_fread (void *buf, int count, FILE * fd)
|
|
|
|
{
|
|
|
|
if (fread (buf, count, 1, fd) != 1)
|
|
|
|
{ /* size_t = count, nmemb = 1 */
|
|
|
|
if (feof (fd))
|
|
|
|
gerr (ErrEof, _("EOF while attemping to read %d bytes"), count);
|
|
|
|
else
|
|
|
|
FLUID_LOG (FLUID_ERR, _("File read failed"));
|
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
return (OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
safe_fseek (FILE * fd, long ofs, int whence)
|
|
|
|
{
|
|
|
|
if (fseek (fd, ofs, whence) == -1) {
|
|
|
|
FLUID_LOG (FLUID_ERR, _("File seek failed with offset = %ld and whence = %d"), ofs, whence);
|
|
|
|
return (FAIL);
|
|
|
|
}
|
|
|
|
return (OK);
|
|
|
|
}
|