mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-05-31 17:20:54 +00:00
parent
fad964344c
commit
e49b5ed201
11 changed files with 768 additions and 13 deletions
4
AUTHORS
4
AUTHORS
|
@ -122,8 +122,8 @@ summary of contributions.
|
||||||
|
|
||||||
* Tom Moebert (fluidsynth's maintainer since Jun 2017) cleaned up and refactored
|
* 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
|
fluidsynth's API and revised its documentation, added support for 24 bit sample
|
||||||
soundfonts, fixed various bugs, implemented unit tests and CI builds for
|
soundfonts, added support for DLS soundfonts, fixed various bugs, implemented
|
||||||
Windows, Linux, MacOSX.
|
unit tests and CI builds for Windows, Linux, MacOSX and BSD.
|
||||||
|
|
||||||
* Growing list of individuals who contributed bug fixes, corrections and minor features:
|
* Growing list of individuals who contributed bug fixes, corrections and minor features:
|
||||||
Nicolas Boulicault for ALSA sequencer midi.portname setting.
|
Nicolas Boulicault for ALSA sequencer midi.portname setting.
|
||||||
|
|
|
@ -64,6 +64,7 @@ option ( enable-dbus "compile DBUS support (if it is available)" on )
|
||||||
option ( enable-ipv6 "enable ipv6 support" on )
|
option ( enable-ipv6 "enable ipv6 support" on )
|
||||||
option ( enable-jack "compile JACK support (if it is available)" on )
|
option ( enable-jack "compile JACK support (if it is available)" on )
|
||||||
option ( enable-ladspa "enable LADSPA effect units" 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-libsndfile "compile libsndfile support (if it is available)" on )
|
||||||
option ( enable-midishare "compile MidiShare 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 )
|
option ( enable-opensles "compile OpenSLES support (if it is available)" off )
|
||||||
|
@ -567,7 +568,13 @@ else(NOT enable-pkgconfig)
|
||||||
set ( LADSPA 1 )
|
set ( LADSPA 1 )
|
||||||
endif ( LADSPA_SUPPORT )
|
endif ( LADSPA_SUPPORT )
|
||||||
endif ( enable-ladspa )
|
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 )
|
unset ( SDL2_SUPPORT CACHE )
|
||||||
if ( enable-sdl2 )
|
if ( enable-sdl2 )
|
||||||
pkg_check_modules ( SDL2 sdl2 )
|
pkg_check_modules ( SDL2 sdl2 )
|
||||||
|
|
|
@ -158,6 +158,12 @@ else ( WITH_READLINE )
|
||||||
message ( "Readline: no" )
|
message ( "Readline: no" )
|
||||||
endif ( WITH_READLINE )
|
endif ( WITH_READLINE )
|
||||||
|
|
||||||
|
if ( LIBINSTPATCH_SUPPORT )
|
||||||
|
message ( "libinstpatch: yes" )
|
||||||
|
else ( LIBINSTPATCH_SUPPORT )
|
||||||
|
message ( "libinstpatch: no" )
|
||||||
|
endif ( LIBINSTPATCH_SUPPORT )
|
||||||
|
|
||||||
if ( WITH_FLOAT )
|
if ( WITH_FLOAT )
|
||||||
message ( "Samples type=float: yes" )
|
message ( "Samples type=float: yes" )
|
||||||
else ( WITH_FLOAT )
|
else ( WITH_FLOAT )
|
||||||
|
|
|
@ -31,13 +31,14 @@ include_directories (
|
||||||
${CMAKE_SOURCE_DIR}/src/bindings
|
${CMAKE_SOURCE_DIR}/src/bindings
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
${CMAKE_BINARY_DIR}/include
|
${CMAKE_BINARY_DIR}/include
|
||||||
${PTHREADS_INCLUDE_DIR}
|
|
||||||
${SDL2_INCLUDE_DIR}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories (
|
include_directories (
|
||||||
SYSTEM
|
SYSTEM
|
||||||
${GLIB_INCLUDE_DIRS}
|
${GLIB_INCLUDE_DIRS}
|
||||||
|
${PTHREADS_INCLUDE_DIR}
|
||||||
|
${SDL2_INCLUDE_DIR}
|
||||||
|
${LIBINSTPATCH_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
# ************ library ************
|
# ************ library ************
|
||||||
|
@ -127,6 +128,10 @@ if ( AUFILE_SUPPORT )
|
||||||
set ( fluid_aufile_SOURCES drivers/fluid_aufile.c )
|
set ( fluid_aufile_SOURCES drivers/fluid_aufile.c )
|
||||||
endif ( AUFILE_SUPPORT )
|
endif ( AUFILE_SUPPORT )
|
||||||
|
|
||||||
|
if ( LIBINSTPATCH_SUPPORT )
|
||||||
|
set ( fluid_libinstpatch_SOURCES sfloader/fluid_instpatch.c sfloader/fluid_instpatch.h )
|
||||||
|
endif ( LIBINSTPATCH_SUPPORT )
|
||||||
|
|
||||||
if ( OPENSLES_SUPPORT )
|
if ( OPENSLES_SUPPORT )
|
||||||
set ( fluid_opensles_SOURCES drivers/fluid_opensles.c )
|
set ( fluid_opensles_SOURCES drivers/fluid_opensles.c )
|
||||||
include_directories ( ${OpenSLES_INCLUDE_DIRS} )
|
include_directories ( ${OpenSLES_INCLUDE_DIRS} )
|
||||||
|
@ -277,6 +282,7 @@ add_library ( libfluidsynth-OBJ OBJECT
|
||||||
${fluid_waveout_SOURCES}
|
${fluid_waveout_SOURCES}
|
||||||
${fluid_winmidi_SOURCES}
|
${fluid_winmidi_SOURCES}
|
||||||
${fluid_sdl2_SOURCES}
|
${fluid_sdl2_SOURCES}
|
||||||
|
${fluid_libinstpatch_SOURCES}
|
||||||
${libfluidsynth_SOURCES}
|
${libfluidsynth_SOURCES}
|
||||||
${public_HEADERS}
|
${public_HEADERS}
|
||||||
${public_main_HEADER}
|
${public_main_HEADER}
|
||||||
|
@ -355,6 +361,7 @@ target_link_libraries ( libfluidsynth
|
||||||
${OpenSLES_LIBS}
|
${OpenSLES_LIBS}
|
||||||
${OBOE_LIBS}
|
${OBOE_LIBS}
|
||||||
${LIBFLUID_LIBS}
|
${LIBFLUID_LIBS}
|
||||||
|
${LIBINSTPATCH_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
# ************ CLI program ************
|
# ************ CLI program ************
|
||||||
|
|
|
@ -154,6 +154,9 @@
|
||||||
/* Define to enable network support */
|
/* Define to enable network support */
|
||||||
#cmakedefine NETWORK_SUPPORT @NETWORK_SUPPORT@
|
#cmakedefine NETWORK_SUPPORT @NETWORK_SUPPORT@
|
||||||
|
|
||||||
|
/* libinstpatch for DLS and GIG */
|
||||||
|
#cmakedefine LIBINSTPATCH_SUPPORT @LIBINSTPATCH_SUPPORT@
|
||||||
|
|
||||||
/* libsndfile has ogg vorbis support */
|
/* libsndfile has ogg vorbis support */
|
||||||
#cmakedefine LIBSNDFILE_HASVORBIS @LIBSNDFILE_HASVORBIS@
|
#cmakedefine LIBSNDFILE_HASVORBIS @LIBSNDFILE_HASVORBIS@
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
#define GETOPT_SUPPORT 1
|
#define GETOPT_SUPPORT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBINSTPATCH_SUPPORT
|
||||||
|
#include <libinstpatch/libinstpatch.h>
|
||||||
|
#endif
|
||||||
#include "fluid_lash.h"
|
#include "fluid_lash.h"
|
||||||
|
|
||||||
#ifdef SYSTEMD_SUPPORT
|
#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);
|
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
|
* main
|
||||||
* Process initialization steps in the following order:
|
* 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);
|
lash_args = fluid_lash_extract_args(&argc, &argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SDL2_SUPPORT
|
#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());
|
fprintf(stderr, "Warning: Unable to initialize SDL2 Audio: %s", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
@ -359,6 +380,7 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
atexit(SDL_Quit);
|
atexit(SDL_Quit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -766,7 +788,7 @@ int main(int argc, char **argv)
|
||||||
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
|
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
|
||||||
for(i = arg1; i < argc; i++)
|
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)
|
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"
|
fprintf(stderr, "Failed to create the server.\n"
|
||||||
"Continuing without it.\n");
|
"Continuing without it.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SYSTEMD_SUPPORT
|
#ifdef SYSTEMD_SUPPORT
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sd_notify(0, "READY=1");
|
sd_notify(0, "READY=1");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED)
|
||||||
{
|
{
|
||||||
fluid_sfont_delete_internal(sfont);
|
fluid_defsfont_sfont_delete(sfont);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
676
src/sfloader/fluid_instpatch.c
Normal file
676
src/sfloader/fluid_instpatch.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
11
src/sfloader/fluid_instpatch.h
Normal file
11
src/sfloader/fluid_instpatch.h
Normal 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
|
|
@ -26,7 +26,7 @@ void *default_fopen(const char *path)
|
||||||
{
|
{
|
||||||
const char* msg;
|
const char* msg;
|
||||||
FILE* handle = fluid_file_open(path, &msg);
|
FILE* handle = fluid_file_open(path, &msg);
|
||||||
|
|
||||||
if(handle == NULL)
|
if(handle == NULL)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Failed to open '%s': %s", path, msg);
|
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->ftell = tell;
|
||||||
cb->fclose = close;
|
cb->fclose = close;
|
||||||
|
|
||||||
|
// NOTE: if we ever make the instpatch loader public, this may return FLUID_FAILED
|
||||||
return FLUID_OK;
|
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.
|
* Useful in low latency scenarios e.g. to allocate a pool of samples.
|
||||||
*
|
*
|
||||||
* @return Size of fluid_sample_t in bytes
|
* @return Size of fluid_sample_t in bytes
|
||||||
*
|
*
|
||||||
* @note It is recommend to zero initialize the memory before using the object.
|
* @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!
|
* @warning Do NOT allocate samples on the stack and assign them to a voice!
|
||||||
*/
|
*/
|
||||||
size_t fluid_sample_sizeof()
|
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->data);
|
||||||
FLUID_FREE(sample->data24);
|
FLUID_FREE(sample->data24);
|
||||||
}
|
}
|
||||||
|
|
||||||
sample->data = NULL;
|
sample->data = NULL;
|
||||||
sample->data24 = NULL;
|
sample->data24 = NULL;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "fluid_settings.h"
|
#include "fluid_settings.h"
|
||||||
#include "fluid_sfont.h"
|
#include "fluid_sfont.h"
|
||||||
#include "fluid_defsfont.h"
|
#include "fluid_defsfont.h"
|
||||||
|
#include "fluid_instpatch.h"
|
||||||
|
|
||||||
#ifdef TRAP_ON_FPE
|
#ifdef TRAP_ON_FPE
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
@ -463,6 +464,11 @@ fluid_synth_init(void)
|
||||||
fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */
|
fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */
|
||||||
/* Amount: 96 dB of attenuation (on the opposite channel) */
|
/* Amount: 96 dB of attenuation (on the opposite channel) */
|
||||||
fluid_mod_set_amount(&custom_balance_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */
|
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)
|
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 */
|
#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 */
|
/* allocate and add the default sfont loader */
|
||||||
loader = new_fluid_defsfloader(settings);
|
loader = new_fluid_defsfloader(settings);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue