mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-05-08 22:50:40 +00:00
Merge pull request #360 from FluidSynth/sfont-loader-refactor
SoundFont Loading Refactor
This commit is contained in:
commit
32961c4031
12 changed files with 2935 additions and 2607 deletions
|
@ -129,6 +129,10 @@ set ( libfluidsynth_SOURCES
|
|||
sfloader/fluid_ramsfont.h
|
||||
sfloader/fluid_sfont.h
|
||||
sfloader/fluid_sfont.c
|
||||
sfloader/fluid_sffile.c
|
||||
sfloader/fluid_sffile.h
|
||||
sfloader/fluid_samplecache.c
|
||||
sfloader/fluid_samplecache.h
|
||||
rvoice/fluid_adsr_env.c
|
||||
rvoice/fluid_adsr_env.h
|
||||
rvoice/fluid_chorus.c
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,18 +27,13 @@
|
|||
|
||||
#include "fluidsynth.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_sffile.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_mod.h"
|
||||
#include "fluid_gen.h"
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/*-----------------------------------sfont.h----------------------------*/
|
||||
|
||||
#define SF_SAMPMODES_LOOP 1
|
||||
|
@ -49,292 +44,6 @@
|
|||
|
||||
#define SF_MIN_SAMPLE_LENGTH 32
|
||||
|
||||
/* Sound Font structure defines */
|
||||
|
||||
typedef struct _SFVersion
|
||||
{ /* version structure */
|
||||
unsigned short major;
|
||||
unsigned short minor;
|
||||
}
|
||||
SFVersion;
|
||||
|
||||
typedef struct _SFMod
|
||||
{ /* Modulator structure */
|
||||
unsigned short src; /* source modulator */
|
||||
unsigned short dest; /* destination generator */
|
||||
signed short amount; /* signed, degree of modulation */
|
||||
unsigned short amtsrc; /* second source controls amnt of first */
|
||||
unsigned short trans; /* transform applied to source */
|
||||
}
|
||||
SFMod;
|
||||
|
||||
typedef union _SFGenAmount
|
||||
{ /* Generator amount structure */
|
||||
signed short sword; /* signed 16 bit value */
|
||||
unsigned short uword; /* unsigned 16 bit value */
|
||||
struct
|
||||
{
|
||||
unsigned char lo; /* low value for ranges */
|
||||
unsigned char hi; /* high value for ranges */
|
||||
}
|
||||
range;
|
||||
}
|
||||
SFGenAmount;
|
||||
|
||||
typedef struct _SFGen
|
||||
{ /* Generator structure */
|
||||
unsigned short id; /* generator ID */
|
||||
SFGenAmount amount; /* generator value */
|
||||
}
|
||||
SFGen;
|
||||
|
||||
typedef struct _SFZone
|
||||
{ /* Sample/instrument zone structure */
|
||||
fluid_list_t *instsamp; /* instrument/sample pointer for zone */
|
||||
fluid_list_t *gen; /* list of generators */
|
||||
fluid_list_t *mod; /* list of modulators */
|
||||
}
|
||||
SFZone;
|
||||
|
||||
typedef struct _SFSample
|
||||
{ /* Sample structure */
|
||||
char name[21]; /* Name of sample */
|
||||
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
|
||||
unsigned int start; /* Offset in sample area to start of sample */
|
||||
unsigned int end; /* Offset from start to end of sample,
|
||||
this is the last point of the
|
||||
sample, the SF spec has this as the
|
||||
1st point after, corrected on
|
||||
load/save */
|
||||
unsigned int loopstart; /* Offset from start to start of loop */
|
||||
unsigned int loopend; /* Offset from start to end of loop,
|
||||
marks the first point after loop,
|
||||
whose sample value is ideally
|
||||
equivalent to loopstart */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
|
||||
}
|
||||
SFSample;
|
||||
|
||||
typedef struct _SFInst
|
||||
{ /* Instrument structure */
|
||||
char name[21]; /* Name of instrument */
|
||||
fluid_list_t *zone; /* list of instrument zones */
|
||||
}
|
||||
SFInst;
|
||||
|
||||
typedef struct _SFPreset
|
||||
{ /* Preset structure */
|
||||
char name[21]; /* preset name */
|
||||
unsigned short prenum; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned int libr; /* Not used (preserved) */
|
||||
unsigned int genre; /* Not used (preserved) */
|
||||
unsigned int morph; /* Not used (preserved) */
|
||||
fluid_list_t *zone; /* list of preset zones */
|
||||
}
|
||||
SFPreset;
|
||||
|
||||
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
|
||||
typedef struct _SFData
|
||||
{ /* Sound font data structure */
|
||||
SFVersion version; /* sound font version */
|
||||
SFVersion romver; /* ROM version */
|
||||
|
||||
unsigned int samplepos; /* position within sffd of the sample chunk */
|
||||
unsigned int samplesize; /* length within sffd of the sample chunk */
|
||||
|
||||
unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit sample support */
|
||||
unsigned int sample24size; /* length within sffd of the sm24 chunk */
|
||||
|
||||
char *fname; /* file name */
|
||||
FILE *sffd; /* loaded sfont file descriptor */
|
||||
fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
|
||||
fluid_list_t *preset; /* linked list of preset info */
|
||||
fluid_list_t *inst; /* linked list of instrument info */
|
||||
fluid_list_t *sample; /* linked list of sample info */
|
||||
}
|
||||
SFData;
|
||||
|
||||
/* sf file chunk IDs */
|
||||
enum
|
||||
{ UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
|
||||
INFO_ID, SDTA_ID, PDTA_ID, /* info/sample/preset */
|
||||
|
||||
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 */
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/* generator types */
|
||||
typedef enum
|
||||
{ Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
|
||||
Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_ModLFO2Pitch,
|
||||
Gen_VibLFO2Pitch, Gen_ModEnv2Pitch, Gen_FilterFc, Gen_FilterQ,
|
||||
Gen_ModLFO2FilterFc, Gen_ModEnv2FilterFc, Gen_EndAddrCoarseOfs,
|
||||
Gen_ModLFO2Vol, Gen_Unused1, Gen_ChorusSend, Gen_ReverbSend, Gen_Pan,
|
||||
Gen_Unused2, Gen_Unused3, Gen_Unused4,
|
||||
Gen_ModLFODelay, Gen_ModLFOFreq, Gen_VibLFODelay, Gen_VibLFOFreq,
|
||||
Gen_ModEnvDelay, Gen_ModEnvAttack, Gen_ModEnvHold, Gen_ModEnvDecay,
|
||||
Gen_ModEnvSustain, Gen_ModEnvRelease, Gen_Key2ModEnvHold,
|
||||
Gen_Key2ModEnvDecay, Gen_VolEnvDelay, Gen_VolEnvAttack,
|
||||
Gen_VolEnvHold, Gen_VolEnvDecay, Gen_VolEnvSustain, Gen_VolEnvRelease,
|
||||
Gen_Key2VolEnvHold, Gen_Key2VolEnvDecay, Gen_Instrument,
|
||||
Gen_Reserved1, Gen_KeyRange, Gen_VelRange,
|
||||
Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
|
||||
Gen_Attenuation, Gen_Reserved2, Gen_EndLoopAddrCoarseOfs,
|
||||
Gen_CoarseTune, Gen_FineTune, Gen_SampleId, Gen_SampleModes,
|
||||
Gen_Reserved3, Gen_ScaleTune, Gen_ExclusiveClass, Gen_OverrideRootKey,
|
||||
Gen_Dummy
|
||||
}
|
||||
Gen_Type;
|
||||
|
||||
#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
|
||||
#define Gen_Count Gen_Dummy /* count of generators */
|
||||
#define GenArrSize sizeof(SFGenAmount)*Gen_Count /* gen array size */
|
||||
|
||||
/* generator unit type */
|
||||
typedef enum
|
||||
{
|
||||
None, /* No unit type */
|
||||
Unit_Smpls, /* in samples */
|
||||
Unit_32kSmpls, /* in 32k samples */
|
||||
Unit_Cent, /* in cents (1/100th of a semitone) */
|
||||
Unit_HzCent, /* in Hz Cents */
|
||||
Unit_TCent, /* in Time Cents */
|
||||
Unit_cB, /* in centibels (1/100th of a decibel) */
|
||||
Unit_Percent, /* in percentage */
|
||||
Unit_Semitone, /* in semitones */
|
||||
Unit_Range /* a range of values */
|
||||
}
|
||||
Gen_Unit;
|
||||
|
||||
/* functions */
|
||||
void sfont_init_chunks (void);
|
||||
|
||||
void sfont_close (SFData * sf, const fluid_file_callbacks_t* fcbs);
|
||||
void sfont_free_zone (SFZone * zone);
|
||||
int sfont_preset_compare_func (void* a, void* b);
|
||||
|
||||
void sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone);
|
||||
|
||||
fluid_list_t *gen_inlist (int gen, fluid_list_t * genlist);
|
||||
int gen_valid (int gen);
|
||||
int gen_validp (int gen);
|
||||
|
||||
|
||||
/*-----------------------------------sffile.h----------------------------*/
|
||||
/*
|
||||
File structures and routines (used to be in sffile.h)
|
||||
*/
|
||||
|
||||
#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
|
||||
|
||||
/* sfont file chunk sizes */
|
||||
#define SFPHDRSIZE 38
|
||||
#define SFBAGSIZE 4
|
||||
#define SFMODSIZE 10
|
||||
#define SFGENSIZE 4
|
||||
#define SFIHDRSIZE 22
|
||||
#define SFSHDRSIZE 46
|
||||
|
||||
/* sfont file data structures */
|
||||
typedef struct _SFChunk
|
||||
{ /* RIFF file chunk structure */
|
||||
unsigned int id; /* chunk id */
|
||||
unsigned int size; /* size of the following chunk */
|
||||
}
|
||||
SFChunk;
|
||||
|
||||
typedef struct _SFPhdr
|
||||
{
|
||||
unsigned char name[20]; /* preset name */
|
||||
unsigned short preset; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned short pbagndx; /* index into preset bag */
|
||||
unsigned int library; /* just for preserving them */
|
||||
unsigned int genre; /* Not used */
|
||||
unsigned int morphology; /* Not used */
|
||||
}
|
||||
SFPhdr;
|
||||
|
||||
typedef struct _SFBag
|
||||
{
|
||||
unsigned short genndx; /* index into generator list */
|
||||
unsigned short modndx; /* index into modulator list */
|
||||
}
|
||||
SFBag;
|
||||
|
||||
typedef struct _SFIhdr
|
||||
{
|
||||
char name[20]; /* Name of instrument */
|
||||
unsigned short ibagndx; /* Instrument bag index */
|
||||
}
|
||||
SFIhdr;
|
||||
|
||||
typedef struct _SFShdr
|
||||
{ /* Sample header loading struct */
|
||||
char name[20]; /* Sample name */
|
||||
unsigned int start; /* Offset to start of sample */
|
||||
unsigned int end; /* Offset to end of sample */
|
||||
unsigned int loopstart; /* Offset to start of loop */
|
||||
unsigned int loopend; /* Offset to end of loop */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short samplelink; /* Not used */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
}
|
||||
SFShdr;
|
||||
|
||||
/* functions */
|
||||
SFData *sfload_file (const char * fname, const fluid_file_callbacks_t* fcbs);
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
|
||||
/*-----------------------------------util.h----------------------------*/
|
||||
/*
|
||||
Utility functions (formerly in util.h)
|
||||
*/
|
||||
#define FAIL 0
|
||||
#define OK 1
|
||||
|
||||
enum
|
||||
{ ErrWarn, ErrFatal, ErrStatus, ErrCorr, ErrEof, ErrMem, Errno,
|
||||
ErrRead, ErrWrite
|
||||
};
|
||||
|
||||
#define ErrMax ErrWrite
|
||||
#define ErrnoStart Errno
|
||||
#define ErrnoEnd ErrWrite
|
||||
|
||||
int gerr (int ev, char * fmt, ...);
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* FORWARD DECLARATIONS
|
||||
|
@ -407,15 +116,15 @@ struct _fluid_defsfont_t
|
|||
|
||||
|
||||
fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings);
|
||||
int delete_fluid_defsfont(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_load(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* file_callbacks, const char* file);
|
||||
const char* fluid_defsfont_get_name(fluid_defsfont_t* sfont);
|
||||
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset);
|
||||
int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* file_callbacks);
|
||||
int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample);
|
||||
int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset);
|
||||
int delete_fluid_defsfont(fluid_defsfont_t* defsfont);
|
||||
int fluid_defsfont_load(fluid_defsfont_t* defsfont, const fluid_file_callbacks_t* file_callbacks, const char* file);
|
||||
const char* fluid_defsfont_get_name(fluid_defsfont_t* defsfont);
|
||||
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* defsfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_defsfont_iteration_start(fluid_defsfont_t* defsfont);
|
||||
int fluid_defsfont_iteration_next(fluid_defsfont_t* defsfont, fluid_preset_t* preset);
|
||||
int fluid_defsfont_load_sampledata(fluid_defsfont_t* defsfont, const fluid_file_callbacks_t* file_callbacks);
|
||||
int fluid_defsfont_add_sample(fluid_defsfont_t* defsfont, fluid_sample_t* sample);
|
||||
int fluid_defsfont_add_preset(fluid_defsfont_t* defsfont, fluid_defpreset_t* defpreset);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -424,7 +133,7 @@ int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset
|
|||
struct _fluid_defpreset_t
|
||||
{
|
||||
fluid_defpreset_t* next;
|
||||
fluid_defsfont_t* sfont; /* the soundfont this preset belongs to */
|
||||
fluid_defsfont_t* defsfont; /* the soundfont this preset belongs to */
|
||||
char name[21]; /* the name of the preset */
|
||||
unsigned int bank; /* the bank number */
|
||||
unsigned int num; /* the preset number */
|
||||
|
@ -432,18 +141,18 @@ struct _fluid_defpreset_t
|
|||
fluid_preset_zone_t* zone; /* the chained list of preset zones */
|
||||
};
|
||||
|
||||
fluid_defpreset_t* new_fluid_defpreset(fluid_defsfont_t* sfont);
|
||||
void delete_fluid_defpreset(fluid_defpreset_t* preset);
|
||||
fluid_defpreset_t* fluid_defpreset_next(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t* preset, SFPreset* sfpreset, fluid_defsfont_t* sfont);
|
||||
int fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
|
||||
int fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_zone(fluid_defpreset_t* preset);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_global_zone(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_get_banknum(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_get_num(fluid_defpreset_t* preset);
|
||||
const char* fluid_defpreset_get_name(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
fluid_defpreset_t* new_fluid_defpreset(fluid_defsfont_t* defsfont);
|
||||
void delete_fluid_defpreset(fluid_defpreset_t* defpreset);
|
||||
fluid_defpreset_t* fluid_defpreset_next(fluid_defpreset_t* defpreset);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t* defpreset, SFPreset* sfpreset, fluid_defsfont_t* defsfont);
|
||||
int fluid_defpreset_set_global_zone(fluid_defpreset_t* defpreset, fluid_preset_zone_t* zone);
|
||||
int fluid_defpreset_add_zone(fluid_defpreset_t* defpreset, fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_zone(fluid_defpreset_t* defpreset);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_global_zone(fluid_defpreset_t* defpreset);
|
||||
int fluid_defpreset_get_banknum(fluid_defpreset_t* defpreset);
|
||||
int fluid_defpreset_get_num(fluid_defpreset_t* defpreset);
|
||||
const char* fluid_defpreset_get_name(fluid_defpreset_t* defpreset);
|
||||
int fluid_defpreset_noteon(fluid_defpreset_t* defpreset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/*
|
||||
* fluid_preset_zone
|
||||
|
@ -460,8 +169,8 @@ struct _fluid_preset_zone_t
|
|||
|
||||
fluid_preset_zone_t* new_fluid_preset_zone(char* name);
|
||||
void delete_fluid_preset_zone(fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_preset_zone_next(fluid_preset_zone_t* preset);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone* sfzone, fluid_defsfont_t* sfont);
|
||||
fluid_preset_zone_t* fluid_preset_zone_next(fluid_preset_zone_t* zone);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone* sfzone, fluid_defsfont_t* defssfont);
|
||||
fluid_inst_t* fluid_preset_zone_get_inst(fluid_preset_zone_t* zone);
|
||||
|
||||
/*
|
||||
|
@ -475,8 +184,8 @@ struct _fluid_inst_t
|
|||
};
|
||||
|
||||
fluid_inst_t* new_fluid_inst(void);
|
||||
int fluid_inst_import_sfont(fluid_preset_zone_t* zonePZ, fluid_inst_t* inst,
|
||||
SFInst *sfinst, fluid_defsfont_t* sfont);
|
||||
int fluid_inst_import_sfont(fluid_preset_zone_t* preset_zone, fluid_inst_t* inst,
|
||||
SFInst *sfinst, fluid_defsfont_t* defsfont);
|
||||
void delete_fluid_inst(fluid_inst_t* inst);
|
||||
int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
|
||||
int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
|
||||
|
@ -500,13 +209,13 @@ struct _fluid_inst_zone_t
|
|||
fluid_inst_zone_t* new_fluid_inst_zone(char* name);
|
||||
void delete_fluid_inst_zone(fluid_inst_zone_t* zone);
|
||||
fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone);
|
||||
int fluid_inst_zone_import_sfont(fluid_preset_zone_t* zonePZ,
|
||||
fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont);
|
||||
int fluid_inst_zone_import_sfont(fluid_preset_zone_t* preset_zone,
|
||||
fluid_inst_zone_t* inst_zone, SFZone *sfzone, fluid_defsfont_t* defsfont);
|
||||
fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);
|
||||
|
||||
|
||||
|
||||
int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont);
|
||||
int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* defsfont);
|
||||
int fluid_sample_in_rom(fluid_sample_t* sample);
|
||||
|
||||
|
||||
|
|
279
src/sfloader/fluid_samplecache.c
Normal file
279
src/sfloader/fluid_samplecache.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* SoundFont file loading code borrowed from Smurf SoundFont Editor
|
||||
* Copyright (C) 1999-2001 Josh Green
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
/* CACHED SAMPLE DATA LOADER
|
||||
*
|
||||
* This is a wrapper around fluid_sffile_read_sample_data that attempts to cache the read
|
||||
* data across all FluidSynth instances in a global (process-wide) list.
|
||||
*/
|
||||
|
||||
#include "fluid_samplecache.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "fluid_list.h"
|
||||
|
||||
|
||||
typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
|
||||
|
||||
struct _fluid_samplecache_entry_t
|
||||
{
|
||||
/* The follwing members all form the cache key */
|
||||
char *filename;
|
||||
time_t modification_time;
|
||||
unsigned int sf_samplepos;
|
||||
unsigned int sf_samplesize;
|
||||
unsigned int sf_sample24pos;
|
||||
unsigned int sf_sample24size;
|
||||
unsigned int sample_start;
|
||||
unsigned int sample_count;
|
||||
/* End of cache key members */
|
||||
|
||||
short *sample_data;
|
||||
char *sample_data24;
|
||||
|
||||
int num_references;
|
||||
int mlocked;
|
||||
};
|
||||
|
||||
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_count);
|
||||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_count);
|
||||
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
|
||||
|
||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
|
||||
|
||||
|
||||
/* PUBLIC INTERFACE */
|
||||
|
||||
int fluid_samplecache_load(SFData *sf,
|
||||
unsigned int sample_start, unsigned int sample_count,
|
||||
int try_mlock, short **sample_data, char **sample_data24)
|
||||
{
|
||||
fluid_samplecache_entry_t *entry;
|
||||
int ret;
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
|
||||
entry = get_samplecache_entry(sf, sample_start, sample_count);
|
||||
if (entry == NULL)
|
||||
{
|
||||
entry = new_samplecache_entry(sf, sample_start, sample_count);
|
||||
if (entry == NULL)
|
||||
{
|
||||
ret = FLUID_FAILED;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
samplecache_list = fluid_list_prepend(samplecache_list, entry);
|
||||
}
|
||||
|
||||
if (try_mlock && !entry->mlocked)
|
||||
{
|
||||
/* Lock the memory to disable paging. It's okay if this fails. It
|
||||
* probably means that the user doesn't have the required permission. */
|
||||
if (fluid_mlock(entry->sample_data, entry->sample_count * 2) == 0)
|
||||
{
|
||||
if (entry->sample_data24 != NULL)
|
||||
{
|
||||
entry->mlocked = (fluid_mlock(entry->sample_data24, entry->sample_count) == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->mlocked = TRUE;
|
||||
}
|
||||
|
||||
if (!entry->mlocked)
|
||||
{
|
||||
fluid_munlock(entry->sample_data, entry->sample_count * 2);
|
||||
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry->num_references++;
|
||||
*sample_data = entry->sample_data;
|
||||
*sample_data24 = entry->sample_data24;
|
||||
ret = FLUID_OK;
|
||||
|
||||
unlock_exit:
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fluid_samplecache_unload(const short *sample_data)
|
||||
{
|
||||
fluid_list_t *entry_list;
|
||||
fluid_samplecache_entry_t *entry;
|
||||
int ret;
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
|
||||
entry_list = samplecache_list;
|
||||
while (entry_list)
|
||||
{
|
||||
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
|
||||
|
||||
if (sample_data == entry->sample_data)
|
||||
{
|
||||
entry->num_references--;
|
||||
|
||||
if (entry->num_references == 0)
|
||||
{
|
||||
if (entry->mlocked)
|
||||
{
|
||||
fluid_munlock(entry->sample_data, entry->sample_count * 2);
|
||||
if (entry->sample_data24 != NULL)
|
||||
{
|
||||
fluid_munlock(entry->sample_data24, entry->sample_count);
|
||||
}
|
||||
}
|
||||
|
||||
samplecache_list = fluid_list_remove(samplecache_list, entry);
|
||||
delete_samplecache_entry(entry);
|
||||
}
|
||||
|
||||
ret = FLUID_OK;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
entry_list = fluid_list_next(entry_list);
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache.");
|
||||
ret = FLUID_FAILED;
|
||||
|
||||
unlock_exit:
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Private functions */
|
||||
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
|
||||
unsigned int sample_start,
|
||||
unsigned int sample_count)
|
||||
{
|
||||
fluid_samplecache_entry_t *entry;
|
||||
|
||||
entry = FLUID_NEW(fluid_samplecache_entry_t);
|
||||
if (entry == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(entry, 0, sizeof(*entry));
|
||||
|
||||
entry->filename = FLUID_STRDUP(sf->fname);
|
||||
if (entry->filename == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||
entry->modification_time = 0;
|
||||
}
|
||||
|
||||
entry->sf_samplepos = sf->samplepos;
|
||||
entry->sf_samplesize = sf->samplesize;
|
||||
entry->sf_sample24pos = sf->sample24pos;
|
||||
entry->sf_sample24size = sf->sample24size;
|
||||
entry->sample_start = sample_start;
|
||||
entry->sample_count = sample_count;
|
||||
|
||||
if (fluid_sffile_read_sample_data(sf, sample_start, sample_count,
|
||||
&entry->sample_data, &entry->sample_data24) == FLUID_FAILED)
|
||||
{
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
||||
error_exit:
|
||||
delete_samplecache_entry(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
|
||||
{
|
||||
fluid_return_if_fail(entry != NULL);
|
||||
|
||||
FLUID_FREE(entry->filename);
|
||||
FLUID_FREE(entry->sample_data);
|
||||
FLUID_FREE(entry->sample_data24);
|
||||
FLUID_FREE(entry);
|
||||
}
|
||||
|
||||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
|
||||
unsigned int sample_start,
|
||||
unsigned int sample_count)
|
||||
{
|
||||
time_t mtime;
|
||||
fluid_list_t *entry_list;
|
||||
fluid_samplecache_entry_t *entry;
|
||||
|
||||
if (fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||
mtime = 0;
|
||||
}
|
||||
|
||||
entry_list = samplecache_list;
|
||||
while (entry_list)
|
||||
{
|
||||
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
|
||||
|
||||
if ((FLUID_STRCMP(sf->fname, entry->filename) == 0) &&
|
||||
(mtime == entry->modification_time) &&
|
||||
(sf->samplepos == entry->sf_samplepos) &&
|
||||
(sf->samplesize == entry->sf_samplesize) &&
|
||||
(sf->sample24pos == entry->sf_sample24pos) &&
|
||||
(sf->sample24size == entry->sf_sample24size) &&
|
||||
(sample_start == entry->sample_start) &&
|
||||
(sample_count == entry->sample_count))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
entry_list = fluid_list_next(entry_list);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
|
||||
{
|
||||
fluid_stat_buf_t buf;
|
||||
|
||||
if (fluid_stat(filename, &buf))
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
*modification_time = buf.st_mtime;
|
||||
return FLUID_OK;
|
||||
}
|
34
src/sfloader/fluid_samplecache.h
Normal file
34
src/sfloader/fluid_samplecache.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_SAMPLECACHE_H
|
||||
#define _FLUID_SAMPLECACHE_H
|
||||
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_sffile.h"
|
||||
|
||||
int fluid_samplecache_load(SFData *sf,
|
||||
unsigned int sample_start, unsigned int sample_count,
|
||||
int try_mlock, short **data, char **data24);
|
||||
|
||||
int fluid_samplecache_unload(const short *sample_data);
|
||||
|
||||
#endif /* _FLUID_SAMPLECACHE_H */
|
1902
src/sfloader/fluid_sffile.c
Normal file
1902
src/sfloader/fluid_sffile.c
Normal file
File diff suppressed because it is too large
Load diff
212
src/sfloader/fluid_sffile.h
Normal file
212
src/sfloader/fluid_sffile.h
Normal file
|
@ -0,0 +1,212 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_SFFILE_H
|
||||
#define _FLUID_SFFILE_H
|
||||
|
||||
|
||||
#include "fluid_gen.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_mod.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
/* Sound Font structure defines */
|
||||
|
||||
/* Forward declarations */
|
||||
typedef union _SFGenAmount SFGenAmount;
|
||||
typedef struct _SFVersion SFVersion;
|
||||
typedef struct _SFMod SFMod;
|
||||
typedef struct _SFGen SFGen;
|
||||
typedef struct _SFZone SFZone;
|
||||
typedef struct _SFSample SFSample;
|
||||
typedef struct _SFInst SFInst;
|
||||
typedef struct _SFPreset SFPreset;
|
||||
typedef struct _SFData SFData;
|
||||
typedef struct _SFChunk SFChunk;
|
||||
typedef struct _SFPhdr SFPhdr;
|
||||
typedef struct _SFBag SFBag;
|
||||
typedef struct _SFIhdr SFIhdr;
|
||||
typedef struct _SFShdr SFShdr;
|
||||
|
||||
|
||||
struct _SFVersion
|
||||
{ /* version structure */
|
||||
unsigned short major;
|
||||
unsigned short minor;
|
||||
};
|
||||
|
||||
struct _SFMod
|
||||
{ /* Modulator structure */
|
||||
unsigned short src; /* source modulator */
|
||||
unsigned short dest; /* destination generator */
|
||||
signed short amount; /* signed, degree of modulation */
|
||||
unsigned short amtsrc; /* second source controls amnt of first */
|
||||
unsigned short trans; /* transform applied to source */
|
||||
};
|
||||
|
||||
union _SFGenAmount { /* Generator amount structure */
|
||||
signed short sword; /* signed 16 bit value */
|
||||
unsigned short uword; /* unsigned 16 bit value */
|
||||
struct
|
||||
{
|
||||
unsigned char lo; /* low value for ranges */
|
||||
unsigned char hi; /* high value for ranges */
|
||||
} range;
|
||||
};
|
||||
|
||||
struct _SFGen
|
||||
{ /* Generator structure */
|
||||
unsigned short id; /* generator ID */
|
||||
SFGenAmount amount; /* generator value */
|
||||
};
|
||||
|
||||
struct _SFZone
|
||||
{ /* Sample/instrument zone structure */
|
||||
fluid_list_t *instsamp; /* instrument/sample pointer for zone */
|
||||
fluid_list_t *gen; /* list of generators */
|
||||
fluid_list_t *mod; /* list of modulators */
|
||||
};
|
||||
|
||||
struct _SFSample
|
||||
{ /* Sample structure */
|
||||
char name[21]; /* Name of sample */
|
||||
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
|
||||
unsigned int start; /* Offset in sample area to start of sample */
|
||||
unsigned int end; /* Offset from start to end of sample,
|
||||
this is the last point of the
|
||||
sample, the SF spec has this as the
|
||||
1st point after, corrected on
|
||||
load/save */
|
||||
unsigned int loopstart; /* Offset from start to start of loop */
|
||||
unsigned int loopend; /* Offset from start to end of loop,
|
||||
marks the first point after loop,
|
||||
whose sample value is ideally
|
||||
equivalent to loopstart */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
|
||||
};
|
||||
|
||||
struct _SFInst
|
||||
{ /* Instrument structure */
|
||||
char name[21]; /* Name of instrument */
|
||||
fluid_list_t *zone; /* list of instrument zones */
|
||||
};
|
||||
|
||||
struct _SFPreset
|
||||
{ /* Preset structure */
|
||||
char name[21]; /* preset name */
|
||||
unsigned short prenum; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned int libr; /* Not used (preserved) */
|
||||
unsigned int genre; /* Not used (preserved) */
|
||||
unsigned int morph; /* Not used (preserved) */
|
||||
fluid_list_t *zone; /* list of preset zones */
|
||||
};
|
||||
|
||||
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
|
||||
struct _SFData
|
||||
{ /* Sound font data structure */
|
||||
SFVersion version; /* sound font version */
|
||||
SFVersion romver; /* ROM version */
|
||||
|
||||
unsigned int samplepos; /* position within sffd of the sample chunk */
|
||||
unsigned int samplesize; /* length within sffd of the sample chunk */
|
||||
|
||||
unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit
|
||||
sample support */
|
||||
unsigned int sample24size; /* length within sffd of the sm24 chunk */
|
||||
|
||||
char *fname; /* file name */
|
||||
FILE *sffd; /* loaded sfont file descriptor */
|
||||
const fluid_file_callbacks_t *fcbs; /* file callbacks used to read this file */
|
||||
|
||||
fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
|
||||
fluid_list_t *preset; /* linked list of preset info */
|
||||
fluid_list_t *inst; /* linked list of instrument info */
|
||||
fluid_list_t *sample; /* linked list of sample info */
|
||||
};
|
||||
|
||||
/* functions */
|
||||
|
||||
|
||||
/*-----------------------------------sffile.h----------------------------*/
|
||||
/*
|
||||
File structures and routines (used to be in sffile.h)
|
||||
*/
|
||||
|
||||
/* sfont file data structures */
|
||||
struct _SFChunk
|
||||
{ /* RIFF file chunk structure */
|
||||
unsigned int id; /* chunk id */
|
||||
unsigned int size; /* size of the following chunk */
|
||||
};
|
||||
|
||||
struct _SFPhdr
|
||||
{
|
||||
unsigned char name[20]; /* preset name */
|
||||
unsigned short preset; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned short pbagndx; /* index into preset bag */
|
||||
unsigned int library; /* just for preserving them */
|
||||
unsigned int genre; /* Not used */
|
||||
unsigned int morphology; /* Not used */
|
||||
};
|
||||
|
||||
struct _SFBag
|
||||
{
|
||||
unsigned short genndx; /* index into generator list */
|
||||
unsigned short modndx; /* index into modulator list */
|
||||
};
|
||||
|
||||
struct _SFIhdr
|
||||
{
|
||||
char name[20]; /* Name of instrument */
|
||||
unsigned short ibagndx; /* Instrument bag index */
|
||||
};
|
||||
|
||||
struct _SFShdr
|
||||
{ /* Sample header loading struct */
|
||||
char name[20]; /* Sample name */
|
||||
unsigned int start; /* Offset to start of sample */
|
||||
unsigned int end; /* Offset to end of sample */
|
||||
unsigned int loopstart; /* Offset to start of loop */
|
||||
unsigned int loopend; /* Offset to end of loop */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short samplelink; /* Not used */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
};
|
||||
|
||||
/* Public functions */
|
||||
SFData *fluid_sffile_load(const char *fname, const fluid_file_callbacks_t *fcbs);
|
||||
void fluid_sffile_close(SFData *sf);
|
||||
int fluid_sffile_read_sample_data(SFData *sf, unsigned int start, unsigned int count,
|
||||
short **data, char **data24);
|
||||
|
||||
#endif /* _FLUID_SFFILE_H */
|
|
@ -21,6 +21,12 @@
|
|||
#include "fluid_sfont.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void * default_fopen(const char * path)
|
||||
{
|
||||
return FLUID_FOPEN(path, "rb");
|
||||
|
@ -41,9 +47,9 @@ int safe_fread (void *buf, int count, void * fd)
|
|||
if (FLUID_FREAD(buf, count, 1, (FILE *)fd) != 1)
|
||||
{
|
||||
if (feof ((FILE *)fd))
|
||||
FLUID_LOG (FLUID_ERR, _("EOF while attemping to read %d bytes"), count);
|
||||
FLUID_LOG (FLUID_ERR, "EOF while attemping to read %d bytes", count);
|
||||
else
|
||||
FLUID_LOG (FLUID_ERR, _("File read failed"));
|
||||
FLUID_LOG (FLUID_ERR, "File read failed");
|
||||
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
@ -53,7 +59,7 @@ int safe_fread (void *buf, int count, void * fd)
|
|||
int safe_fseek (void * fd, long ofs, int whence)
|
||||
{
|
||||
if (FLUID_FSEEK((FILE *)fd, ofs, whence) != 0) {
|
||||
FLUID_LOG (FLUID_ERR, _("File seek failed with offset = %ld and whence = %d"), ofs, whence);
|
||||
FLUID_LOG (FLUID_ERR, "File seek failed with offset = %ld and whence = %d", ofs, whence);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
|
@ -498,7 +504,6 @@ fluid_sample_set_sound_data (fluid_sample_t* sample,
|
|||
|
||||
sample->samplerate = sample_rate;
|
||||
sample->sampletype = FLUID_SAMPLETYPE_MONO;
|
||||
sample->valid = 1;
|
||||
sample->auto_free = copy_data;
|
||||
|
||||
return FLUID_OK;
|
||||
|
@ -546,3 +551,242 @@ int fluid_sample_set_pitch(fluid_sample_t* sample, int root_key, int fine_tune)
|
|||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate parameters of a sample
|
||||
*
|
||||
*/
|
||||
int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size)
|
||||
{
|
||||
/* ROM samples are unusable for us by definition */
|
||||
if (sample->sampletype & FLUID_SAMPLETYPE_ROM)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s': ROM sample ignored", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* Ogg vorbis compressed samples in the SF3 format use byte indices for
|
||||
* sample start and end pointers before decompression. Standard SF2 samples
|
||||
* use sample word indices for all pointers, so use half the buffer_size
|
||||
* for validation. */
|
||||
if (!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))
|
||||
{
|
||||
if (buffer_size % 2)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s': invalid buffer size", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
buffer_size /= 2;
|
||||
}
|
||||
|
||||
if ((sample->end > buffer_size) || (sample->start >= sample->end))
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s': invalid start/end file positions", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/* Check the sample loop pointers and optionally convert them to something
|
||||
* usable in case they are broken. Return a boolean indicating if the pointers
|
||||
* have been modified, so the user can be notified of possible audio glitches.
|
||||
*/
|
||||
int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size)
|
||||
{
|
||||
int modified = FALSE;
|
||||
unsigned int max_end = buffer_size / 2;
|
||||
/* In fluid_sample_t the sample end pointer points to the last sample, not
|
||||
* to the data word after the last sample. FIXME: why? */
|
||||
unsigned int sample_end = sample->end + 1;
|
||||
|
||||
/* Checking loops on compressed samples makes no sense at all and is really
|
||||
* a programming error. Disable the loop to be on the safe side. */
|
||||
if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Sample '%s': checking loop on compressed sample, disabling loop",
|
||||
sample->name);
|
||||
sample->loopstart = sample->loopend = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (sample->loopstart == sample->loopend)
|
||||
{
|
||||
/* Some SoundFonts disable loops by setting loopstart = loopend. While
|
||||
* technically invalid, we decided to accept those samples anyway. Just
|
||||
* ensure that those two pointers are within the sampledata by setting
|
||||
* them to 0. Don't set modified here, as this change has no audible
|
||||
* effect. */
|
||||
sample->loopstart = sample->loopend = 0;
|
||||
}
|
||||
else if (sample->loopstart > sample->loopend)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
/* If loop start and end are reversed, try to swap them around and
|
||||
* continue validation */
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': reversed loop pointers '%d' - '%d', trying to fix",
|
||||
sample->name, sample->loopstart, sample->loopend);
|
||||
tmp = sample->loopstart;
|
||||
sample->loopstart = sample->loopend;
|
||||
sample->loopend = tmp;
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
/* The SoundFont 2.4 spec defines the loopstart index as the first sample
|
||||
* point of the loop while loopend is the first point AFTER the last sample
|
||||
* of the loop. However we cannot be sure whether any of loopend or end is
|
||||
* correct. Hours of thinking through this have concluded that it would be
|
||||
* best practice to mangle with loops as little as necessary by only making
|
||||
* sure the pointers are within sample->start to max_end. Incorrect
|
||||
* soundfont shall preferably fail loudly. */
|
||||
if ((sample->loopstart < sample->start) || (sample->loopstart > max_end))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop start '%d', setting to sample start '%d'",
|
||||
sample->name, sample->loopstart, sample->start);
|
||||
sample->loopstart = sample->start;
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
if ((sample->loopend < sample->start) || (sample->loopend > max_end))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop end '%d', setting to sample end '%d'",
|
||||
sample->name, sample->loopend, sample_end);
|
||||
sample->loopend = sample_end;
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
if ((sample->loopstart > sample_end) || (sample->loopend > sample_end))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': loop range '%d - %d' after sample end '%d', using it anyway",
|
||||
sample->name, sample->loopstart, sample->loopend, sample_end);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
|
||||
// virtual file access rountines to allow for handling
|
||||
// samples as virtual files in memory
|
||||
static sf_count_t
|
||||
sfvio_get_filelen(void* user_data)
|
||||
{
|
||||
fluid_sample_t *sample = (fluid_sample_t *)user_data;
|
||||
|
||||
return (sf_count_t)(sample->end + 1 - sample->start);
|
||||
}
|
||||
|
||||
static sf_count_t
|
||||
sfvio_seek(sf_count_t offset, int whence, void* user_data)
|
||||
{
|
||||
fluid_sample_t *sample = (fluid_sample_t *)user_data;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
sample->userdata = (void *)offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
sample->userdata = (void *)((sf_count_t)sample->userdata + offset);
|
||||
break;
|
||||
case SEEK_END:
|
||||
sample->userdata = (void *)(sfvio_get_filelen(user_data) + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return (sf_count_t)sample->userdata;
|
||||
}
|
||||
|
||||
static sf_count_t
|
||||
sfvio_read(void* ptr, sf_count_t count, void* user_data)
|
||||
{
|
||||
fluid_sample_t *sample = (fluid_sample_t *)user_data;
|
||||
sf_count_t remain = sfvio_get_filelen(user_data) - (sf_count_t)sample->userdata;
|
||||
|
||||
if (count > remain)
|
||||
count = remain;
|
||||
|
||||
memcpy(ptr, (char *)sample->data + sample->start + (sf_count_t)sample->userdata, count);
|
||||
sample->userdata = (void *)((sf_count_t)sample->userdata + count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static sf_count_t
|
||||
sfvio_tell (void* user_data)
|
||||
{
|
||||
fluid_sample_t *sample = (fluid_sample_t *)user_data;
|
||||
|
||||
return (sf_count_t)sample->userdata;
|
||||
}
|
||||
|
||||
int fluid_sample_decompress_vorbis(fluid_sample_t *sample)
|
||||
{
|
||||
SNDFILE *sndfile;
|
||||
SF_INFO sfinfo;
|
||||
SF_VIRTUAL_IO sfvio = {
|
||||
sfvio_get_filelen,
|
||||
sfvio_seek,
|
||||
sfvio_read,
|
||||
NULL,
|
||||
sfvio_tell
|
||||
};
|
||||
short *sampledata_ogg;
|
||||
|
||||
// initialize file position indicator and SF_INFO structure
|
||||
g_assert(sample->userdata == NULL);
|
||||
memset(&sfinfo, 0, sizeof(sfinfo));
|
||||
|
||||
// open sample as a virtual file in memory
|
||||
sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, sample);
|
||||
if (!sndfile)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
// empty sample
|
||||
if (!sfinfo.frames || !sfinfo.channels)
|
||||
{
|
||||
sample->start = sample->end = 0;
|
||||
sample->loopstart = sample->loopend = 0;
|
||||
sample->data = NULL;
|
||||
sf_close(sndfile);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
// allocate memory for uncompressed sample data stream
|
||||
sampledata_ogg = (short *)FLUID_MALLOC(sfinfo.frames * sfinfo.channels * sizeof(short));
|
||||
if (!sampledata_ogg)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
sf_close(sndfile);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
// uncompress sample data stream
|
||||
if (sf_readf_short(sndfile, sampledata_ogg, sfinfo.frames) < sfinfo.frames)
|
||||
{
|
||||
FLUID_FREE(sampledata_ogg);
|
||||
FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
|
||||
sf_close(sndfile);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
sf_close(sndfile);
|
||||
|
||||
// point sample data to uncompressed data stream
|
||||
sample->data = sampledata_ogg;
|
||||
sample->auto_free = TRUE;
|
||||
sample->start = 0;
|
||||
sample->end = sfinfo.frames - 1;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
#else
|
||||
int fluid_sample_decompress_vorbis(fluid_sample_t *sample)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include "fluidsynth.h"
|
||||
|
||||
int fluid_sample_validate(fluid_sample_t *sample, unsigned int max_end);
|
||||
int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int max_end);
|
||||
int fluid_sample_decompress_vorbis(fluid_sample_t *sample);
|
||||
|
||||
/*
|
||||
* Utility macros to access soundfonts, presets, and samples
|
||||
*/
|
||||
|
@ -179,7 +183,6 @@ struct _fluid_sample_t
|
|||
int origpitch; /**< Original pitch (MIDI note number, 0-127) */
|
||||
int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */
|
||||
int sampletype; /**< Specifies the type of this sample as indicated by the #fluid_sample_type enum */
|
||||
int valid; /**< Should be TRUE if sample data is valid, FALSE otherwise (in which case it will not be synthesized) */
|
||||
int auto_free; /**< TRUE if _fluid_sample_t::data and _fluid_sample_t::data24 should be freed upon sample destruction */
|
||||
short* data; /**< Pointer to the sample's 16 bit PCM data */
|
||||
char* data24; /**< If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples */
|
||||
|
|
|
@ -1726,8 +1726,8 @@ fluid_voice_optimize_sample(fluid_sample_t* s)
|
|||
double result;
|
||||
unsigned int i;
|
||||
|
||||
/* ignore ROM and other(?) invalid samples */
|
||||
if (!s->valid) return (FLUID_OK);
|
||||
/* ignore disabled samples */
|
||||
if (s->start == s->end) return (FLUID_OK);
|
||||
|
||||
if (!s->amplitude_that_reaches_noise_floor_is_valid) { /* Only once */
|
||||
/* Scan the loop */
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include <gmodule.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
/**
|
||||
* Macro used for safely accessing a message from a GError and using a default
|
||||
* message if it is NULL.
|
||||
|
@ -355,6 +357,10 @@ void fluid_socket_close(fluid_socket_t sock);
|
|||
fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock);
|
||||
fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);
|
||||
|
||||
/* File access */
|
||||
typedef GStatBuf fluid_stat_buf_t;
|
||||
#define fluid_stat(_filename, _statbuf) g_stat((_filename), (_statbuf))
|
||||
|
||||
|
||||
/* Profiling */
|
||||
#if WITH_PROFILING
|
||||
|
|
|
@ -320,9 +320,4 @@ do { strncpy(_dst,_src,_n); \
|
|||
|
||||
char* fluid_error(void);
|
||||
|
||||
|
||||
/* Internationalization */
|
||||
#define _(s) s
|
||||
|
||||
|
||||
#endif /* _FLUIDSYNTH_PRIV_H */
|
||||
|
|
Loading…
Reference in a new issue