mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-19 07:50:49 +00:00
Merge branch 'master' into 2.1-testing
This commit is contained in:
commit
2cef5b0587
14 changed files with 479 additions and 677 deletions
|
@ -204,7 +204,6 @@ if ( WIN32 )
|
|||
|
||||
# Check presence of MS include files
|
||||
check_include_file ( windows.h HAVE_WINDOWS_H )
|
||||
check_include_file ( io.h HAVE_IO_H )
|
||||
check_include_file ( dsound.h HAVE_DSOUND_H )
|
||||
check_include_files ( "windows.h;mmsystem.h" HAVE_MMSYSTEM_H )
|
||||
|
||||
|
@ -350,6 +349,18 @@ if ( enable-profiling )
|
|||
endif ( )
|
||||
|
||||
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPT_FLAGS}" )
|
||||
|
||||
if ( CMAKE_VERSION VERSION_GREATER "3.6.0" )
|
||||
find_program( CLANG_TIDY
|
||||
NAMES "clang-tidy"
|
||||
DOC "Path to clang-tidy executable" )
|
||||
|
||||
if ( CLANG_TIDY )
|
||||
message ( STATUS "Found clang-tidy" )
|
||||
set ( CMAKE_C_CLANG_TIDY "clang-tidy" )
|
||||
endif ( CLANG_TIDY )
|
||||
endif ( CMAKE_VERSION VERSION_GREATER "3.6.0" )
|
||||
|
||||
endif ( enable-profiling )
|
||||
|
||||
unset ( ENABLE_TRAPONFPE CACHE )
|
||||
|
@ -383,22 +394,6 @@ if ( CMAKE_BUILD_TYPE MATCHES "Debug" )
|
|||
set ( DEBUG 1 )
|
||||
endif ( CMAKE_BUILD_TYPE MATCHES "Debug" )
|
||||
|
||||
if ( CMAKE_VERSION VERSION_GREATER "3.6.0" )
|
||||
find_program( CLANG_TIDY
|
||||
NAMES "clang-tidy"
|
||||
DOC "Path to clang-tidy executable" )
|
||||
|
||||
if ( CLANG_TIDY )
|
||||
message ( STATUS "Found clang-tidy" )
|
||||
# whenever clang-tidy is available, use it to automatically add braces after ever "make"
|
||||
if ( WITH_PROFILING )
|
||||
set ( CMAKE_C_CLANG_TIDY "clang-tidy" )
|
||||
else ( WITH_PROFILING )
|
||||
set ( CMAKE_C_CLANG_TIDY "clang-tidy;-checks=-*,readability-braces-*;-format-style=file" )
|
||||
endif ( WITH_PROFILING )
|
||||
endif ( CLANG_TIDY )
|
||||
endif ( CMAKE_VERSION VERSION_GREATER "3.6.0" )
|
||||
|
||||
# Additional targets to perform clang-format/clang-tidy
|
||||
# Get all project files
|
||||
file(GLOB_RECURSE
|
||||
|
|
|
@ -379,6 +379,6 @@ ExternalProject_Add(gentables
|
|||
DOWNLOAD_COMMAND ""
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/gentables
|
||||
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gentables
|
||||
INSTALL_COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gentables/make_tables${CMAKE_EXECUTABLE_SUFFIX} "${CMAKE_BINARY_DIR}/"
|
||||
INSTALL_COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gentables/make_tables.exe "${CMAKE_BINARY_DIR}/"
|
||||
)
|
||||
add_dependencies(libfluidsynth-OBJ gentables)
|
||||
|
|
|
@ -43,9 +43,6 @@
|
|||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#cmakedefine HAVE_INTTYPES_H @HAVE_INTTYPES_H@
|
||||
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#cmakedefine HAVE_IO_H @HAVE_IO_H@
|
||||
|
||||
/* whether or not we are supporting lash */
|
||||
#cmakedefine HAVE_LASH @HAVE_LASH@
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ project (gentables C)
|
|||
|
||||
set ( CMAKE_BUILD_TYPE Debug )
|
||||
|
||||
# hardcode ".exe" as suffix to the binary, else in case of cross-platform cross-compiling the calling cmake will not know the suffix used here and fail to find the binary
|
||||
set ( CMAKE_EXECUTABLE_SUFFIX ".exe" )
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
||||
|
|
|
@ -81,6 +81,41 @@ static int fluid_midi_file_get_division(fluid_midi_file *midifile);
|
|||
* MIDIFILE
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if a file is a MIDI file.
|
||||
* @param filename Path to the file to check
|
||||
* @return TRUE if it could be a MIDI file, FALSE otherwise
|
||||
*
|
||||
* The current implementation only checks for the "MThd" header in the file.
|
||||
* It is useful only to distinguish between SoundFont and MIDI files.
|
||||
*/
|
||||
int fluid_is_midifile(const char *filename)
|
||||
{
|
||||
FILE *fp = FLUID_FOPEN(filename, "rb");
|
||||
uint32_t id;
|
||||
int retcode = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if(fp == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(FLUID_FREAD(&id, sizeof(id), 1, fp) != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
retcode = (id == FLUID_FOURCC('M', 'T', 'h', 'd'));
|
||||
}
|
||||
while(0);
|
||||
|
||||
FLUID_FCLOSE(fp);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new MIDI file handle for parsing an already-loaded MIDI file.
|
||||
* @internal
|
||||
|
@ -1597,7 +1632,7 @@ new_fluid_player(fluid_synth_t *synth)
|
|||
|
||||
fluid_settings_getint(synth->settings, "player.reset-synth", &i);
|
||||
fluid_player_handle_reset_synth(player, NULL, i);
|
||||
|
||||
|
||||
fluid_settings_callback_int(synth->settings, "player.reset-synth",
|
||||
fluid_player_handle_reset_synth, player);
|
||||
|
||||
|
|
|
@ -1105,24 +1105,30 @@ new_fluid_preset_zone(char *name)
|
|||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_preset_zone
|
||||
* delete list of modulators.
|
||||
*/
|
||||
void
|
||||
delete_fluid_preset_zone(fluid_preset_zone_t *zone)
|
||||
static void delete_fluid_list_mod(fluid_mod_t *mod)
|
||||
{
|
||||
fluid_mod_t *mod, *tmp;
|
||||
fluid_list_t *list;
|
||||
|
||||
fluid_return_if_fail(zone != NULL);
|
||||
|
||||
mod = zone->mod;
|
||||
|
||||
fluid_mod_t *tmp;
|
||||
while(mod) /* delete the modulators */
|
||||
{
|
||||
tmp = mod;
|
||||
mod = mod->next;
|
||||
delete_fluid_mod(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_preset_zone
|
||||
*/
|
||||
void
|
||||
delete_fluid_preset_zone(fluid_preset_zone_t *zone)
|
||||
{
|
||||
fluid_list_t *list;
|
||||
|
||||
fluid_return_if_fail(zone != NULL);
|
||||
|
||||
delete_fluid_list_mod(zone->mod);
|
||||
|
||||
for(list = zone->voice_zone; list != NULL; list = fluid_list_next(list))
|
||||
{
|
||||
|
@ -1187,52 +1193,226 @@ static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone
|
|||
}
|
||||
|
||||
/*
|
||||
* fluid_preset_zone_import_sfont
|
||||
* fluid_zone_gen_import_sfont
|
||||
* Imports generators from sfzone to gen and range.
|
||||
* @param gen, pointer on destination generators table.
|
||||
* @param range, pointer on destination range generators.
|
||||
* @param sfzone, pointer on soundfont zone generators.
|
||||
*/
|
||||
int
|
||||
fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
|
||||
static void
|
||||
fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, SFZone *sfzone)
|
||||
{
|
||||
fluid_list_t *r;
|
||||
SFGen *sfgen;
|
||||
SFInst *sfinst;
|
||||
int count;
|
||||
|
||||
for(count = 0, r = sfzone->gen; r != NULL; count++)
|
||||
for( r = sfzone->gen; r != NULL; )
|
||||
{
|
||||
sfgen = (SFGen *)fluid_list_get(r);
|
||||
|
||||
switch(sfgen->id)
|
||||
{
|
||||
case GEN_KEYRANGE:
|
||||
zone->range.keylo = sfgen->amount.range.lo;
|
||||
zone->range.keyhi = sfgen->amount.range.hi;
|
||||
range->keylo = sfgen->amount.range.lo;
|
||||
range->keyhi = sfgen->amount.range.hi;
|
||||
break;
|
||||
|
||||
case GEN_VELRANGE:
|
||||
zone->range.vello = sfgen->amount.range.lo;
|
||||
zone->range.velhi = sfgen->amount.range.hi;
|
||||
range->vello = sfgen->amount.range.lo;
|
||||
range->velhi = sfgen->amount.range.hi;
|
||||
break;
|
||||
|
||||
case GEN_ATTENUATION:
|
||||
/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
|
||||
* preset and instrument level */
|
||||
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||
zone->gen[sfgen->id].flags = GEN_SET;
|
||||
gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||
gen[sfgen->id].flags = GEN_SET;
|
||||
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;
|
||||
gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
||||
gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
}
|
||||
|
||||
r = fluid_list_next(r);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_zone_mod_source_import_sfont
|
||||
* Imports source information from sf_source to src and flags.
|
||||
* @param src, pointer on destination modulator source.
|
||||
* @param flags, pointer on destination modulator flags.
|
||||
* @param sf_source, soundfont modulator source.
|
||||
* @return return TRUE if success, FALSE if source type is unknow.
|
||||
*/
|
||||
static int
|
||||
fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, unsigned short sf_source)
|
||||
{
|
||||
int type;
|
||||
unsigned char flags_dest; /* destination flags */
|
||||
|
||||
/* sources */
|
||||
*src = sf_source & 127; /* index of source, seven-bit value, SF2.01 section 8.2, page 50 */
|
||||
|
||||
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
||||
flags_dest = 0;
|
||||
if(sf_source & (1 << 7))
|
||||
{
|
||||
flags_dest |= FLUID_MOD_CC;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_dest |= FLUID_MOD_GC;
|
||||
}
|
||||
|
||||
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
||||
if(sf_source & (1 << 8))
|
||||
{
|
||||
flags_dest |= FLUID_MOD_NEGATIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_dest |= FLUID_MOD_POSITIVE;
|
||||
}
|
||||
|
||||
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
||||
if(sf_source & (1 << 9))
|
||||
{
|
||||
flags_dest |= FLUID_MOD_BIPOLAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_dest |= FLUID_MOD_UNIPOLAR;
|
||||
}
|
||||
|
||||
/* modulator source types: SF2.01 section 8.2.1 page 52 */
|
||||
type = sf_source >> 10;
|
||||
type &= 63; /* type is a 6-bit value */
|
||||
|
||||
if(type == 0)
|
||||
{
|
||||
flags_dest |= FLUID_MOD_LINEAR;
|
||||
}
|
||||
else if(type == 1)
|
||||
{
|
||||
flags_dest |= FLUID_MOD_CONCAVE;
|
||||
}
|
||||
else if(type == 2)
|
||||
{
|
||||
flags_dest |= FLUID_MOD_CONVEX;
|
||||
}
|
||||
else if(type == 3)
|
||||
{
|
||||
flags_dest |= FLUID_MOD_SWITCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
*flags = flags_dest;
|
||||
/* This shouldn't happen - unknown type! */
|
||||
return FALSE;
|
||||
}
|
||||
*flags = flags_dest;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_zone_mod_import_sfont
|
||||
* Imports modulators from sfzone to mod list.
|
||||
* @param mod, pointer on modulator list to return.
|
||||
* @param sfzone, pointer on soundfont zone.
|
||||
* @return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||
*/
|
||||
static int
|
||||
fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
|
||||
{
|
||||
fluid_list_t *r;
|
||||
int count;
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
for(count = 0, r = sfzone->mod; r != NULL; count++)
|
||||
{
|
||||
|
||||
SFMod *mod_src = (SFMod *)fluid_list_get(r);
|
||||
fluid_mod_t *mod_dest = new_fluid_mod();
|
||||
|
||||
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;
|
||||
|
||||
/* *** Source *** */
|
||||
if(!fluid_zone_mod_source_import_sfont(&mod_dest->src1, &mod_dest->flags1, mod_src->src))
|
||||
{
|
||||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
/* *** Dest *** */
|
||||
mod_dest->dest = mod_src->dest; /* index of controlled generator */
|
||||
|
||||
/* *** Amount source *** */
|
||||
if(!fluid_zone_mod_source_import_sfont(&mod_dest->src2, &mod_dest->flags2, mod_src->amtsrc))
|
||||
{
|
||||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* *** Transform *** */
|
||||
/* SF2.01 only uses the 'linear' transform (0).
|
||||
* Deactivate the modulator by setting the amount to 0 in any other case.
|
||||
*/
|
||||
if(mod_src->trans != 0)
|
||||
{
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
*mod = mod_dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
fluid_mod_t *last_mod = *mod;
|
||||
|
||||
/* Find the end of the list */
|
||||
while(last_mod->next != NULL)
|
||||
{
|
||||
last_mod = last_mod->next;
|
||||
}
|
||||
|
||||
last_mod->next = mod_dest;
|
||||
}
|
||||
|
||||
r = fluid_list_next(r);
|
||||
} /* foreach modulator */
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_preset_zone_import_sfont
|
||||
*/
|
||||
int
|
||||
fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
|
||||
{
|
||||
/* import the generators */
|
||||
fluid_zone_gen_import_sfont(zone->gen, &zone->range, sfzone);
|
||||
|
||||
if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
|
||||
{
|
||||
sfinst = sfzone->instsamp->data;
|
||||
SFInst *sfinst = sfzone->instsamp->data;
|
||||
|
||||
zone->inst = find_inst_by_idx(defsfont, sfinst->idx);
|
||||
|
||||
|
@ -1253,182 +1433,7 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_
|
|||
}
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
for(count = 0, r = sfzone->mod; r != NULL; count++)
|
||||
{
|
||||
|
||||
SFMod *mod_src = (SFMod *)fluid_list_get(r);
|
||||
fluid_mod_t *mod_dest = new_fluid_mod();
|
||||
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;
|
||||
|
||||
/* *** Source *** */
|
||||
mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
|
||||
mod_dest->flags1 = 0;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
{
|
||||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* *** Dest *** */
|
||||
mod_dest->dest = mod_src->dest; /* index of controlled generator */
|
||||
|
||||
/* *** Amount source *** */
|
||||
mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, p.50 */
|
||||
mod_dest->flags2 = 0;
|
||||
|
||||
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
||||
if(mod_src->amtsrc & (1 << 7))
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_CC;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_GC;
|
||||
}
|
||||
|
||||
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
||||
if(mod_src->amtsrc & (1 << 8))
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_POSITIVE;
|
||||
}
|
||||
|
||||
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
||||
if(mod_src->amtsrc & (1 << 9))
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
|
||||
}
|
||||
|
||||
/* 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
|
||||
{
|
||||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* *** Transform *** */
|
||||
/* SF2.01 only uses the 'linear' transform (0).
|
||||
* Deactivate the modulator by setting the amount to 0 in any other case.
|
||||
*/
|
||||
if(mod_src->trans != 0)
|
||||
{
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
r = fluid_list_next(r);
|
||||
} /* foreach modulator */
|
||||
|
||||
return FLUID_OK;
|
||||
return fluid_zone_mod_import_sfont(&zone->mod, sfzone);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1661,18 +1666,9 @@ new_fluid_inst_zone(char *name)
|
|||
void
|
||||
delete_fluid_inst_zone(fluid_inst_zone_t *zone)
|
||||
{
|
||||
fluid_mod_t *mod, *tmp;
|
||||
|
||||
fluid_return_if_fail(zone != NULL);
|
||||
|
||||
mod = zone->mod;
|
||||
|
||||
while(mod) /* delete the modulators */
|
||||
{
|
||||
tmp = mod;
|
||||
mod = mod->next;
|
||||
delete_fluid_mod(tmp);
|
||||
}
|
||||
delete_fluid_list_mod(zone->mod);
|
||||
|
||||
FLUID_FREE(zone->name);
|
||||
FLUID_FREE(zone);
|
||||
|
@ -1693,43 +1689,8 @@ fluid_inst_zone_next(fluid_inst_zone_t *zone)
|
|||
int
|
||||
fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
|
||||
{
|
||||
fluid_list_t *r;
|
||||
SFGen *sfgen;
|
||||
int count;
|
||||
|
||||
for(count = 0, r = sfzone->gen; r != NULL; count++)
|
||||
{
|
||||
sfgen = (SFGen *)fluid_list_get(r);
|
||||
|
||||
switch(sfgen->id)
|
||||
{
|
||||
case GEN_KEYRANGE:
|
||||
inst_zone->range.keylo = sfgen->amount.range.lo;
|
||||
inst_zone->range.keyhi = sfgen->amount.range.hi;
|
||||
break;
|
||||
|
||||
case GEN_VELRANGE:
|
||||
inst_zone->range.vello = sfgen->amount.range.lo;
|
||||
inst_zone->range.velhi = sfgen->amount.range.hi;
|
||||
break;
|
||||
|
||||
case GEN_ATTENUATION:
|
||||
/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
|
||||
* preset and instrument level */
|
||||
inst_zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||
inst_zone->gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* FIXME: some generators have an unsigned word amount value but
|
||||
i don't know which ones */
|
||||
inst_zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
||||
inst_zone->gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
}
|
||||
|
||||
r = fluid_list_next(r);
|
||||
}
|
||||
/* import the generators */
|
||||
fluid_zone_gen_import_sfont(inst_zone->gen, &inst_zone->range, sfzone);
|
||||
|
||||
/* FIXME */
|
||||
/* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */
|
||||
|
@ -1743,182 +1704,7 @@ fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid
|
|||
}
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
for(count = 0, r = sfzone->mod; r != NULL; count++)
|
||||
{
|
||||
SFMod *mod_src = (SFMod *)fluid_list_get(r);
|
||||
int type;
|
||||
fluid_mod_t *mod_dest;
|
||||
|
||||
mod_dest = new_fluid_mod();
|
||||
|
||||
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;
|
||||
|
||||
/* *** Source *** */
|
||||
mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
|
||||
mod_dest->flags1 = 0;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
{
|
||||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* *** Dest *** */
|
||||
mod_dest->dest = mod_src->dest; /* index of controlled generator */
|
||||
|
||||
/* *** Amount source *** */
|
||||
mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, page 50 */
|
||||
mod_dest->flags2 = 0;
|
||||
|
||||
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
||||
if(mod_src->amtsrc & (1 << 7))
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_CC;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_GC;
|
||||
}
|
||||
|
||||
/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
|
||||
if(mod_src->amtsrc & (1 << 8))
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_POSITIVE;
|
||||
}
|
||||
|
||||
/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
|
||||
if(mod_src->amtsrc & (1 << 9))
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
|
||||
}
|
||||
|
||||
/* 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
|
||||
{
|
||||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* *** Transform *** */
|
||||
/* SF2.01 only uses the 'linear' transform (0).
|
||||
* Deactivate the modulator by setting the amount to 0 in any other case.
|
||||
*/
|
||||
if(mod_src->trans != 0)
|
||||
{
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
inst_zone->mod = mod_dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
fluid_mod_t *last_mod = inst_zone->mod;
|
||||
|
||||
/* Find the end of the list */
|
||||
while(last_mod->next != NULL)
|
||||
{
|
||||
last_mod = last_mod->next;
|
||||
}
|
||||
|
||||
last_mod->next = mod_dest;
|
||||
}
|
||||
|
||||
r = fluid_list_next(r);
|
||||
} /* foreach modulator */
|
||||
|
||||
return FLUID_OK;
|
||||
return fluid_zone_mod_import_sfont(&inst_zone->mod, sfzone);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -60,8 +60,10 @@ struct _fluid_samplecache_entry_t
|
|||
static fluid_list_t *samplecache_list = NULL;
|
||||
static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
|
||||
|
||||
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
|
||||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
|
||||
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start,
|
||||
unsigned int sample_end, int sample_type, time_t mtime);
|
||||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start,
|
||||
unsigned int sample_end, int sample_type, time_t mtime);
|
||||
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
|
||||
|
||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
|
||||
|
@ -75,14 +77,20 @@ int fluid_samplecache_load(SFData *sf,
|
|||
{
|
||||
fluid_samplecache_entry_t *entry;
|
||||
int ret;
|
||||
time_t mtime;
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
|
||||
entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type);
|
||||
if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
|
||||
{
|
||||
mtime = 0;
|
||||
}
|
||||
|
||||
entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
|
||||
|
||||
if(entry == NULL)
|
||||
{
|
||||
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type);
|
||||
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
|
||||
|
||||
if(entry == NULL)
|
||||
{
|
||||
|
@ -180,7 +188,8 @@ unlock_exit:
|
|||
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
|
||||
unsigned int sample_start,
|
||||
unsigned int sample_end,
|
||||
int sample_type)
|
||||
int sample_type,
|
||||
time_t mtime)
|
||||
{
|
||||
fluid_samplecache_entry_t *entry;
|
||||
|
||||
|
@ -202,12 +211,6 @@ static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
|
|||
goto error_exit;
|
||||
}
|
||||
|
||||
if(fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||
entry->modification_time = 0;
|
||||
}
|
||||
|
||||
entry->sf_samplepos = sf->samplepos;
|
||||
entry->sf_samplesize = sf->samplesize;
|
||||
entry->sf_sample24pos = sf->sample24pos;
|
||||
|
@ -215,6 +218,7 @@ static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
|
|||
entry->sample_start = sample_start;
|
||||
entry->sample_end = sample_end;
|
||||
entry->sample_type = sample_type;
|
||||
entry->modification_time = mtime;
|
||||
|
||||
entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type,
|
||||
&entry->sample_data, &entry->sample_data24);
|
||||
|
@ -244,18 +248,12 @@ static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
|
|||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
|
||||
unsigned int sample_start,
|
||||
unsigned int sample_end,
|
||||
int sample_type)
|
||||
int sample_type,
|
||||
time_t mtime)
|
||||
{
|
||||
time_t mtime;
|
||||
fluid_list_t *entry_list;
|
||||
fluid_samplecache_entry_t *entry;
|
||||
|
||||
if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||
mtime = 0;
|
||||
}
|
||||
|
||||
entry_list = samplecache_list;
|
||||
|
||||
while(entry_list)
|
||||
|
|
|
@ -34,76 +34,79 @@
|
|||
Borrowed from Smurf SoundFont Editor by Josh Green
|
||||
=================================================================*/
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
/* FOURCC definitions */
|
||||
#define RIFF_FCC FLUID_FOURCC('R','I','F','F')
|
||||
#define LIST_FCC FLUID_FOURCC('L','I','S','T')
|
||||
#define SFBK_FCC FLUID_FOURCC('s','f','b','k')
|
||||
#define INFO_FCC FLUID_FOURCC('I','N','F','O')
|
||||
#define SDTA_FCC FLUID_FOURCC('s','d','t','a')
|
||||
#define PDTA_FCC FLUID_FOURCC('p','d','t','a') /* info/sample/preset */
|
||||
|
||||
/* sf file chunk IDs */
|
||||
enum
|
||||
{
|
||||
RIFF_ID,
|
||||
LIST_ID,
|
||||
SFBK_ID,
|
||||
INFO_ID,
|
||||
SDTA_ID,
|
||||
PDTA_ID, /* info/sample/preset */
|
||||
#define IFIL_FCC FLUID_FOURCC('i','f','i','l')
|
||||
#define ISNG_FCC FLUID_FOURCC('i','s','n','g')
|
||||
#define INAM_FCC FLUID_FOURCC('I','N','A','M')
|
||||
#define IROM_FCC FLUID_FOURCC('i','r','o','m') /* info ids (1st byte of info strings) */
|
||||
#define IVER_FCC FLUID_FOURCC('i','v','e','r')
|
||||
#define ICRD_FCC FLUID_FOURCC('I','C','R','D')
|
||||
#define IENG_FCC FLUID_FOURCC('I','E','N','G')
|
||||
#define IPRD_FCC FLUID_FOURCC('I','P','R','D') /* more info ids */
|
||||
#define ICOP_FCC FLUID_FOURCC('I','C','O','P')
|
||||
#define ICMT_FCC FLUID_FOURCC('I','C','M','T')
|
||||
#define ISFT_FCC FLUID_FOURCC('I','S','F','T') /* and yet more info ids */
|
||||
|
||||
IFIL_ID,
|
||||
ISNG_ID,
|
||||
INAM_ID,
|
||||
IROM_ID, /* info ids (1st byte of info strings) */
|
||||
IVER_ID,
|
||||
ICRD_ID,
|
||||
IENG_ID,
|
||||
IPRD_ID, /* more info ids */
|
||||
ICOP_ID,
|
||||
ICMT_ID,
|
||||
ISFT_ID, /* and yet more info ids */
|
||||
#define SNAM_FCC FLUID_FOURCC('s','n','a','m')
|
||||
#define SMPL_FCC FLUID_FOURCC('s','m','p','l') /* sample ids */
|
||||
#define PHDR_FCC FLUID_FOURCC('p','h','d','r')
|
||||
#define PBAG_FCC FLUID_FOURCC('p','b','a','g')
|
||||
#define PMOD_FCC FLUID_FOURCC('p','m','o','d')
|
||||
#define PGEN_FCC FLUID_FOURCC('p','g','e','n') /* preset ids */
|
||||
#define IHDR_FCC FLUID_FOURCC('i','n','s','t')
|
||||
#define IBAG_FCC FLUID_FOURCC('i','b','a','g')
|
||||
#define IMOD_FCC FLUID_FOURCC('i','m','o','d')
|
||||
#define IGEN_FCC FLUID_FOURCC('i','g','e','n') /* instrument ids */
|
||||
#define SHDR_FCC FLUID_FOURCC('s','h','d','r') /* sample info */
|
||||
#define SM24_FCC FLUID_FOURCC('s','m','2','4')
|
||||
|
||||
SNAM_ID,
|
||||
SMPL_ID, /* sample ids */
|
||||
PHDR_ID,
|
||||
PBAG_ID,
|
||||
PMOD_ID,
|
||||
PGEN_ID, /* preset ids */
|
||||
IHDR_ID,
|
||||
IBAG_ID,
|
||||
IMOD_ID,
|
||||
IGEN_ID, /* instrument ids */
|
||||
SHDR_ID, /* sample info */
|
||||
SM24_ID,
|
||||
|
||||
UNKN_ID
|
||||
};
|
||||
/* Set when the FCC code is unknown */
|
||||
#define UNKN_ID FLUID_N_ELEMENTS(idlist)
|
||||
|
||||
/*
|
||||
* This declares a char array containing the SF2 chunk identifiers. This
|
||||
* array is being accessed like an uint32 below to simplify id comparison.
|
||||
* To make sure it is suitably aligned for uint32 access, we must wrap it
|
||||
* inside a union along with a uint32 telling the compiler to align it
|
||||
* for integer access and avoiding undefined behaviour.
|
||||
* This basically is the C89 equivalent to what is written in C11 as:
|
||||
* alignas(uint32_t) static const char idlist[] = {};
|
||||
*
|
||||
* See: EXP36-C. Do not cast pointers into more strictly aligned pointer
|
||||
* types - SEI CERT C Coding Standard
|
||||
* This declares a uint32_t array containing the SF2 chunk identifiers.
|
||||
*/
|
||||
static const union fluid_idlist
|
||||
static const uint32_t idlist[] =
|
||||
{
|
||||
/*
|
||||
* Cannot be char c[ ], because in C89, arrays wraped in unions
|
||||
* must have a fixed size. Otherwise the size of the union would depend
|
||||
* on the initialization of its first member, which results in
|
||||
* different sizes for different instances of the same union type.
|
||||
*/
|
||||
char c[116];
|
||||
uint32_t i;
|
||||
} idlist = {"RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"
|
||||
"ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdrsm24"
|
||||
};
|
||||
RIFF_FCC,
|
||||
LIST_FCC,
|
||||
SFBK_FCC,
|
||||
INFO_FCC,
|
||||
SDTA_FCC,
|
||||
PDTA_FCC,
|
||||
|
||||
IFIL_FCC,
|
||||
ISNG_FCC,
|
||||
INAM_FCC,
|
||||
IROM_FCC,
|
||||
IVER_FCC,
|
||||
ICRD_FCC,
|
||||
IENG_FCC,
|
||||
IPRD_FCC,
|
||||
ICOP_FCC,
|
||||
ICMT_FCC,
|
||||
ISFT_FCC,
|
||||
|
||||
SNAM_FCC,
|
||||
SMPL_FCC,
|
||||
PHDR_FCC,
|
||||
PBAG_FCC,
|
||||
PMOD_FCC,
|
||||
PGEN_FCC,
|
||||
IHDR_FCC,
|
||||
IBAG_FCC,
|
||||
IMOD_FCC,
|
||||
IGEN_FCC,
|
||||
SHDR_FCC,
|
||||
SM24_FCC
|
||||
};
|
||||
|
||||
/* generator types */
|
||||
typedef enum
|
||||
|
@ -206,8 +209,6 @@ static const unsigned short invalid_preset_gen[] =
|
|||
};
|
||||
|
||||
|
||||
#define CHNKIDSTR(id) &idlist.c[(id - 1) * 4]
|
||||
|
||||
/* sfont file chunk sizes */
|
||||
#define SF_PHDR_SIZE (38)
|
||||
#define SF_BAG_SIZE (4)
|
||||
|
@ -323,6 +324,56 @@ static void delete_zone(SFZone *zone);
|
|||
static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
|
||||
static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
|
||||
|
||||
/**
|
||||
* Check if a file is a SoundFont file.
|
||||
* @param filename Path to the file to check
|
||||
* @return TRUE if it could be a SoundFont, FALSE otherwise
|
||||
*
|
||||
* @note The current implementation only checks for the "RIFF" and "sfbk" headers in
|
||||
* the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
|
||||
*/
|
||||
int fluid_is_soundfont(const char *filename)
|
||||
{
|
||||
FILE *fp = FLUID_FOPEN(filename, "rb");
|
||||
uint32_t fcc;
|
||||
int retcode = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if(fp == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(fcc != RIFF_FCC)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(FLUID_FSEEK(fp, 4, SEEK_CUR))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
retcode = (fcc == SFBK_FCC);
|
||||
}
|
||||
while(0);
|
||||
|
||||
FLUID_FCLOSE(fp);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a SoundFont file and parse it's contents into a SFData structure.
|
||||
*
|
||||
|
@ -512,11 +563,10 @@ void fluid_sffile_close(SFData *sf)
|
|||
static int chunkid(uint32_t id)
|
||||
{
|
||||
unsigned int i;
|
||||
const uint32_t *p = &idlist.i;
|
||||
|
||||
for(i = 0; i < sizeof(idlist) / sizeof(idlist.i); i++, p += 1)
|
||||
for(i = 0; i < FLUID_N_ELEMENTS(idlist); i++)
|
||||
{
|
||||
if(*p == id)
|
||||
if(idlist[i] == id)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -532,7 +582,7 @@ static int load_header(SFData *sf)
|
|||
|
||||
READCHUNK(sf, &chunk); /* load RIFF chunk */
|
||||
|
||||
if(chunkid(chunk.id) != RIFF_ID)
|
||||
if(chunk.id != RIFF_FCC)
|
||||
{
|
||||
/* error if not RIFF */
|
||||
FLUID_LOG(FLUID_ERR, "Not a RIFF file");
|
||||
|
@ -541,7 +591,7 @@ static int load_header(SFData *sf)
|
|||
|
||||
READID(sf, &chunk.id); /* load file ID */
|
||||
|
||||
if(chunkid(chunk.id) != SFBK_ID)
|
||||
if(chunk.id != SFBK_FCC)
|
||||
{
|
||||
/* error if not SFBK_ID */
|
||||
FLUID_LOG(FLUID_ERR, "Not a SoundFont file");
|
||||
|
@ -560,7 +610,7 @@ static int load_header(SFData *sf)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(chunkid(chunk.id) != INFO_ID)
|
||||
if(chunk.id != INFO_FCC)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk");
|
||||
return FALSE;
|
||||
|
@ -577,7 +627,7 @@ static int load_header(SFData *sf)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(chunkid(chunk.id) != SDTA_ID)
|
||||
if(chunk.id != SDTA_FCC)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk");
|
||||
return FALSE;
|
||||
|
@ -594,7 +644,7 @@ static int load_header(SFData *sf)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(chunkid(chunk.id) != PDTA_ID)
|
||||
if(chunk.id != PDTA_FCC)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk");
|
||||
return FALSE;
|
||||
|
@ -639,7 +689,7 @@ static int read_listchunk(SFData *sf, SFChunk *chunk)
|
|||
{
|
||||
READCHUNK(sf, chunk); /* read list chunk */
|
||||
|
||||
if(chunkid(chunk->id) != LIST_ID) /* error if ! list chunk */
|
||||
if(chunk->id != LIST_FCC) /* error if ! list chunk */
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse");
|
||||
return FALSE;
|
||||
|
@ -653,8 +703,11 @@ static int read_listchunk(SFData *sf, SFChunk *chunk)
|
|||
static int process_info(SFData *sf, int size)
|
||||
{
|
||||
SFChunk chunk;
|
||||
unsigned char id;
|
||||
char *item;
|
||||
union
|
||||
{
|
||||
char *chr;
|
||||
uint32_t *fcc;
|
||||
} item;
|
||||
unsigned short ver;
|
||||
|
||||
while(size > 0)
|
||||
|
@ -662,9 +715,7 @@ static int process_info(SFData *sf, int size)
|
|||
READCHUNK(sf, &chunk);
|
||||
size -= 8;
|
||||
|
||||
id = chunkid(chunk.id);
|
||||
|
||||
if(id == IFIL_ID)
|
||||
if(chunk.id == IFIL_FCC)
|
||||
{
|
||||
/* sound font version chunk? */
|
||||
if(chunk.size != 4)
|
||||
|
@ -705,7 +756,7 @@ static int process_info(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(id == IVER_ID)
|
||||
else if(chunk.id == IVER_FCC)
|
||||
{
|
||||
/* ROM version chunk? */
|
||||
if(chunk.size != 4)
|
||||
|
@ -719,34 +770,35 @@ static int process_info(SFData *sf, int size)
|
|||
READW(sf, ver);
|
||||
sf->romver.minor = ver;
|
||||
}
|
||||
else if(id != UNKN_ID)
|
||||
else if(chunkid(chunk.id) != UNKN_ID)
|
||||
{
|
||||
if((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
|
||||
if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",
|
||||
&chunk.id, chunk.size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* alloc for chunk id and da chunk */
|
||||
if(!(item = FLUID_MALLOC(chunk.size + 1)))
|
||||
/* alloc for chunk fcc and da chunk */
|
||||
if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1)))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */
|
||||
sf->info = fluid_list_append(sf->info, item);
|
||||
sf->info = fluid_list_append(sf->info, item.fcc);
|
||||
|
||||
*(unsigned char *)item = id;
|
||||
/* save chunk fcc and update pointer to data value */
|
||||
*item.fcc++ = chunk.id;
|
||||
|
||||
if(sf->fcbs->fread(&item[1], chunk.size, sf->sffd) == FLUID_FAILED)
|
||||
if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* force terminate info item (don't forget uint8 info ID) */
|
||||
*(item + chunk.size) = '\0';
|
||||
/* force terminate info item */
|
||||
item.chr[chunk.size] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -779,7 +831,7 @@ static int process_sdta(SFData *sf, unsigned int size)
|
|||
READCHUNK(sf, &chunk);
|
||||
size -= 8;
|
||||
|
||||
if(chunkid(chunk.id) != SMPL_ID)
|
||||
if(chunk.id != SMPL_FCC)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");
|
||||
return FALSE;
|
||||
|
@ -812,7 +864,7 @@ static int process_sdta(SFData *sf, unsigned int size)
|
|||
READCHUNK(sf, &chunk);
|
||||
size -= 8;
|
||||
|
||||
if(chunkid(chunk.id) == SM24_ID)
|
||||
if(chunk.id == SM24_FCC)
|
||||
{
|
||||
int sm24size, sdtahalfsize;
|
||||
|
||||
|
@ -852,29 +904,24 @@ ret:
|
|||
|
||||
static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)
|
||||
{
|
||||
unsigned int id;
|
||||
const char *expstr;
|
||||
|
||||
expstr = CHNKIDSTR(expid); /* in case we need it */
|
||||
|
||||
READCHUNK(sf, chunk);
|
||||
*size -= 8;
|
||||
|
||||
if((id = chunkid(chunk->id)) != expid)
|
||||
if(chunk->id != expid)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", expstr);
|
||||
FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", &expid);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(chunk->size % reclen) /* valid chunk size? */
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", expstr, reclen);
|
||||
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", &expid, reclen);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if((*size -= chunk->size) < 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", expstr);
|
||||
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", &expid);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -885,7 +932,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
{
|
||||
SFChunk chunk;
|
||||
|
||||
if(!pdtahelper(sf, PHDR_ID, SF_PHDR_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -895,7 +942,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, PBAG_ID, SF_BAG_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -905,7 +952,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, PMOD_ID, SF_MOD_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -915,7 +962,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, PGEN_ID, SF_GEN_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -925,7 +972,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, IHDR_ID, SF_IHDR_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -935,7 +982,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, IBAG_ID, SF_BAG_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -945,7 +992,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, IMOD_ID, SF_MOD_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -955,7 +1002,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, IGEN_ID, SF_GEN_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -965,7 +1012,7 @@ static int process_pdta(SFData *sf, int size)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pdtahelper(sf, SHDR_ID, SF_SHDR_SIZE, &chunk, &size))
|
||||
if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -1902,7 +1902,7 @@ fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len,
|
|||
int bank = 0, prog, channels;
|
||||
double tunedata[128];
|
||||
int keys[128];
|
||||
char name[17];
|
||||
char name[17]={0};
|
||||
int note, frac, frac2;
|
||||
uint8_t chksum;
|
||||
int i, count, index;
|
||||
|
@ -1973,7 +1973,8 @@ fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len,
|
|||
}
|
||||
|
||||
*resptr++ = prog;
|
||||
FLUID_STRNCPY(resptr, name, 16);
|
||||
/* copy 16 ASCII characters (potentially not null terminated) to the sysex buffer */
|
||||
FLUID_MEMCPY(resptr, name, 16);
|
||||
resptr += 16;
|
||||
|
||||
for(i = 0; i < 128; i++)
|
||||
|
|
|
@ -1162,24 +1162,23 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
|
|||
* iteration of the audio cycle (which would probably be feasible if
|
||||
* the synth was made in silicon).
|
||||
*
|
||||
* The update is done in three steps:
|
||||
* The update is done in two steps:
|
||||
*
|
||||
* - step 1: first, we look for all the modulators that have the changed
|
||||
* controller as a source. This will yield a list of generators that
|
||||
* will be changed because of the controller event.
|
||||
* controller as a source. This will yield a generator that will be changed
|
||||
* because of the controller event.
|
||||
*
|
||||
* - step 2: For every changed generator, calculate its new value. This is the
|
||||
* - step 2: For this generator, calculate its new value. This is the
|
||||
* sum of its original value plus the values of all the attached modulators.
|
||||
* The generator flag is set to indicate the parameters must be updated.
|
||||
*
|
||||
* - step 3: We need to avoid the risk to call 'fluid_voice_update_param' several
|
||||
* This avoid the risk to call 'fluid_voice_update_param' several
|
||||
* times for the same generator if several modulators have that generator as
|
||||
* destination. So every changed generators are updated only once
|
||||
* destination. So every changed generators are updated only once.
|
||||
*/
|
||||
|
||||
/* bit table for each generator being updated. The bits are packed in variables
|
||||
Each variable have NBR_BIT_BY_VAR bits represented by NBR_BIT_BY_VAR_LN2.
|
||||
The size of the table is the number of variables: SIZE_UPDATED_GEN.
|
||||
The size of the table is the number of variables: SIZE_UPDATED_GEN_BIT.
|
||||
|
||||
Note: In this implementation NBR_BIT_BY_VAR_LN2 is set to 5 (convenient for 32 bits cpu)
|
||||
but this could be set to 6 for 64 bits cpu.
|
||||
|
@ -1200,7 +1199,7 @@ int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
|
|||
uint32_t gen;
|
||||
fluid_real_t modval;
|
||||
|
||||
/* registered bits table of updated generators */
|
||||
/* Clears registered bits table of updated generators */
|
||||
uint32_t updated_gen_bit[SIZE_UPDATED_GEN_BIT] = {0};
|
||||
|
||||
/* printf("Chan=%d, CC=%d, Src=%d, Val=%d\n", voice->channel->channum, cc, ctrl, val); */
|
||||
|
@ -1210,36 +1209,36 @@ int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
|
|||
mod = &voice->mod[i];
|
||||
|
||||
/* step 1: find all the modulators that have the changed controller
|
||||
as input source. When ctrl is -1 all modulators's destination
|
||||
as input source. When ctrl is -1 all modulators destination
|
||||
are updated */
|
||||
if(ctrl < 0 || fluid_mod_has_source(mod, cc, ctrl))
|
||||
{
|
||||
gen = fluid_mod_get_dest(mod);
|
||||
modval = 0.0;
|
||||
|
||||
/* step 2: for every changed modulator, calculate the modulation
|
||||
* value of its associated generator */
|
||||
for(k = 0; k < voice->mod_count; k++)
|
||||
/* Skip if this generator has already been updated */
|
||||
if(!is_gen_updated(updated_gen_bit, gen))
|
||||
{
|
||||
if(fluid_mod_has_dest(&voice->mod[k], gen))
|
||||
{
|
||||
modval += fluid_mod_get_value(&voice->mod[k], voice);
|
||||
}
|
||||
}
|
||||
modval = 0.0;
|
||||
|
||||
fluid_gen_set_mod(&voice->gen[gen], modval);
|
||||
/* set the bit that indicates this generator is updated */
|
||||
set_gen_updated(updated_gen_bit, gen);
|
||||
}
|
||||
}
|
||||
|
||||
/* step 3: now recalculate the parameter values that are derived from the
|
||||
generator */
|
||||
for(gen = 0; gen < GEN_LAST; gen++)
|
||||
{
|
||||
if (is_gen_updated(updated_gen_bit, gen))
|
||||
{
|
||||
fluid_voice_update_param(voice, gen);
|
||||
/* step 2: for every attached modulator, calculate the modulation
|
||||
* value for the generator gen */
|
||||
for(k = 0; k < voice->mod_count; k++)
|
||||
{
|
||||
if(fluid_mod_has_dest(&voice->mod[k], gen))
|
||||
{
|
||||
modval += fluid_mod_get_value(&voice->mod[k], voice);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_gen_set_mod(&voice->gen[gen], modval);
|
||||
|
||||
/* now recalculate the parameter values that are derived from the
|
||||
generator */
|
||||
fluid_voice_update_param(voice, gen);
|
||||
|
||||
/* set the bit that indicates this generator is updated */
|
||||
set_gen_updated(updated_gen_bit, gen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -274,71 +274,6 @@ fluid_error()
|
|||
return fluid_errbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is a MIDI file.
|
||||
* @param filename Path to the file to check
|
||||
* @return TRUE if it could be a MIDI file, FALSE otherwise
|
||||
*
|
||||
* The current implementation only checks for the "MThd" header in the file.
|
||||
* It is useful only to distinguish between SoundFont and MIDI files.
|
||||
*/
|
||||
int
|
||||
fluid_is_midifile(const char *filename)
|
||||
{
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
char id[4];
|
||||
|
||||
if(fp == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fread((void *) id, 1, 4, fp) != 4)
|
||||
{
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return FLUID_STRNCMP(id, "MThd", 4) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is a SoundFont file.
|
||||
* @param filename Path to the file to check
|
||||
* @return TRUE if it could be a SoundFont, FALSE otherwise
|
||||
*
|
||||
* @note The current implementation only checks for the "RIFF" and "sfbk" headers in
|
||||
* the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
|
||||
*/
|
||||
int
|
||||
fluid_is_soundfont(const char *filename)
|
||||
{
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
char riff_id[4], sfbk_id[4];
|
||||
|
||||
if(fp == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((fread((void *) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
|
||||
(fseek(fp, 4, SEEK_CUR) != 0) ||
|
||||
(fread((void *) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
|
||||
{
|
||||
goto error_rec;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
|
||||
(FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
|
||||
|
||||
error_rec:
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspend the execution of the current thread for the specified amount of time.
|
||||
* @param milliseconds to wait.
|
||||
|
|
|
@ -77,6 +77,14 @@
|
|||
#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)
|
||||
#define FLUID_LE16TOH(x) GINT16_FROM_LE(x)
|
||||
|
||||
#if FLUID_IS_BIG_ENDIAN
|
||||
#define FLUID_FOURCC(_a, _b, _c, _d) \
|
||||
(uint32_t)(((uint32_t)(_a) << 24) | ((uint32_t)(_b) << 16) | ((uint32_t)(_c) << 8) | (uint32_t)(_d))
|
||||
#else
|
||||
#define FLUID_FOURCC(_a, _b, _c, _d) \
|
||||
(uint32_t)(((uint32_t)(_d) << 24) | ((uint32_t)(_c) << 16) | ((uint32_t)(_b) << 8) | (uint32_t)(_a))
|
||||
#endif
|
||||
|
||||
|
||||
#define fluid_return_if_fail(cond) \
|
||||
if(cond) \
|
||||
|
|
|
@ -106,10 +106,6 @@
|
|||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
@ -265,7 +261,7 @@ typedef FILE *fluid_file;
|
|||
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) \
|
||||
do { strncpy(_dst,_src,_n); \
|
||||
(_dst)[(_n)-1]=0; \
|
||||
(_dst)[(_n)-1]='\0'; \
|
||||
}while(0)
|
||||
|
||||
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
|
||||
|
|
|
@ -21,6 +21,8 @@ int main(void)
|
|||
// no sfont loaded
|
||||
TEST_ASSERT(fluid_synth_sfcount(synth) == 0);
|
||||
|
||||
TEST_ASSERT(fluid_is_soundfont(TEST_SOUNDFONT) == TRUE);
|
||||
|
||||
// load a sfont to synth
|
||||
TEST_SUCCESS(id = fluid_synth_sfload(synth, TEST_SOUNDFONT, 1));
|
||||
// one sfont loaded
|
||||
|
|
Loading…
Reference in a new issue