Support Loading DLS Files (#493)

Fixes #320
This commit is contained in:
Tom M 2019-05-11 05:31:56 +02:00 committed by GitHub
parent fad964344c
commit e49b5ed201
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 768 additions and 13 deletions

View file

@ -122,8 +122,8 @@ summary of contributions.
* Tom Moebert (fluidsynth's maintainer since Jun 2017) cleaned up and refactored
fluidsynth's API and revised its documentation, added support for 24 bit sample
soundfonts, fixed various bugs, implemented unit tests and CI builds for
Windows, Linux, MacOSX.
soundfonts, added support for DLS soundfonts, fixed various bugs, implemented
unit tests and CI builds for Windows, Linux, MacOSX and BSD.
* Growing list of individuals who contributed bug fixes, corrections and minor features:
Nicolas Boulicault for ALSA sequencer midi.portname setting.

View file

@ -64,6 +64,7 @@ option ( enable-dbus "compile DBUS support (if it is available)" on )
option ( enable-ipv6 "enable ipv6 support" on )
option ( enable-jack "compile JACK support (if it is available)" on )
option ( enable-ladspa "enable LADSPA effect units" on )
option ( enable-libinstpatch "use libinstpatch (if available) to load DLS and GIG files" on )
option ( enable-libsndfile "compile libsndfile support (if it is available)" on )
option ( enable-midishare "compile MidiShare support (if it is available)" on )
option ( enable-opensles "compile OpenSLES support (if it is available)" off )
@ -567,7 +568,13 @@ else(NOT enable-pkgconfig)
set ( LADSPA 1 )
endif ( LADSPA_SUPPORT )
endif ( enable-ladspa )
unset ( LIBINSTPATCH_SUPPORT CACHE )
if ( enable-libinstpatch )
pkg_check_modules ( LIBINSTPATCH libinstpatch-1.0 )
set ( LIBINSTPATCH_SUPPORT ${LIBINSTPATCH_FOUND} )
endif ( enable-libinstpatch )
unset ( SDL2_SUPPORT CACHE )
if ( enable-sdl2 )
pkg_check_modules ( SDL2 sdl2 )

View file

@ -158,6 +158,12 @@ else ( WITH_READLINE )
message ( "Readline: no" )
endif ( WITH_READLINE )
if ( LIBINSTPATCH_SUPPORT )
message ( "libinstpatch: yes" )
else ( LIBINSTPATCH_SUPPORT )
message ( "libinstpatch: no" )
endif ( LIBINSTPATCH_SUPPORT )
if ( WITH_FLOAT )
message ( "Samples type=float: yes" )
else ( WITH_FLOAT )

View file

@ -31,13 +31,14 @@ include_directories (
${CMAKE_SOURCE_DIR}/src/bindings
${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include
${PTHREADS_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
)
include_directories (
SYSTEM
${GLIB_INCLUDE_DIRS}
${PTHREADS_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
${LIBINSTPATCH_INCLUDE_DIRS}
)
# ************ library ************
@ -127,6 +128,10 @@ if ( AUFILE_SUPPORT )
set ( fluid_aufile_SOURCES drivers/fluid_aufile.c )
endif ( AUFILE_SUPPORT )
if ( LIBINSTPATCH_SUPPORT )
set ( fluid_libinstpatch_SOURCES sfloader/fluid_instpatch.c sfloader/fluid_instpatch.h )
endif ( LIBINSTPATCH_SUPPORT )
if ( OPENSLES_SUPPORT )
set ( fluid_opensles_SOURCES drivers/fluid_opensles.c )
include_directories ( ${OpenSLES_INCLUDE_DIRS} )
@ -277,6 +282,7 @@ add_library ( libfluidsynth-OBJ OBJECT
${fluid_waveout_SOURCES}
${fluid_winmidi_SOURCES}
${fluid_sdl2_SOURCES}
${fluid_libinstpatch_SOURCES}
${libfluidsynth_SOURCES}
${public_HEADERS}
${public_main_HEADER}
@ -355,6 +361,7 @@ target_link_libraries ( libfluidsynth
${OpenSLES_LIBS}
${OBOE_LIBS}
${LIBFLUID_LIBS}
${LIBINSTPATCH_LIBRARIES}
)
# ************ CLI program ************

View file

@ -154,6 +154,9 @@
/* Define to enable network support */
#cmakedefine NETWORK_SUPPORT @NETWORK_SUPPORT@
/* libinstpatch for DLS and GIG */
#cmakedefine LIBINSTPATCH_SUPPORT @LIBINSTPATCH_SUPPORT@
/* libsndfile has ogg vorbis support */
#cmakedefine LIBSNDFILE_HASVORBIS @LIBSNDFILE_HASVORBIS@

View file

@ -29,6 +29,9 @@
#define GETOPT_SUPPORT 1
#endif
#ifdef LIBINSTPATCH_SUPPORT
#include <libinstpatch/libinstpatch.h>
#endif
#include "fluid_lash.h"
#ifdef SYSTEMD_SUPPORT
@ -297,6 +300,23 @@ fast_render_loop(fluid_settings_t *settings, fluid_synth_t *synth, fluid_player_
delete_fluid_file_renderer(renderer);
}
static int is_dls(const char *fname)
{
#ifdef LIBINSTPATCH_SUPPORT
IpatchFileHandle *fhandle = ipatch_file_identify_open(fname, NULL);
int ret = (fhandle != NULL);
if(ret)
{
ipatch_file_close(fhandle);
}
return ret;
#else
return FALSE;
#endif
}
/*
* main
* Process initialization steps in the following order:
@ -349,9 +369,10 @@ int main(int argc, char **argv)
lash_args = fluid_lash_extract_args(&argc, &argv);
#endif
#if SDL2_SUPPORT
if (SDL_Init(SDL_INIT_AUDIO) != 0)
if(SDL_Init(SDL_INIT_AUDIO) != 0)
{
fprintf(stderr, "Warning: Unable to initialize SDL2 Audio: %s", SDL_GetError());
}
@ -359,6 +380,7 @@ int main(int argc, char **argv)
{
atexit(SDL_Quit);
}
#endif
@ -766,7 +788,7 @@ int main(int argc, char **argv)
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
for(i = arg1; i < argc; i++)
{
if(fluid_is_soundfont(argv[i]))
if(fluid_is_soundfont(argv[i]) || is_dls(argv[i]))
{
if(fluid_synth_sfload(synth, argv[i], 1) == -1)
{
@ -911,11 +933,13 @@ int main(int argc, char **argv)
fprintf(stderr, "Failed to create the server.\n"
"Continuing without it.\n");
}
#ifdef SYSTEMD_SUPPORT
else
{
sd_notify(0, "READY=1");
}
#endif
}

View file

@ -104,7 +104,7 @@ fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *file
if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED)
{
fluid_sfont_delete_internal(sfont);
fluid_defsfont_sfont_delete(sfont);
return NULL;
}

View file

@ -0,0 +1,676 @@
#include "fluid_instpatch.h"
#include "fluid_list.h"
#include "fluid_sfont.h"
#include <libinstpatch/libinstpatch.h>
typedef struct _fluid_instpatch_font_t
{
char name[256];
IpatchDLS2 *dls;
fluid_list_t *preset_list; /* the presets of this soundfont */
fluid_list_t *preset_iter_cur; /* the current preset in the iteration */
} fluid_instpatch_font_t;
typedef struct _fluid_instpatch_preset_t
{
fluid_instpatch_font_t *parent_sfont;
IpatchSF2VoiceCache *cache;
/* pointer to name of the preset, duplicated from item, allocated by glib */
char *name;
int bank;
int prog;
} fluid_instpatch_preset_t;
// private struct for storing additional data for each instpatch voice
typedef struct _instpatch_voice_user_data
{
/* pointer to the sample store that holds the PCM */
IpatchSampleStoreCache *sample_store;
/* pointer to a preallocated fluid_sample_t that we can use during noteon for this voice */
fluid_sample_t *sample;
} fluid_instpatch_voice_user_data_t;
/* max voices per instrument (voices exceeding this will not sound) */
enum
{
MAX_INST_VOICES = 128,
};
void fluid_instpatch_init(void)
{
ipatch_init();
}
static int delete_fluid_instpatch(fluid_instpatch_font_t *pfont);
static const char *fluid_instpatch_sfont_get_name(fluid_sfont_t *sfont);
static fluid_preset_t *fluid_instpatch_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum);
/* sfloader callback to get the name of a preset */
static const char *
fluid_instpatch_preset_get_name(fluid_preset_t *preset)
{
fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset);
return preset_data->name;
}
/* sfloader callback to get the bank number of a preset */
static int
fluid_instpatch_preset_get_banknum(fluid_preset_t *preset)
{
fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset);
return preset_data->bank;
}
/* sfloader callback to get the preset number of a preset */
static int
fluid_instpatch_preset_get_num(fluid_preset_t *preset)
{
fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset);
return preset_data->prog;
}
static void fluid_instpatch_iteration_start(fluid_sfont_t *sfont)
{
fluid_instpatch_font_t *pfont = fluid_sfont_get_data(sfont);
pfont->preset_iter_cur = pfont->preset_list;
}
static fluid_preset_t *fluid_instpatch_iteration_next(fluid_sfont_t *sfont)
{
fluid_instpatch_font_t *pfont = fluid_sfont_get_data(sfont);
fluid_preset_t *preset = fluid_list_get(pfont->preset_iter_cur);
pfont->preset_iter_cur = fluid_list_next(pfont->preset_iter_cur);
return preset;
}
/* sfloader callback for a noteon event */
static int
fluid_instpatch_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel)
{
/* voice index array */
guint16 voice_indices[MAX_INST_VOICES];
int sel_values[IPATCH_SF2_VOICE_CACHE_MAX_SEL_VALUES];
fluid_mod_t *fmod = g_alloca(fluid_mod_sizeof());
fluid_voice_t *flvoice;
fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset);
int i, voice_count, voice_num, ret = FLUID_FAILED;
GSList *p;
/* lookup the voice cache that we've created on loading */
IpatchSF2VoiceCache *cache = preset_data->cache;
/* loading and caching the instrument could have failed though */
if(FLUID_UNLIKELY(cache == NULL))
{
return FLUID_FAILED;
}
g_object_ref(cache);
for(i = 0; i < cache->sel_count; i++)
{
IpatchSF2VoiceSelInfo *sel_info = &cache->sel_info[i];
switch(sel_info->type)
{
case IPATCH_SF2_VOICE_SEL_NOTE:
sel_values[i] = key;
break;
case IPATCH_SF2_VOICE_SEL_VELOCITY:
sel_values[i] = vel;
break;
default:
/* match any; NOTE: according to documentation this should be IPATCH_SF2_VOICE_SEL_WILDCARD */
sel_values[i] = -1;
break;
}
}
voice_count = ipatch_sf2_voice_cache_select(cache, sel_values, voice_indices, MAX_INST_VOICES);
/* loop over matching voice indexes */
for(voice_num = 0; voice_num < voice_count; voice_num++)
{
IpatchSF2GenArray *gen_array;
fluid_sample_t *fsample;
IpatchSF2Voice *voice = IPATCH_SF2_VOICE_CACHE_GET_VOICE(cache, voice_indices[voice_num]);
if(!voice->sample_store)
{
/* For ROM and other non-readable samples */
continue;
}
fsample = ((fluid_instpatch_voice_user_data_t *)voice->user_data)->sample;
ret = fluid_sample_set_sound_data(fsample,
ipatch_sample_store_cache_get_location(IPATCH_SAMPLE_STORE_CACHE(voice->sample_store)),
NULL,
voice->sample_size,
voice->rate,
FALSE
);
if(FLUID_UNLIKELY(ret == FLUID_FAILED))
{
FLUID_LOG(FLUID_ERR, "fluid_sample_set_sound_data() failed");
goto error_rec;
}
ret = fluid_sample_set_loop(fsample, voice->loop_start, voice->loop_end);
if(FLUID_UNLIKELY(ret == FLUID_FAILED))
{
FLUID_LOG(FLUID_ERR, "fluid_sample_set_loop() failed");
goto error_rec;
}
ret = fluid_sample_set_pitch(fsample, voice->root_note, voice->fine_tune);
if(FLUID_UNLIKELY(ret == FLUID_FAILED))
{
FLUID_LOG(FLUID_ERR, "fluid_sample_set_pitch() failed");
goto error_rec;
}
/* allocate the FluidSynth voice */
flvoice = fluid_synth_alloc_voice(synth, fsample, chan, key, vel);
if(flvoice == NULL)
{
ret = FLUID_FAILED;
goto error_rec;
}
/* set only those generator parameters that are set */
gen_array = &voice->gen_array;
for(i = 0; i < IPATCH_SF2_GEN_COUNT; i++)
{
if(IPATCH_SF2_GEN_ARRAY_TEST_FLAG(gen_array, i))
{
fluid_voice_gen_set(flvoice, i, (float)(gen_array->values[i].sword));
}
}
p = voice->mod_list;
while(p)
{
static const unsigned int mod_mask =
(IPATCH_SF2_MOD_MASK_DIRECTION | IPATCH_SF2_MOD_MASK_POLARITY | IPATCH_SF2_MOD_MASK_TYPE);
IpatchSF2Mod *mod = p->data;
fluid_mod_set_dest(fmod, mod->dest);
fluid_mod_set_source1(fmod,
mod->src & IPATCH_SF2_MOD_MASK_CONTROL,
((mod->src & mod_mask) >> IPATCH_SF2_MOD_SHIFT_DIRECTION)
| ((mod->src & IPATCH_SF2_MOD_MASK_CC) ? FLUID_MOD_CC : 0));
fluid_mod_set_source2(fmod,
mod->amtsrc & IPATCH_SF2_MOD_MASK_CONTROL,
((mod->amtsrc & mod_mask) >> IPATCH_SF2_MOD_SHIFT_DIRECTION)
| ((mod->amtsrc & IPATCH_SF2_MOD_MASK_CC) ? FLUID_MOD_CC : 0));
fluid_mod_set_amount(fmod, mod->amount);
fluid_voice_add_mod(flvoice, fmod, FLUID_VOICE_OVERWRITE);
p = p->next;
}
fluid_synth_start_voice(synth, flvoice);
/* sample store reference taken over by fsample structure */
}
ret = FLUID_OK;
error_rec:
g_object_unref(cache);
return ret;
}
/* sfloader callback to get a patch file name */
static const char *
fluid_instpatch_sfont_get_name(fluid_sfont_t *sfont)
{
fluid_instpatch_font_t *sfont_data = fluid_sfont_get_data(sfont);
return sfont_data->name;
}
static void delete_fluid_instpatch_preset(fluid_instpatch_preset_t *preset_data)
{
fluid_return_if_fail(preset_data != NULL);
/* -- remove voice cache reference */
g_object_unref(preset_data->cache);
g_free(preset_data->name);
FLUID_FREE(preset_data);
}
static void fluid_instpatch_preset_free(fluid_preset_t *preset)
{
fluid_return_if_fail(preset != NULL);
delete_fluid_instpatch_preset(fluid_preset_get_data(preset));
delete_fluid_preset(preset);
}
/* sfloader callback to get a preset (instrument) by bank and preset number */
static fluid_preset_t *
fluid_instpatch_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum)
{
fluid_instpatch_font_t *sfont_data = fluid_sfont_get_data(sfont);
fluid_preset_t *preset;
fluid_list_t *list;
for(list = sfont_data->preset_list; list != NULL; list = fluid_list_next(list))
{
preset = (fluid_preset_t *)fluid_list_get(list);
if((fluid_preset_get_banknum(preset) == bank) && (fluid_preset_get_num(preset) == prenum))
{
return preset;
}
}
return NULL;
}
static fluid_instpatch_voice_user_data_t *new_fluid_instpatch_voice_user_data(IpatchSampleStoreCache *sample_store)
{
fluid_instpatch_voice_user_data_t *data = FLUID_NEW(fluid_instpatch_voice_user_data_t);
fluid_sample_t *sample = new_fluid_sample();
if(data == NULL || sample == NULL)
{
FLUID_FREE(data);
delete_fluid_sample(sample);
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
data->sample = sample;
/* Keep sample store cached by doing a dummy open */
ipatch_sample_store_cache_open(sample_store);
data->sample_store = sample_store;
return data;
}
static void fluid_instpatch_on_voice_user_data_destroy(gpointer user_data)
{
fluid_instpatch_voice_user_data_t *data = user_data;
delete_fluid_sample(data->sample);
ipatch_sample_store_cache_close(data->sample_store);
FLUID_FREE(data);
}
static IpatchSF2VoiceCache *convert_dls_to_sf2_instrument(fluid_instpatch_font_t *patchfont, IpatchDLS2Inst *item, const char **err)
{
static const char no_conv[] = "Unable to find a voice cache converter for this type";
static const char conv_fail[] = "Failed to convert DLS inst to SF2 voices";
static const char cache_fail[] = "Failed to cache DLS inst to SF2 voices";
static const char oom[] = "Out of memory";
IpatchConverter *conv;
IpatchSF2VoiceCache *cache;
int i, count;
/* create SF2 voice cache converter */
conv = ipatch_create_converter(G_OBJECT_TYPE(item), IPATCH_TYPE_SF2_VOICE_CACHE);
/* no SF2 voice cache converter for this item type? */
if(conv == NULL)
{
*err = no_conv;
return NULL;
}
cache = ipatch_sf2_voice_cache_new(NULL, 0);
if(cache == NULL)
{
*err = oom;
g_object_unref(conv);
return NULL;
}
ipatch_converter_add_input(conv, G_OBJECT(item));
ipatch_converter_add_output(conv, G_OBJECT(cache));
if(!ipatch_converter_convert(conv, NULL))
{
*err = conv_fail;
g_object_unref(cache);
g_object_unref(conv);
return NULL;
}
g_clear_object(&conv);
/* Use voice->user_data to close open cached stores */
cache->voice_user_data_destroy = fluid_instpatch_on_voice_user_data_destroy;
/* loop over voices and load sample data into RAM */
count = cache->voices->len;
for(i = 0; i < count; i++)
{
IpatchSF2Voice *voice = &g_array_index(cache->voices, IpatchSF2Voice, i);
if(!ipatch_sf2_voice_cache_sample_data(voice, NULL))
{
*err = cache_fail;
g_object_unref(cache);
return NULL;
}
if((voice->user_data = new_fluid_instpatch_voice_user_data(IPATCH_SAMPLE_STORE_CACHE(voice->sample_store))) == NULL)
{
*err = oom;
g_object_unref(cache);
return NULL;
}
}
/* !! caller takes over cache reference */
return cache;
}
fluid_instpatch_font_t *new_fluid_instpatch(fluid_sfont_t *sfont, const fluid_file_callbacks_t *fcbs, const char *filename)
{
fluid_instpatch_font_t *patchfont = NULL;
GError *err = NULL;
IpatchDLSReader *reader = NULL;
IpatchDLSFile *file = NULL;
IpatchFileHandle *handle = NULL;
fluid_return_val_if_fail(filename != NULL, NULL);
if((patchfont = FLUID_NEW(fluid_instpatch_font_t)) == NULL)
{
return NULL;
}
FLUID_MEMSET(patchfont, 0, sizeof(*patchfont));
FLUID_STRNCPY(&patchfont->name[0], filename, sizeof(patchfont->name));
/* open a file, we get a reference */
if((file = ipatch_dls_file_new()) == NULL)
{
FLUID_FREE(patchfont);
return NULL;
}
/* ipatch_file_open() references the file again */
if((handle = ipatch_file_open(IPATCH_FILE(file), filename, "r", &err)) == NULL)
{
FLUID_LOG(FLUID_ERR, "ipatch_file_open() failed with error: '%s'", ipatch_gerror_message(err));
g_object_unref(file);
FLUID_FREE(patchfont);
return NULL;
}
/* get rid of the reference we own, we dont need it any longer */
g_clear_object(&file);
/* open a reader, this gives us a reference */
if((reader = ipatch_dls_reader_new(handle)) == NULL)
{
ipatch_file_close(handle);
FLUID_FREE(patchfont);
return NULL;
}
patchfont->dls = ipatch_dls_reader_load(reader, &err);
/* unref the reader directly afterwards, not needed any longer */
g_clear_object(&reader);
if(patchfont->dls == NULL)
{
FLUID_LOG(FLUID_ERR, "ipatch_dls_reader_new() failed with error: '%s'", ipatch_gerror_message(err));
// reader has already been unrefed, i.e. no need to call ipatch_file_close()
FLUID_FREE(patchfont);
return NULL;
}
else
{
/* at this point everything is owned by the IpatchDLS2*, no need for custom cleanups any longer */
IpatchIter iter;
IpatchDLS2Inst *inst;
gboolean success = ipatch_container_init_iter(IPATCH_CONTAINER(patchfont->dls), &iter, IPATCH_TYPE_DLS2_INST);
if(success == FALSE)
{
goto bad_luck;
}
inst = ipatch_dls2_inst_first(&iter);
if(inst == NULL)
{
FLUID_LOG(FLUID_ERR, "A soundfont file was accepted by libinstpatch, but it doesn't contain a single instrument. Dropping the whole file.");
goto bad_luck;
}
/* loop over instruments, convert to sf2 voices, create fluid_samples, cache all presets in a list */
do
{
fluid_preset_t *preset;
IpatchSF2VoiceCache *cache;
int bank, prog;
const char *err = NULL;
ipatch_dls2_inst_get_midi_locale(inst, &bank, &prog);
if((cache = convert_dls_to_sf2_instrument(patchfont, inst, &err)) == NULL)
{
FLUID_LOG(FLUID_WARN, "Unable to use DLS instrument bank %d , prog %d : %s.", bank, prog, err);
}
else
{
int is_percussion = (ipatch_item_get_flags(inst) & IPATCH_DLS2_INST_PERCUSSION) != 0;
fluid_instpatch_preset_t *preset_data = FLUID_NEW(fluid_instpatch_preset_t);
if(preset_data == NULL)
{
g_object_unref(inst);
g_object_unref(cache);
FLUID_LOG(FLUID_ERR, "Out of memory");
goto bad_luck;
}
FLUID_MEMSET(preset_data, 0, sizeof(*preset_data));
preset_data->parent_sfont = patchfont;
preset_data->cache = cache;
/* save name, bank and preset for quick lookup */
preset_data->bank = is_percussion * 128 + bank;
preset_data->prog = prog;
g_object_get(inst, "name", &preset_data->name, NULL);
preset = new_fluid_preset(sfont,
fluid_instpatch_preset_get_name,
fluid_instpatch_preset_get_banknum,
fluid_instpatch_preset_get_num,
fluid_instpatch_preset_noteon,
fluid_instpatch_preset_free);
if(preset == NULL)
{
delete_fluid_instpatch_preset(preset_data);
FLUID_LOG(FLUID_ERR, "Out of memory");
goto bad_luck;
}
else
{
fluid_preset_set_data(preset, preset_data);
patchfont->preset_list = fluid_list_append(patchfont->preset_list, preset);
}
}
inst = ipatch_dls2_inst_next(&iter);
}
while(inst);
return patchfont;
}
bad_luck:
delete_fluid_instpatch(patchfont);
return NULL;
}
static int delete_fluid_instpatch(fluid_instpatch_font_t *pfont)
{
guint16 voice_indices[MAX_INST_VOICES];
int sel_values[IPATCH_SF2_VOICE_CACHE_MAX_SEL_VALUES];
fluid_list_t *list;
fluid_return_val_if_fail(pfont != NULL, FLUID_OK);
/* loop through all fluid samples and return error if any sample is currently in use for rendering */
for(list = pfont->preset_list; list; list = fluid_list_next(list))
{
fluid_instpatch_preset_t *preset_data = fluid_preset_get_data((fluid_preset_t *)fluid_list_get(list));
int i, voice_count;
/* lookup the voice cache that we've created on loading */
IpatchSF2VoiceCache *cache = preset_data->cache;
if(cache == NULL)
{
continue;
}
g_object_ref(cache);
for(i = 0; i < cache->sel_count; i++)
{
sel_values[i] = -1;
}
voice_count = ipatch_sf2_voice_cache_select(cache, sel_values, voice_indices, MAX_INST_VOICES);
for(i = 0; i < voice_count; i++)
{
IpatchSF2Voice *voice = IPATCH_SF2_VOICE_CACHE_GET_VOICE(cache, voice_indices[i]);
fluid_sample_t *fsample = ((fluid_instpatch_voice_user_data_t *)voice->user_data)->sample;
if(fsample->refcount != 0)
{
g_object_unref(cache);
return FLUID_FAILED;
}
}
g_object_unref(cache);
}
for(list = pfont->preset_list; list; list = fluid_list_next(list))
{
fluid_preset_delete_internal((fluid_preset_t *)fluid_list_get(list));
}
delete_fluid_list(pfont->preset_list);
// also unrefs IpatchDLSFile and IpatchFileHandle
g_object_unref(pfont->dls);
FLUID_FREE(pfont);
return FLUID_OK;
}
static int fluid_instpatch_sfont_delete(fluid_sfont_t *sfont)
{
int ret;
fluid_return_val_if_fail(sfont != NULL, -1);
if((ret = delete_fluid_instpatch(fluid_sfont_get_data(sfont))) == FLUID_OK)
{
delete_fluid_sfont(sfont);
}
return ret;
}
static fluid_sfont_t *fluid_instpatch_loader_load(fluid_sfloader_t *loader, const char *filename)
{
fluid_instpatch_font_t *patchfont = NULL;
fluid_sfont_t *sfont = NULL;
sfont = new_fluid_sfont(fluid_instpatch_sfont_get_name,
fluid_instpatch_sfont_get_preset,
fluid_instpatch_iteration_start,
fluid_instpatch_iteration_next,
fluid_instpatch_sfont_delete);
if(sfont == NULL)
{
return NULL;
}
if((patchfont = new_fluid_instpatch(sfont, &loader->file_callbacks, filename)) == NULL)
{
delete_fluid_sfont(sfont);
return NULL;
}
fluid_sfont_set_data(sfont, patchfont);
return sfont;
}
fluid_sfloader_t *new_fluid_instpatch_loader(fluid_settings_t *settings)
{
fluid_sfloader_t *loader;
fluid_return_val_if_fail(settings != NULL, NULL);
loader = new_fluid_sfloader(fluid_instpatch_loader_load, delete_fluid_sfloader);
if(loader == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
fluid_sfloader_set_data(loader, settings);
return loader;
}

View file

@ -0,0 +1,11 @@
#ifndef _FLUID_INSTPATCH_H
#define _FLUID_INSTPATCH_H
#include "fluid_sfont.h"
#include "fluid_settings.h"
void fluid_instpatch_init(void);
fluid_sfloader_t *new_fluid_instpatch_loader(fluid_settings_t *settings);
#endif // _FLUID_INSTPATCH_H

View file

@ -26,7 +26,7 @@ void *default_fopen(const char *path)
{
const char* msg;
FILE* handle = fluid_file_open(path, &msg);
if(handle == NULL)
{
FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Failed to open '%s': %s", path, msg);
@ -190,6 +190,7 @@ int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
cb->ftell = tell;
cb->fclose = close;
// NOTE: if we ever make the instpatch loader public, this may return FLUID_FAILED
return FLUID_OK;
}
@ -523,9 +524,9 @@ delete_fluid_sample(fluid_sample_t *sample)
* Useful in low latency scenarios e.g. to allocate a pool of samples.
*
* @return Size of fluid_sample_t in bytes
*
*
* @note It is recommend to zero initialize the memory before using the object.
*
*
* @warning Do NOT allocate samples on the stack and assign them to a voice!
*/
size_t fluid_sample_sizeof()
@ -583,7 +584,7 @@ fluid_sample_set_sound_data(fluid_sample_t *sample,
FLUID_FREE(sample->data);
FLUID_FREE(sample->data24);
}
sample->data = NULL;
sample->data24 = NULL;

View file

@ -25,6 +25,7 @@
#include "fluid_settings.h"
#include "fluid_sfont.h"
#include "fluid_defsfont.h"
#include "fluid_instpatch.h"
#ifdef TRAP_ON_FPE
#define _GNU_SOURCE
@ -463,6 +464,11 @@ fluid_synth_init(void)
fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */
/* Amount: 96 dB of attenuation (on the opposite channel) */
fluid_mod_set_amount(&custom_balance_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */
#ifdef LIBINSTPATCH_SUPPORT
/* defer libinstpatch init to fluid_instpatch.c to avoid #include "libinstpatch.h" */
fluid_instpatch_init();
#endif
}
static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t *synth)
@ -816,6 +822,20 @@ new_fluid_synth(fluid_settings_t *settings)
#endif /* LADSPA */
}
/* allocate and add the dls sfont loader */
#ifdef LIBINSTPATCH_SUPPORT
loader = new_fluid_instpatch_loader(settings);
if(loader == NULL)
{
FLUID_LOG(FLUID_WARN, "Failed to create the instpatch SoundFont loader");
}
else
{
fluid_synth_add_sfloader(synth, loader);
}
#endif
/* allocate and add the default sfont loader */
loader = new_fluid_defsfloader(settings);