mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-20 19:02:04 +00:00
Refactor Soundfont loader API (#334)
* add fluid_mod_sizeof() and fluid_sample_sizeof() for low latency scenarios * fix return value of default_fclose * enable padding warnings for cmake enable-profiling=1 * make these types private: * struct _fluid_sfloader_t * struct _fluid_sample_t * struct _fluid_sfont_t * struct _fluid_preset_t ...and provide proper getter and setter functions
This commit is contained in:
parent
825216f0b6
commit
4a0a7365ee
17 changed files with 945 additions and 540 deletions
|
@ -266,9 +266,11 @@ unset ( WITH_PROFILING CACHE )
|
|||
if ( enable-profiling )
|
||||
set ( WITH_PROFILING 1 )
|
||||
if ( CMAKE_C_COMPILER_ID STREQUAL "Clang" )
|
||||
set ( OPT_FLAGS "-Rpass=loop-vectorize -Rpass-analysis=loop-vectorize" )
|
||||
set ( OPT_FLAGS "-Rpass=loop-vectorize -Rpass-analysis=loop-vectorize -Wpadded" )
|
||||
elseif ( CMAKE_C_COMPILER_ID STREQUAL "Intel" )
|
||||
set ( OPT_FLAGS "-qopt-report=3" )
|
||||
elseif ( CMAKE_C_COMPILER_ID STREQUAL "GNU" )
|
||||
set ( OPT_FLAGS "-Wpadded" )
|
||||
endif ( )
|
||||
|
||||
set ( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${OPT_FLAGS}" )
|
||||
|
|
1
TODO
1
TODO
|
@ -66,7 +66,6 @@ FluidSynth Next Generation
|
|||
|
||||
Top of the list
|
||||
- Use FIFOs to send events to the audio thread
|
||||
- Redo sfloader api using "interface" api
|
||||
- 3D audio output
|
||||
|
||||
MIDI player
|
||||
|
|
|
@ -112,11 +112,12 @@ Changes in FluidSynth 2.0.0 concerning developers:
|
|||
- add individual reverb setters: fluid_synth_set_reverb_roomsize(), fluid_synth_set_reverb_damp(), fluid_synth_set_reverb_width(), fluid_synth_set_reverb_level()
|
||||
- add individual chorus setters: fluid_synth_set_chorus_nr(), fluid_synth_set_chorus_level(), fluid_synth_set_chorus_speed(), fluid_synth_set_chorus_depth(), fluid_synth_set_chorus_type()
|
||||
- introduce a separate data type for sequencer client IDs: #fluid_seq_id_t
|
||||
- add file callback struct to _fluid_sfloader_t and expose new_fluid_defsfloader() to enable soundfont loading from memory ( see fluid_sfload_mem.c )
|
||||
- add seek support to midi-player, see fluid_player_seek()
|
||||
- expose functions to manipulate the ladspa effects unit (see ladspa.h)
|
||||
- add support for text and lyrics midi events, see fluid_midi_event_set_lyrics() and fluid_midi_event_set_text()
|
||||
- add 24 bit sample support, see _fluid_sample_t::data24
|
||||
- complete rewrite of the soundfont loader API, see sfont.h
|
||||
- support for 24 bit audio samples, see fluid_sample_set_sound_data()
|
||||
- expose new_fluid_defsfloader() to support loading soundfonts from memory, see fluid_sfloader_set_callbacks() and <a href="fluidsynth_sfload_mem_8c-example.html">fluidsynth_sfload_mem.c</a>
|
||||
- add an additional general-purpose IIR filter, see fluid_synth_set_custom_filter()
|
||||
- add a custom sinusoidal modulator mapping function, see #FLUID_MOD_SIN
|
||||
|
||||
|
|
|
@ -46,15 +46,6 @@ long my_tell(void * handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
fluid_file_callbacks_t my_cb =
|
||||
{
|
||||
.fopen = my_open,
|
||||
.fread = my_read,
|
||||
.fseek = my_seek,
|
||||
.fclose = my_close,
|
||||
.ftell = my_tell
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -63,7 +54,12 @@ int main()
|
|||
fluid_synth_t* synth = new_fluid_synth(settings);
|
||||
|
||||
fluid_sfloader_t* my_sfloader = new_fluid_defsfloader(settings);
|
||||
my_sfloader->file_callbacks = &my_cb;
|
||||
fluid_sfloader_set_callbacks(my_sfloader,
|
||||
my_open,
|
||||
my_read,
|
||||
my_seek,
|
||||
my_tell,
|
||||
my_close);
|
||||
fluid_synth_add_sfloader(synth, my_sfloader);
|
||||
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ enum fluid_mod_src
|
|||
|
||||
FLUIDSYNTH_API fluid_mod_t* new_fluid_mod(void);
|
||||
FLUIDSYNTH_API void delete_fluid_mod(fluid_mod_t * mod);
|
||||
FLUIDSYNTH_API size_t fluid_mod_sizeof(void);
|
||||
|
||||
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags);
|
||||
|
|
|
@ -57,12 +57,6 @@ int fluid_ramsfont_izone_set_loop(fluid_ramsfont_t* sfont,
|
|||
unsigned int bank, unsigned int num, fluid_sample_t* sample,
|
||||
int on, float loopstart, float loopend);
|
||||
|
||||
FLUIDSYNTH_API fluid_sample_t* new_fluid_ramsample(void);
|
||||
FLUIDSYNTH_API void delete_fluid_ramsample(fluid_sample_t* sample);
|
||||
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t* sample, const char *name);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_sample_set_sound_data(fluid_sample_t* sample, short *data,
|
||||
unsigned int nbframes, short copy_data, int rootkey);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -83,239 +83,199 @@ enum fluid_sample_type
|
|||
FLUID_SAMPLETYPE_ROM = 0x8000 /**< Indicates ROM samples, causes sample to be ignored */
|
||||
};
|
||||
|
||||
/**
|
||||
* SoundFont loader structure.
|
||||
*/
|
||||
struct _fluid_sfloader_t {
|
||||
void* data; /**< User defined data pointer used by _fluid_sfloader_t::load() */
|
||||
|
||||
/** Callback structure specifying file operations used during soundfont loading to allow custom loading, such as from memory */
|
||||
const fluid_file_callbacks_t* file_callbacks;
|
||||
|
||||
/**
|
||||
* The free method should free the memory allocated for this loader instance in
|
||||
* addition to any private data.
|
||||
* @param loader SoundFont loader
|
||||
*/
|
||||
void (*free)(fluid_sfloader_t* loader);
|
||||
|
||||
/**
|
||||
* Method to load an instrument file (does not actually need to be a real file name,
|
||||
* could be another type of string identifier that the \a loader understands).
|
||||
* @param loader SoundFont loader
|
||||
* @param filename File name or other string identifier
|
||||
* @return The loaded instrument file (SoundFont) or NULL if an error occured.
|
||||
*/
|
||||
fluid_sfont_t* (*load)(fluid_sfloader_t* loader, const char* filename);
|
||||
};
|
||||
|
||||
/**
|
||||
* File callback structure to enable custom soundfont loading (e.g. from memory).
|
||||
* Method to load an instrument file (does not actually need to be a real file name,
|
||||
* could be another type of string identifier that the \a loader understands).
|
||||
* @param loader SoundFont loader
|
||||
* @param filename File name or other string identifier
|
||||
* @return The loaded instrument file (SoundFont) or NULL if an error occured.
|
||||
*/
|
||||
struct _fluid_file_callbacks_t {
|
||||
/**
|
||||
* Opens the file or memory indicated by \c filename in binary read mode.
|
||||
* \c filename matches the one provided during the fluid_synth_sfload() call.
|
||||
*
|
||||
* @return returns a file handle on success, NULL otherwise
|
||||
*/
|
||||
void * (* fopen )(const char * filename);
|
||||
typedef fluid_sfont_t* (*fluid_sfloader_load_t)(fluid_sfloader_t* loader, const char* filename);
|
||||
|
||||
/**
|
||||
* Reads \c count bytes to the specified buffer \c buf.
|
||||
*
|
||||
* @return returns #FLUID_OK if exactly \c count bytes were successfully read, else #FLUID_FAILED
|
||||
*/
|
||||
int (* fread )(void *buf, int count, void * handle);
|
||||
/**
|
||||
* The free method should free the memory allocated for a fluid_sfloader_t instance in
|
||||
* addition to any private data. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfloader() to ensure proper cleanup of the #fluid_sfloader_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfloader() is sufficient.
|
||||
* @param loader SoundFont loader
|
||||
*/
|
||||
typedef void (*fluid_sfloader_free_t)(fluid_sfloader_t* loader);
|
||||
|
||||
/**
|
||||
* Same purpose and behaviour as fseek.
|
||||
*
|
||||
* @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
|
||||
*
|
||||
* @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise */
|
||||
int (* fseek )(void * handle, long offset, int origin);
|
||||
|
||||
/**
|
||||
* Closes the handle and frees used ressources.
|
||||
*
|
||||
* @return returns #FLUID_OK on success, #FLUID_FAILED on error */
|
||||
int (* fclose)(void * handle);
|
||||
|
||||
/** @return returns current file offset or #FLUID_FAILED on error */
|
||||
long (* ftell )(void * handle);
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API fluid_sfloader_t* new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free);
|
||||
FLUIDSYNTH_API void delete_fluid_sfloader(fluid_sfloader_t* loader);
|
||||
|
||||
FLUIDSYNTH_API fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont instance structure.
|
||||
* Opens the file or memory indicated by \c filename in binary read mode.
|
||||
* \c filename matches the string provided during the fluid_synth_sfload() call.
|
||||
*
|
||||
* @return returns a file handle on success, NULL otherwise
|
||||
*/
|
||||
struct _fluid_sfont_t {
|
||||
void* data; /**< User defined data */
|
||||
unsigned int id; /**< SoundFont ID */
|
||||
typedef void * (* fluid_sfloader_callback_open_t )(const char * filename);
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont bank.
|
||||
* @param sfont Virtual SoundFont to free.
|
||||
* @return Should return 0 when it was able to free all resources or non-zero
|
||||
* if some of the samples could not be freed because they are still in use,
|
||||
* in which case the free will be tried again later, until success.
|
||||
*/
|
||||
int (*free)(fluid_sfont_t* sfont);
|
||||
/**
|
||||
* Reads \c count bytes to the specified buffer \c buf.
|
||||
*
|
||||
* @return returns #FLUID_OK if exactly \c count bytes were successfully read, else returns #FLUID_FAILED and leaves \a buf unmodified.
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_read_t )(void *buf, int count, void * handle);
|
||||
|
||||
/**
|
||||
* Method to return the name of a virtual SoundFont.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @return The name of the virtual SoundFont.
|
||||
*/
|
||||
const char* (*get_name)(fluid_sfont_t* sfont);
|
||||
/**
|
||||
* Same purpose and behaviour as fseek.
|
||||
*
|
||||
* @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
|
||||
*
|
||||
* @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_seek_t )(void * handle, long offset, int origin);
|
||||
|
||||
/**
|
||||
* Get a virtual SoundFont preset by bank and program numbers.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param bank MIDI bank number (0-16384)
|
||||
* @param prenum MIDI preset number (0-127)
|
||||
* @return Should return an allocated virtual preset or NULL if it could not
|
||||
* be found.
|
||||
*/
|
||||
fluid_preset_t* (*get_preset)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
/**
|
||||
* Closes the handle returned by #fluid_sfloader_callback_open and frees used ressources.
|
||||
*
|
||||
* @return returns #FLUID_OK on success, #FLUID_FAILED on error
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_close_t )(void * handle);
|
||||
|
||||
/**
|
||||
* Start virtual SoundFont preset iteration method.
|
||||
* @param sfont Virtual SoundFont
|
||||
*
|
||||
* Starts/re-starts virtual preset iteration in a SoundFont.
|
||||
*/
|
||||
void (*iteration_start)(fluid_sfont_t* sfont);
|
||||
/** @return returns current file offset or #FLUID_FAILED on error */
|
||||
typedef long (* fluid_sfloader_callback_tell_t )(void * handle);
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfloader_set_callbacks(fluid_sfloader_t* loader,
|
||||
fluid_sfloader_callback_open_t open,
|
||||
fluid_sfloader_callback_read_t read,
|
||||
fluid_sfloader_callback_seek_t seek,
|
||||
fluid_sfloader_callback_tell_t tell,
|
||||
fluid_sfloader_callback_close_t close);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfloader_set_data(fluid_sfloader_t* loader, void* data);
|
||||
FLUIDSYNTH_API void* fluid_sfloader_get_data(fluid_sfloader_t* loader);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset iteration function.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param preset Caller supplied preset to fill in with current preset information
|
||||
* @return 0 when no more presets are available, 1 otherwise
|
||||
*
|
||||
* Should store preset information to the caller supplied \a preset structure
|
||||
* and advance the internal iteration state to the next preset for subsequent
|
||||
* calls.
|
||||
*/
|
||||
int (*iteration_next)(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset.
|
||||
* Method to return the name of a virtual SoundFont.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @return The name of the virtual SoundFont.
|
||||
*/
|
||||
struct _fluid_preset_t {
|
||||
void* data; /**< User supplied data */
|
||||
fluid_sfont_t* sfont; /**< Parent virtual SoundFont */
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont preset.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return 0
|
||||
*/
|
||||
int (*free)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset name.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return the name of the preset. The returned string must be
|
||||
* valid for the duration of the virtual preset (or the duration of the
|
||||
* SoundFont, in the case of preset iteration).
|
||||
*/
|
||||
const char* (*get_name)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI bank number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The bank number of the preset
|
||||
*/
|
||||
int (*get_banknum)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI program number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The program number of the preset
|
||||
*/
|
||||
int (*get_num)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to handle a noteon event (synthesize the instrument).
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param synth Synthesizer instance
|
||||
* @param chan MIDI channel number of the note on event
|
||||
* @param key MIDI note number (0-127)
|
||||
* @param vel MIDI velocity (0-127)
|
||||
* @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*
|
||||
* Call fluid_synth_alloc_voice() for every sample that has
|
||||
* to be played. fluid_synth_alloc_voice() expects a pointer to a
|
||||
* #fluid_sample_t structure and returns a pointer to the opaque
|
||||
* #fluid_voice_t structure. To set or increment the values of a
|
||||
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
|
||||
* finished initializing the voice call fluid_voice_start() to
|
||||
* start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
|
||||
* created will be started at the same time.
|
||||
*/
|
||||
int (*noteon)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset notify method.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
|
||||
* @param chan MIDI channel number
|
||||
* @return Should return #FLUID_OK
|
||||
*
|
||||
* Implement this optional method if the preset needs to be notified about
|
||||
* preset select and unselect events.
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*/
|
||||
int (*notify)(fluid_preset_t* preset, int reason, int chan);
|
||||
};
|
||||
typedef const char* (*fluid_sfont_get_name_t)(fluid_sfont_t* sfont);
|
||||
|
||||
/**
|
||||
* Get a virtual SoundFont preset by bank and program numbers.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param bank MIDI bank number (0-16383)
|
||||
* @param prenum MIDI preset number (0-127)
|
||||
* @return Should return an allocated virtual preset or NULL if it could not
|
||||
* be found.
|
||||
*/
|
||||
typedef fluid_preset_t* (*fluid_sfont_get_preset_t)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont sample.
|
||||
* Method to free a virtual SoundFont bank. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfont() is sufficient.
|
||||
* @param sfont Virtual SoundFont to free.
|
||||
* @return Should return 0 when it was able to free all resources or non-zero
|
||||
* if some of the samples could not be freed because they are still in use,
|
||||
* in which case the free will be tried again later, until success.
|
||||
*/
|
||||
struct _fluid_sample_t
|
||||
{
|
||||
char name[21]; /**< Sample name */
|
||||
unsigned int start; /**< Start index */
|
||||
unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
|
||||
unsigned int loopstart; /**< Loop start index */
|
||||
unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
|
||||
unsigned int samplerate; /**< Sample rate */
|
||||
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) */
|
||||
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 */
|
||||
typedef int (*fluid_sfont_free_t)(fluid_sfont_t* sfont);
|
||||
|
||||
int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
|
||||
double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
|
||||
|
||||
unsigned int refcount; /**< Count of voices using this sample */
|
||||
FLUIDSYNTH_API fluid_sfont_t* new_fluid_sfont(fluid_sfont_get_name_t get_name,
|
||||
fluid_sfont_get_preset_t get_preset,
|
||||
fluid_sfont_free_t free);
|
||||
FLUIDSYNTH_API int delete_fluid_sfont(fluid_sfont_t* sfont);
|
||||
|
||||
/**
|
||||
* Implement this function to receive notification when sample is no longer used.
|
||||
* @param sample Virtual SoundFont sample
|
||||
* @param reason #FLUID_SAMPLE_DONE only currently
|
||||
* @return Should return #FLUID_OK
|
||||
*/
|
||||
int (*notify)(fluid_sample_t* sample, int reason);
|
||||
FLUIDSYNTH_API int fluid_sfont_set_data(fluid_sfont_t* sfont, void* data);
|
||||
FLUIDSYNTH_API void* fluid_sfont_get_data(fluid_sfont_t* sfont);
|
||||
|
||||
void* userdata; /**< User defined data */
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset name.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return the name of the preset. The returned string must be
|
||||
* valid for the duration of the virtual preset (or the duration of the
|
||||
* SoundFont, in the case of preset iteration).
|
||||
*/
|
||||
typedef const char* (*fluid_preset_get_name_t)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI bank number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The bank number of the preset
|
||||
*/
|
||||
typedef int (*fluid_preset_get_banknum_t)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI program number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The program number of the preset
|
||||
*/
|
||||
typedef int (*fluid_preset_get_num_t)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to handle a noteon event (synthesize the instrument).
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param synth Synthesizer instance
|
||||
* @param chan MIDI channel number of the note on event
|
||||
* @param key MIDI note number (0-127)
|
||||
* @param vel MIDI velocity (0-127)
|
||||
* @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*
|
||||
* Call fluid_synth_alloc_voice() for every sample that has
|
||||
* to be played. fluid_synth_alloc_voice() expects a pointer to a
|
||||
* #fluid_sample_t structure and returns a pointer to the opaque
|
||||
* #fluid_voice_t structure. To set or increment the values of a
|
||||
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
|
||||
* finished initializing the voice call fluid_voice_start() to
|
||||
* start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
|
||||
* created will be started at the same time.
|
||||
*/
|
||||
typedef int (*fluid_preset_noteon_t)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont preset. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_preset() is sufficient.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return 0
|
||||
*/
|
||||
typedef void (*fluid_preset_free_t)(fluid_preset_t* preset);
|
||||
|
||||
FLUIDSYNTH_API fluid_preset_t* new_fluid_preset(fluid_sfont_t* parent_sfont,
|
||||
fluid_preset_get_name_t get_name,
|
||||
fluid_preset_get_banknum_t get_bank,
|
||||
fluid_preset_get_num_t get_num,
|
||||
fluid_preset_noteon_t noteon,
|
||||
fluid_preset_free_t free);
|
||||
FLUIDSYNTH_API void delete_fluid_preset(fluid_preset_t* preset);
|
||||
|
||||
FLUIDSYNTH_API int fluid_preset_set_data(fluid_preset_t* preset, void* data);
|
||||
FLUIDSYNTH_API void* fluid_preset_get_data(fluid_preset_t* preset);
|
||||
|
||||
|
||||
|
||||
FLUIDSYNTH_API fluid_sample_t* new_fluid_sample(void);
|
||||
FLUIDSYNTH_API void delete_fluid_sample(fluid_sample_t* sample);
|
||||
FLUIDSYNTH_API size_t fluid_sample_sizeof(void);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t* sample, const char *name);
|
||||
FLUIDSYNTH_API int fluid_sample_set_sound_data (fluid_sample_t* sample,
|
||||
short *data,
|
||||
char *data24,
|
||||
unsigned int nbframes,
|
||||
unsigned int sample_rate,
|
||||
short copy_data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sample_set_loop(fluid_sample_t* sample, unsigned int loop_start, unsigned int loop_end);
|
||||
FLUIDSYNTH_API int fluid_sample_set_pitch(fluid_sample_t* sample, int root_key, int fine_tune);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ set ( libfluidsynth_SOURCES
|
|||
sfloader/fluid_ramsfont.c
|
||||
sfloader/fluid_ramsfont.h
|
||||
sfloader/fluid_sfont.h
|
||||
sfloader/fluid_sfont.c
|
||||
rvoice/fluid_adsr_env.c
|
||||
rvoice/fluid_adsr_env.h
|
||||
rvoice/fluid_chorus.c
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
|
||||
#include "fluid_defsfont.h"
|
||||
/* Todo: Get rid of that 'include' */
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
|
@ -42,116 +42,59 @@
|
|||
* SFONT LOADER
|
||||
*/
|
||||
|
||||
static void * default_fopen(const char * path)
|
||||
{
|
||||
return FLUID_FOPEN(path, "rb");
|
||||
}
|
||||
|
||||
static int default_fclose(void * handle)
|
||||
{
|
||||
return FLUID_FCLOSE((FILE *)handle);
|
||||
}
|
||||
|
||||
static long default_ftell(void * handle)
|
||||
{
|
||||
return FLUID_FTELL((FILE *)handle);
|
||||
}
|
||||
|
||||
static int safe_fread (void *buf, int count, void * fd)
|
||||
{
|
||||
if (FLUID_FREAD(buf, count, 1, (FILE *)fd) != 1)
|
||||
{
|
||||
if (feof ((FILE *)fd))
|
||||
gerr (ErrEof, _("EOF while attemping to read %d bytes"), count);
|
||||
else
|
||||
FLUID_LOG (FLUID_ERR, _("File read failed"));
|
||||
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
static 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);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
static const fluid_file_callbacks_t def_file_callbacks =
|
||||
{
|
||||
default_fopen,
|
||||
safe_fread,
|
||||
safe_fseek,
|
||||
default_fclose,
|
||||
default_ftell
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a default soundfont2 loader that can be used with fluid_synth_add_sfloader().
|
||||
* By default every synth instance has an initial default soundfont loader instance.
|
||||
* Calling this function is usually only necessary to load a soundfont from memory, by overriding \c fluid_sfloader_t::file_callbacks member.
|
||||
* Calling this function is usually only necessary to load a soundfont from memory, by providing custom callback functions via fluid_sfloader_set_callbacks().
|
||||
*
|
||||
* @param settings A settings instance obtained by new_fluid_settings()
|
||||
* @return A default soundfont2 loader struct
|
||||
*/
|
||||
fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings)
|
||||
{
|
||||
fluid_sfloader_t* loader;
|
||||
|
||||
fluid_sfloader_t* loader;
|
||||
fluid_return_val_if_fail(settings != NULL, NULL);
|
||||
|
||||
loader = FLUID_NEW(fluid_sfloader_t);
|
||||
if (loader == NULL) {
|
||||
loader = new_fluid_sfloader(fluid_defsfloader_load, delete_fluid_sfloader);
|
||||
|
||||
if (loader == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
loader->data = settings;
|
||||
loader->file_callbacks = &def_file_callbacks;
|
||||
loader->free = delete_fluid_defsfloader;
|
||||
loader->load = fluid_defsfloader_load;
|
||||
|
||||
fluid_sfloader_set_data(loader, settings);
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
void delete_fluid_defsfloader(fluid_sfloader_t* loader)
|
||||
{
|
||||
fluid_return_if_fail(loader != NULL);
|
||||
|
||||
FLUID_FREE(loader);
|
||||
}
|
||||
|
||||
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename)
|
||||
{
|
||||
fluid_defsfont_t* defsfont;
|
||||
fluid_sfont_t* sfont;
|
||||
|
||||
defsfont = new_fluid_defsfont(loader->data);
|
||||
defsfont = new_fluid_defsfont(fluid_sfloader_get_data(loader));
|
||||
|
||||
if (defsfont == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fluid_defsfont_load(defsfont, loader->file_callbacks, filename) == FLUID_FAILED) {
|
||||
if (fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED) {
|
||||
delete_fluid_defsfont(defsfont);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sfont = FLUID_NEW(fluid_sfont_t);
|
||||
if (sfont == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
sfont = new_fluid_sfont(fluid_defsfont_sfont_get_name,
|
||||
fluid_defsfont_sfont_get_preset,
|
||||
fluid_defsfont_sfont_delete);
|
||||
if (sfont == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sfont->data = defsfont;
|
||||
sfont->free = fluid_defsfont_sfont_delete;
|
||||
sfont->get_name = fluid_defsfont_sfont_get_name;
|
||||
sfont->get_preset = fluid_defsfont_sfont_get_preset;
|
||||
sfont->iteration_start = fluid_defsfont_sfont_iteration_start;
|
||||
sfont->iteration_next = fluid_defsfont_sfont_iteration_next;
|
||||
|
||||
fluid_sfont_set_iteration_start(sfont, fluid_defsfont_sfont_iteration_start);
|
||||
fluid_sfont_set_iteration_next(sfont, fluid_defsfont_sfont_iteration_next);
|
||||
fluid_sfont_set_data(sfont, defsfont);
|
||||
|
||||
return sfont;
|
||||
}
|
||||
|
@ -165,16 +108,16 @@ fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* file
|
|||
|
||||
int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont)
|
||||
{
|
||||
if (delete_fluid_defsfont(sfont->data) != FLUID_OK) {
|
||||
if (delete_fluid_defsfont(fluid_sfont_get_data(sfont)) != FLUID_OK) {
|
||||
return -1;
|
||||
}
|
||||
FLUID_FREE(sfont);
|
||||
delete_fluid_sfont(sfont);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont)
|
||||
{
|
||||
return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data);
|
||||
return fluid_defsfont_get_name(fluid_sfont_get_data(sfont));
|
||||
}
|
||||
|
||||
fluid_preset_t*
|
||||
|
@ -182,7 +125,7 @@ fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigne
|
|||
{
|
||||
fluid_preset_t* preset = NULL;
|
||||
fluid_defpreset_t* defpreset;
|
||||
fluid_defsfont_t* defsfont = sfont->data;
|
||||
fluid_defsfont_t* defsfont = fluid_sfont_get_data(sfont);
|
||||
|
||||
defpreset = fluid_defsfont_get_preset(defsfont, bank, prenum);
|
||||
|
||||
|
@ -215,7 +158,7 @@ fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigne
|
|||
|
||||
void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont)
|
||||
{
|
||||
fluid_defsfont_iteration_start((fluid_defsfont_t*) sfont->data);
|
||||
fluid_defsfont_iteration_start(fluid_sfont_get_data(sfont));
|
||||
}
|
||||
|
||||
int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset)
|
||||
|
@ -227,12 +170,12 @@ int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* pr
|
|||
preset->noteon = fluid_defpreset_preset_noteon;
|
||||
preset->notify = NULL;
|
||||
|
||||
return fluid_defsfont_iteration_next((fluid_defsfont_t*) sfont->data, preset);
|
||||
return fluid_defsfont_iteration_next(fluid_sfont_get_data(sfont), preset);
|
||||
}
|
||||
|
||||
int fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
||||
void fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
||||
{
|
||||
fluid_defpreset_t* defpreset = preset ? preset->data : NULL;
|
||||
fluid_defpreset_t* defpreset = fluid_preset_get_data(preset);
|
||||
fluid_defsfont_t* sfont = defpreset ? defpreset->sfont : NULL;
|
||||
|
||||
if (sfont && sfont->preset_stack_size < sfont->preset_stack_capacity) {
|
||||
|
@ -240,30 +183,28 @@ int fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
|||
sfont->preset_stack_size++;
|
||||
}
|
||||
else
|
||||
FLUID_FREE(preset);
|
||||
|
||||
return 0;
|
||||
delete_fluid_preset(preset);
|
||||
}
|
||||
|
||||
const char* fluid_defpreset_preset_get_name(fluid_preset_t* preset)
|
||||
{
|
||||
return fluid_defpreset_get_name((fluid_defpreset_t*) preset->data);
|
||||
return fluid_defpreset_get_name(fluid_preset_get_data(preset));
|
||||
}
|
||||
|
||||
int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset)
|
||||
{
|
||||
return fluid_defpreset_get_banknum((fluid_defpreset_t*) preset->data);
|
||||
return fluid_defpreset_get_banknum(fluid_preset_get_data(preset));
|
||||
}
|
||||
|
||||
int fluid_defpreset_preset_get_num(fluid_preset_t* preset)
|
||||
{
|
||||
return fluid_defpreset_get_num((fluid_defpreset_t*) preset->data);
|
||||
return fluid_defpreset_get_num(fluid_preset_get_data(preset));
|
||||
}
|
||||
|
||||
int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth,
|
||||
int chan, int key, int vel)
|
||||
{
|
||||
return fluid_defpreset_noteon((fluid_defpreset_t*) preset->data, synth, chan, key, vel);
|
||||
return fluid_defpreset_noteon(fluid_preset_get_data(preset), synth, chan, key, vel);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1884,44 +1825,6 @@ fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel)
|
|||
* SAMPLE
|
||||
*/
|
||||
|
||||
/*
|
||||
* new_fluid_sample
|
||||
*/
|
||||
fluid_sample_t*
|
||||
new_fluid_sample()
|
||||
{
|
||||
fluid_sample_t* sample = NULL;
|
||||
|
||||
sample = FLUID_NEW(fluid_sample_t);
|
||||
if (sample == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sample, 0, sizeof(fluid_sample_t));
|
||||
sample->valid = 1;
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_sample
|
||||
*/
|
||||
void
|
||||
delete_fluid_sample(fluid_sample_t* sample)
|
||||
{
|
||||
fluid_return_if_fail(sample != NULL);
|
||||
|
||||
if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
|
||||
{
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
FLUID_FREE(sample->data);
|
||||
#endif
|
||||
}
|
||||
|
||||
FLUID_FREE(sample);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_sample_in_rom
|
||||
*/
|
||||
|
@ -2064,6 +1967,7 @@ fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defs
|
|||
|
||||
// point sample data to uncompressed data stream
|
||||
sample->data = sampledata_ogg;
|
||||
sample->auto_free = TRUE;
|
||||
sample->start = 0;
|
||||
sample->end = sfinfo.frames - 1;
|
||||
|
||||
|
@ -2115,6 +2019,8 @@ fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defs
|
|||
/* sample->loopend = sample->end - 8; */
|
||||
/* } */
|
||||
}
|
||||
|
||||
sample->valid = TRUE;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -351,7 +351,6 @@ typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
|
|||
|
||||
*/
|
||||
|
||||
void delete_fluid_defsfloader(fluid_sfloader_t* loader);
|
||||
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename);
|
||||
|
||||
|
||||
|
@ -362,7 +361,7 @@ void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont);
|
|||
int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
|
||||
|
||||
int fluid_defpreset_preset_delete(fluid_preset_t* preset);
|
||||
void fluid_defpreset_preset_delete(fluid_preset_t* preset);
|
||||
const char* fluid_defpreset_preset_get_name(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_get_num(fluid_preset_t* preset);
|
||||
|
@ -500,8 +499,6 @@ fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);
|
|||
|
||||
|
||||
|
||||
fluid_sample_t* new_fluid_sample(void);
|
||||
void delete_fluid_sample(fluid_sample_t* sample);
|
||||
int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont);
|
||||
int fluid_sample_in_rom(fluid_sample_t* sample);
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
#include "fluid_sys.h"
|
||||
#include "fluid_synth.h"
|
||||
|
||||
/* thenumber of samples before the start and after the end */
|
||||
#define SAMPLE_LOOP_MARGIN 8
|
||||
|
||||
/* Prototypes */
|
||||
static int fluid_ramsfont_sfont_delete(fluid_sfont_t* sfont);
|
||||
|
@ -34,7 +32,6 @@ static fluid_preset_t *fluid_ramsfont_sfont_get_preset(fluid_sfont_t* sfont,
|
|||
static void fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont);
|
||||
static int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont,
|
||||
fluid_preset_t* preset);
|
||||
static int fluid_rampreset_preset_delete(fluid_preset_t* preset);
|
||||
static const char *fluid_rampreset_preset_get_name(fluid_preset_t* preset);
|
||||
static int fluid_rampreset_preset_get_banknum(fluid_preset_t* preset);
|
||||
static int fluid_rampreset_preset_get_num(fluid_preset_t* preset);
|
||||
|
@ -94,21 +91,19 @@ fluid_ramsfont_create_sfont()
|
|||
if (ramsfont == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sfont = FLUID_NEW(fluid_sfont_t);
|
||||
if (sfont == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
delete_fluid_ramsfont(ramsfont);
|
||||
|
||||
sfont = new_fluid_sfont(fluid_ramsfont_sfont_get_name,
|
||||
fluid_ramsfont_sfont_get_preset,
|
||||
fluid_ramsfont_sfont_delete);
|
||||
if (sfont == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sfont->data = ramsfont;
|
||||
sfont->free = fluid_ramsfont_sfont_delete;
|
||||
sfont->get_name = fluid_ramsfont_sfont_get_name;
|
||||
sfont->get_preset = fluid_ramsfont_sfont_get_preset;
|
||||
sfont->iteration_start = fluid_ramsfont_sfont_iteration_start;
|
||||
sfont->iteration_next = fluid_ramsfont_sfont_iteration_next;
|
||||
|
||||
|
||||
fluid_sfont_set_iteration_start(sfont, fluid_ramsfont_sfont_iteration_start);
|
||||
fluid_sfont_set_iteration_next(sfont, fluid_ramsfont_sfont_iteration_next);
|
||||
fluid_sfont_set_data(sfont, ramsfont);
|
||||
|
||||
return sfont;
|
||||
}
|
||||
|
||||
|
@ -118,7 +113,7 @@ fluid_ramsfont_sfont_delete(fluid_sfont_t* sfont)
|
|||
{
|
||||
if (delete_fluid_ramsfont(sfont->data) != 0)
|
||||
return -1;
|
||||
FLUID_FREE(sfont);
|
||||
delete_fluid_sfont(sfont);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -142,20 +137,16 @@ fluid_ramsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigne
|
|||
return NULL;
|
||||
}
|
||||
|
||||
preset = FLUID_NEW(fluid_preset_t);
|
||||
preset = new_fluid_preset(sfont,
|
||||
fluid_rampreset_preset_get_name,
|
||||
fluid_rampreset_preset_get_banknum,
|
||||
fluid_rampreset_preset_get_num,
|
||||
fluid_rampreset_preset_noteon,
|
||||
delete_fluid_preset); /* TODO: free modulators */
|
||||
if (preset == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
preset->sfont = sfont;
|
||||
preset->data = rampreset;
|
||||
preset->free = fluid_rampreset_preset_delete;
|
||||
preset->get_name = fluid_rampreset_preset_get_name;
|
||||
preset->get_banknum = fluid_rampreset_preset_get_banknum;
|
||||
preset->get_num = fluid_rampreset_preset_get_num;
|
||||
preset->noteon = fluid_rampreset_preset_noteon;
|
||||
preset->notify = NULL;
|
||||
fluid_preset_set_data(preset, rampreset);
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
@ -171,7 +162,7 @@ fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont)
|
|||
static int
|
||||
fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset)
|
||||
{
|
||||
preset->free = fluid_rampreset_preset_delete;
|
||||
preset->free = delete_fluid_preset;
|
||||
preset->get_name = fluid_rampreset_preset_get_name;
|
||||
preset->get_banknum = fluid_rampreset_preset_get_banknum;
|
||||
preset->get_num = fluid_rampreset_preset_get_num;
|
||||
|
@ -181,17 +172,6 @@ fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset
|
|||
return fluid_ramsfont_iteration_next((fluid_ramsfont_t*) sfont->data, preset);
|
||||
}
|
||||
|
||||
/* RAM SoundFont loader delete preset method */
|
||||
static int
|
||||
fluid_rampreset_preset_delete(fluid_preset_t* preset)
|
||||
{
|
||||
FLUID_FREE(preset);
|
||||
|
||||
/* TODO: free modulators */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RAM SoundFont loader get preset name method */
|
||||
static const char *
|
||||
fluid_rampreset_preset_get_name(fluid_preset_t* preset)
|
||||
|
@ -264,7 +244,7 @@ delete_fluid_ramsfont (fluid_ramsfont_t* sfont)
|
|||
for (list = sfont->sample; list; list = fluid_list_next(list)) {
|
||||
/* in ram soundfonts, the samples hold their data : so we should free it ourselves */
|
||||
fluid_sample_t* sam = (fluid_sample_t*)fluid_list_get(list);
|
||||
delete_fluid_ramsample(sam);
|
||||
delete_fluid_sample(sam);
|
||||
}
|
||||
|
||||
if (sfont->sample) {
|
||||
|
@ -1096,128 +1076,3 @@ fluid_rampreset_noteon (fluid_rampreset_t* preset, fluid_synth_t* synth, int cha
|
|||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* SAMPLE
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of a RAM SoundFont sample.
|
||||
* @param sample RAM SoundFont sample
|
||||
* @param name Name to assign to sample (20 chars in length, 0 terminated)
|
||||
* @return #FLUID_OK
|
||||
*/
|
||||
int
|
||||
fluid_sample_set_name(fluid_sample_t* sample, const char *name)
|
||||
{
|
||||
FLUID_MEMCPY(sample->name, name, 20);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign sample data to a RAM SoundFont sample.
|
||||
* @param sample RAM SoundFont sample
|
||||
* @param data Buffer containing 16 bit audio sample data
|
||||
* @param nbframes Number of samples in \a data
|
||||
* @param copy_data TRUE to copy the data, FALSE to use it directly
|
||||
* @param rootkey Root MIDI note of sample (0-127)
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
* WARNING: If \a copy_data is FALSE, data should have 8 unused frames at start
|
||||
* and 8 unused frames at the end.
|
||||
*/
|
||||
int
|
||||
fluid_sample_set_sound_data (fluid_sample_t* sample, short *data,
|
||||
unsigned int nbframes, short copy_data, int rootkey)
|
||||
{
|
||||
/* 16 bit mono 44.1KHz data in */
|
||||
/* in all cases, the sample has ownership of the data : it will release it in the end */
|
||||
unsigned int storedNbFrames;
|
||||
|
||||
/* in case we already have some data */
|
||||
if (sample->data != NULL) {
|
||||
FLUID_FREE(sample->data);
|
||||
}
|
||||
|
||||
if (copy_data) {
|
||||
|
||||
/* nbframes should be >= 48 (SoundFont specs) */
|
||||
storedNbFrames = nbframes;
|
||||
if (storedNbFrames < 48) storedNbFrames = 48;
|
||||
|
||||
sample->data = FLUID_MALLOC(storedNbFrames*2 + 4*SAMPLE_LOOP_MARGIN);
|
||||
if (sample->data == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
FLUID_MEMSET(sample->data, 0, storedNbFrames*2 + 4*SAMPLE_LOOP_MARGIN);
|
||||
FLUID_MEMCPY((char*)(sample->data) + 2*SAMPLE_LOOP_MARGIN, data, nbframes*2);
|
||||
|
||||
#if 0
|
||||
/* this would do the fill of the margins */
|
||||
FLUID_MEMCPY((char*)(sample->data) + 2*SAMPLE_LOOP_MARGIN + storedNbFrames*2, (char*)data, 2*SAMPLE_LOOP_MARGIN);
|
||||
FLUID_MEMCPY((char*)(sample->data), (char*)data + nbframes*2 - 2*SAMPLE_LOOP_MARGIN, 2*SAMPLE_LOOP_MARGIN);
|
||||
#endif
|
||||
|
||||
/* pointers */
|
||||
/* all from the start of data */
|
||||
sample->start = SAMPLE_LOOP_MARGIN;
|
||||
sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames;
|
||||
} else {
|
||||
/* we cannot assure the SAMPLE_LOOP_MARGIN */
|
||||
sample->data = data;
|
||||
sample->start = 0;
|
||||
sample->end = nbframes;
|
||||
}
|
||||
|
||||
/* only used as markers for the LOOP generators : set them on the first real frame */
|
||||
sample->loopstart = sample->start;
|
||||
sample->loopend = sample->end;
|
||||
|
||||
sample->samplerate = 44100;
|
||||
sample->origpitch = rootkey;
|
||||
sample->pitchadj = 0;
|
||||
sample->sampletype = FLUID_SAMPLETYPE_MONO;
|
||||
sample->valid = 1;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new RAM SoundFont sample.
|
||||
* @return New RAM SoundFont sample or NULL if out of memory
|
||||
*/
|
||||
fluid_sample_t *
|
||||
new_fluid_ramsample (void)
|
||||
{
|
||||
/* same as new_fluid_sample. Only here so that it is exported */
|
||||
fluid_sample_t* sample = NULL;
|
||||
|
||||
sample = FLUID_NEW(fluid_sample_t);
|
||||
if (sample == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sample, 0, sizeof(fluid_sample_t));
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a RAM SoundFont sample.
|
||||
* @param sample Sample to delete
|
||||
*/
|
||||
void
|
||||
delete_fluid_ramsample (fluid_sample_t* sample)
|
||||
{
|
||||
fluid_return_if_fail(sample != NULL);
|
||||
|
||||
/* same as delete_fluid_sample, plus frees the data */
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "fluidsynth.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_defsfont.h"
|
||||
|
||||
|
||||
|
|
548
src/sfloader/fluid_sfont.c
Normal file
548
src/sfloader/fluid_sfont.c
Normal file
|
@ -0,0 +1,548 @@
|
|||
/* 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
|
||||
*/
|
||||
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
void * default_fopen(const char * path)
|
||||
{
|
||||
return FLUID_FOPEN(path, "rb");
|
||||
}
|
||||
|
||||
int default_fclose(void * handle)
|
||||
{
|
||||
return FLUID_FCLOSE((FILE *)handle) == 0 ? FLUID_OK : FLUID_FAILED;
|
||||
}
|
||||
|
||||
long default_ftell(void * handle)
|
||||
{
|
||||
return FLUID_FTELL((FILE *)handle);
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
FLUID_LOG (FLUID_ERR, _("File read failed"));
|
||||
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
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);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SoundFont loader.
|
||||
*
|
||||
* @param load Pointer to a function that provides a #fluid_sfont_t (see #fluid_sfloader_load_t).
|
||||
* @param free Pointer to a function that destroys this instance (see #fluid_sfloader_free_t).
|
||||
* Unless any private data needs to be freed it is sufficient to set this to delete_fluid_sfloader().
|
||||
*
|
||||
* @return the SoundFont loader instance on success, NULL otherwise.
|
||||
*/
|
||||
fluid_sfloader_t* new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free)
|
||||
{
|
||||
fluid_sfloader_t *loader;
|
||||
|
||||
fluid_return_val_if_fail(load != NULL, NULL);
|
||||
fluid_return_val_if_fail(free != NULL, NULL);
|
||||
|
||||
loader = FLUID_NEW(fluid_sfloader_t);
|
||||
if (loader == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(loader, 0, sizeof(*loader));
|
||||
|
||||
loader->load = load;
|
||||
loader->free = free;
|
||||
fluid_sfloader_set_callbacks(loader,
|
||||
default_fopen,
|
||||
safe_fread,
|
||||
safe_fseek,
|
||||
default_ftell,
|
||||
default_fclose);
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a SoundFont loader created with new_fluid_sfloader().
|
||||
*
|
||||
* @param loader The SoundFont loader instance to free.
|
||||
*/
|
||||
void delete_fluid_sfloader(fluid_sfloader_t* loader)
|
||||
{
|
||||
fluid_return_if_fail(loader != NULL);
|
||||
|
||||
FLUID_FREE(loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify private data to be used by #fluid_sfloader_load_t.
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @param data The private data to store.
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sfloader_set_data(fluid_sfloader_t* loader, void* data)
|
||||
{
|
||||
fluid_return_val_if_fail(loader != NULL, FLUID_FAILED);
|
||||
|
||||
loader->data = data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain private data previously set with fluid_sfloader_set_data().
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @return The private data or NULL if none explicitly set before.
|
||||
*/
|
||||
void* fluid_sfloader_get_data(fluid_sfloader_t* loader)
|
||||
{
|
||||
fluid_return_val_if_fail(loader != NULL, NULL);
|
||||
|
||||
return loader->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom callbacks to be used upon soundfont loading.
|
||||
*
|
||||
* Useful for loading a soundfont from memory, see \a doc/fluidsynth_sfload_mem.c as an example.
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @param open A function implementing #fluid_sfloader_callback_open_t.
|
||||
* @param read A function implementing #fluid_sfloader_callback_read_t.
|
||||
* @param seek A function implementing #fluid_sfloader_callback_seek_t.
|
||||
* @param tell A function implementing #fluid_sfloader_callback_tell_t.
|
||||
* @param close A function implementing #fluid_sfloader_callback_close_t.
|
||||
* @return #FLUID_OK if the callbacks have been successfully set, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sfloader_set_callbacks(fluid_sfloader_t* loader,
|
||||
fluid_sfloader_callback_open_t open,
|
||||
fluid_sfloader_callback_read_t read,
|
||||
fluid_sfloader_callback_seek_t seek,
|
||||
fluid_sfloader_callback_tell_t tell,
|
||||
fluid_sfloader_callback_close_t close)
|
||||
{
|
||||
fluid_file_callbacks_t *cb;
|
||||
|
||||
fluid_return_val_if_fail(loader != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(open != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(read != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(seek != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(tell != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(close != NULL, FLUID_FAILED);
|
||||
|
||||
cb = &loader->file_callbacks;
|
||||
|
||||
cb->fopen = open;
|
||||
cb->fread = read;
|
||||
cb->fseek = seek;
|
||||
cb->ftell = tell;
|
||||
cb->fclose = close;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new virtual SoundFont instance structure.
|
||||
* @param get_name A function implementing #fluid_sfont_get_name_t.
|
||||
* @param get_preset A function implementing #fluid_sfont_get_preset_t.
|
||||
* @param free A function implementing #fluid_sfont_free_t.
|
||||
* @return The soundfont instance on success or NULL otherwise.
|
||||
*/
|
||||
fluid_sfont_t* new_fluid_sfont(fluid_sfont_get_name_t get_name,
|
||||
fluid_sfont_get_preset_t get_preset,
|
||||
fluid_sfont_free_t free)
|
||||
{
|
||||
fluid_sfont_t* sfont;
|
||||
|
||||
fluid_return_val_if_fail(get_name != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_preset != NULL, NULL);
|
||||
fluid_return_val_if_fail(free != NULL, NULL);
|
||||
|
||||
sfont = FLUID_NEW(fluid_sfont_t);
|
||||
if (sfont == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(sfont, 0, sizeof(*sfont));
|
||||
|
||||
sfont->get_name = get_name;
|
||||
sfont->get_preset = get_preset;
|
||||
sfont->free = free;
|
||||
|
||||
return sfont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set private data to use with a SoundFont instance.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @param data The private data to store.
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sfont_set_data(fluid_sfont_t* sfont, void* data)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED);
|
||||
|
||||
sfont->data = data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the private data of a SoundFont instance.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @return The private data or NULL if none explicitly set before.
|
||||
*/
|
||||
void* fluid_sfont_get_data(fluid_sfont_t* sfont)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, NULL);
|
||||
|
||||
return sfont->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal KISS! No need to expose this to public API currently.
|
||||
*/
|
||||
void fluid_sfont_set_iteration_start(fluid_sfont_t* sfont, fluid_sfont_iteration_start_t iter_start)
|
||||
{
|
||||
sfont->iteration_start = iter_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal KISS! No need to expose this to public API currently.
|
||||
*/
|
||||
void fluid_sfont_set_iteration_next(fluid_sfont_t* sfont, fluid_sfont_iteration_next_t iter_next)
|
||||
{
|
||||
sfont->iteration_next = iter_next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a SoundFont instance created with new_fluid_sfont().
|
||||
*
|
||||
* Implements #fluid_sfont_free_t.
|
||||
*
|
||||
* @param sfont The SoundFont instance to destroy.
|
||||
* @return Always returns 0.
|
||||
*/
|
||||
int delete_fluid_sfont(fluid_sfont_t* sfont)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, 0);
|
||||
|
||||
FLUID_FREE(sfont);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a virtual SoundFont preset instance.
|
||||
*
|
||||
* @param parent_sfont The SoundFont instance this preset shall belong to
|
||||
* @param get_name A function implementing #fluid_preset_get_name_t
|
||||
* @param get_bank A function implementing #fluid_preset_get_banknum_t
|
||||
* @param get_num A function implementing #fluid_preset_get_num_t
|
||||
* @param noteon A function implementing #fluid_preset_noteon_t
|
||||
* @param free A function implementing #fluid_preset_free_t
|
||||
* @return The preset instance on success, NULL otherwise.
|
||||
*/
|
||||
fluid_preset_t* new_fluid_preset(fluid_sfont_t* parent_sfont,
|
||||
fluid_preset_get_name_t get_name,
|
||||
fluid_preset_get_banknum_t get_bank,
|
||||
fluid_preset_get_num_t get_num,
|
||||
fluid_preset_noteon_t noteon,
|
||||
fluid_preset_free_t free)
|
||||
{
|
||||
fluid_preset_t* preset;
|
||||
|
||||
fluid_return_val_if_fail(parent_sfont != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_name != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_bank != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_num != NULL, NULL);
|
||||
fluid_return_val_if_fail(noteon != NULL, NULL);
|
||||
fluid_return_val_if_fail(free != NULL, NULL);
|
||||
|
||||
preset = FLUID_NEW(fluid_preset_t);
|
||||
if (preset == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(preset, 0, sizeof(*preset));
|
||||
|
||||
preset->sfont = parent_sfont;
|
||||
preset->get_name = get_name;
|
||||
preset->get_banknum = get_bank;
|
||||
preset->get_num = get_num;
|
||||
preset->noteon = noteon;
|
||||
preset->free = free;
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set private data to use with a SoundFont preset instance.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @param data The private data to store.
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_preset_set_data(fluid_preset_t* preset, void* data)
|
||||
{
|
||||
fluid_return_val_if_fail(preset != NULL, FLUID_FAILED);
|
||||
|
||||
preset->data = data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the private data of a SoundFont preset instance.
|
||||
*
|
||||
* @param sfont The SoundFont preset instance.
|
||||
* @return The private data or NULL if none explicitly set before.
|
||||
*/
|
||||
void* fluid_preset_get_data(fluid_preset_t* preset)
|
||||
{
|
||||
fluid_return_val_if_fail(preset != NULL, NULL);
|
||||
|
||||
return preset->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a SoundFont preset instance created with new_fluid_preset().
|
||||
*
|
||||
* Implements #fluid_preset_free_t.
|
||||
*
|
||||
* @param preset The SoundFont preset instance to destroy.
|
||||
*/
|
||||
void delete_fluid_preset(fluid_preset_t* preset)
|
||||
{
|
||||
fluid_return_if_fail(preset != NULL);
|
||||
|
||||
FLUID_FREE(preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sample instance.
|
||||
* @return The sample on success, NULL otherwise.
|
||||
*/
|
||||
fluid_sample_t*
|
||||
new_fluid_sample()
|
||||
{
|
||||
fluid_sample_t* sample = NULL;
|
||||
|
||||
sample = FLUID_NEW(fluid_sample_t);
|
||||
if (sample == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(sample, 0, sizeof(*sample));
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a sample instance previously created with new_fluid_sample().
|
||||
* @param sample The sample to destroy.
|
||||
*/
|
||||
void
|
||||
delete_fluid_sample(fluid_sample_t* sample)
|
||||
{
|
||||
fluid_return_if_fail(sample != NULL);
|
||||
|
||||
if (sample->auto_free)
|
||||
{
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample->data24);
|
||||
}
|
||||
|
||||
FLUID_FREE(sample);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the fluid_sample_t structure.
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a sample on the stack.
|
||||
*/
|
||||
size_t fluid_sample_sizeof()
|
||||
{
|
||||
return sizeof(fluid_sample_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of a SoundFont sample.
|
||||
* @param sample SoundFont sample
|
||||
* @param name Name to assign to sample (20 chars in length + zero terminator)
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*/
|
||||
int fluid_sample_set_name(fluid_sample_t* sample, const char *name)
|
||||
{
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
|
||||
|
||||
FLUID_STRNCPY(sample->name, name, sizeof(sample->name));
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign sample data to a SoundFont sample.
|
||||
* @param sample SoundFont sample
|
||||
* @param data Buffer containing 16 bit (mono-)audio sample data
|
||||
* @param data24 If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples
|
||||
* @param nbframes Number of samples in \a data
|
||||
* @param sample_rate Sampling rate of the sample data
|
||||
* @param copy_data TRUE to copy the sample data (and automatically free it upon delete_fluid_sample()), FALSE to use it directly (and not free it)
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
* @note If \a copy_data is FALSE, data should have 8 unused frames at start
|
||||
* and 8 unused frames at the end and \a nbframes should be >=48
|
||||
*/
|
||||
int
|
||||
fluid_sample_set_sound_data (fluid_sample_t* sample,
|
||||
short *data,
|
||||
char *data24,
|
||||
unsigned int nbframes,
|
||||
unsigned int sample_rate,
|
||||
short copy_data
|
||||
)
|
||||
{
|
||||
/* the number of samples before the start and after the end */
|
||||
#define SAMPLE_LOOP_MARGIN 8U
|
||||
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(data != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(nbframes == 0, FLUID_FAILED);
|
||||
|
||||
/* in case we already have some data */
|
||||
if ((sample->data != NULL || sample->data24 != NULL) && sample->auto_free)
|
||||
{
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample->data24);
|
||||
}
|
||||
|
||||
if (copy_data)
|
||||
{
|
||||
unsigned int storedNbFrames;
|
||||
|
||||
/* nbframes should be >= 48 (SoundFont specs) */
|
||||
storedNbFrames = nbframes;
|
||||
if (storedNbFrames < 48) storedNbFrames = 48;
|
||||
|
||||
storedNbFrames += 2*SAMPLE_LOOP_MARGIN;
|
||||
|
||||
sample->data = FLUID_ARRAY(short, storedNbFrames);
|
||||
if (sample->data == NULL)
|
||||
{
|
||||
goto error_rec;
|
||||
}
|
||||
FLUID_MEMSET(sample->data, 0, storedNbFrames);
|
||||
FLUID_MEMCPY(sample->data + SAMPLE_LOOP_MARGIN, data, nbframes*sizeof(short));
|
||||
|
||||
if(data24 != NULL)
|
||||
{
|
||||
sample->data24 = FLUID_ARRAY(char, storedNbFrames);
|
||||
if (sample->data24 == NULL)
|
||||
{
|
||||
goto error_rec;
|
||||
}
|
||||
FLUID_MEMSET(sample->data24, 0, storedNbFrames);
|
||||
FLUID_MEMCPY(sample->data24 + SAMPLE_LOOP_MARGIN, data24, nbframes*sizeof(char));
|
||||
}
|
||||
|
||||
/* pointers */
|
||||
/* all from the start of data */
|
||||
sample->start = SAMPLE_LOOP_MARGIN;
|
||||
sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we cannot assure the SAMPLE_LOOP_MARGIN */
|
||||
sample->data = data;
|
||||
sample->data24 = data24;
|
||||
sample->start = 0;
|
||||
sample->end = nbframes - 1;
|
||||
}
|
||||
|
||||
sample->samplerate = sample_rate;
|
||||
sample->sampletype = FLUID_SAMPLETYPE_MONO;
|
||||
sample->valid = 1;
|
||||
sample->auto_free = copy_data;
|
||||
|
||||
return FLUID_OK;
|
||||
|
||||
error_rec:
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample->data24);
|
||||
return FLUID_FAILED;
|
||||
|
||||
#undef SAMPLE_LOOP_MARGIN
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loop of a sample.
|
||||
*
|
||||
* @param loop_start Start sample index of the loop.
|
||||
* @param loop_end End index of the loop (must be a valid sample as it marks the last sample to be played).
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sample_set_loop(fluid_sample_t* sample, unsigned int loop_start, unsigned int loop_end)
|
||||
{
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
|
||||
sample->loopstart = loop_start;
|
||||
sample->loopend = loop_end;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pitch of a sample.
|
||||
*
|
||||
* @param rootkey Root MIDI note of sample (0-127)
|
||||
* @param fine_tune Fine tune in cents
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sample_set_pitch(fluid_sample_t* sample, int root_key, int fine_tune)
|
||||
{
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(0<=root_key && root_key<=127, FLUID_FAILED);
|
||||
|
||||
sample->origpitch = root_key;
|
||||
sample->pitchadj = fine_tune;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
#ifndef _PRIV_FLUID_SFONT_H
|
||||
#define _PRIV_FLUID_SFONT_H
|
||||
|
||||
#include "fluidsynth.h"
|
||||
|
||||
/*
|
||||
* Utility macros to access soundfonts, presets, and samples
|
||||
|
@ -31,22 +32,18 @@
|
|||
#define fluid_sfloader_load(_loader, _filename) (*(_loader)->load)(_loader, _filename)
|
||||
|
||||
|
||||
#define delete_fluid_sfont(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
|
||||
#define fluid_sfont_delete_internal(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
|
||||
|
||||
#define fluid_sfont_get_id(_sf) ((_sf)->id)
|
||||
#define fluid_sfont_get_name(_sf) (*(_sf)->get_name)(_sf)
|
||||
#define fluid_sfont_get_preset(_sf,_bank,_prenum) (*(_sf)->get_preset)(_sf,_bank,_prenum)
|
||||
#define fluid_sfont_iteration_start(_sf) (*(_sf)->iteration_start)(_sf)
|
||||
#define fluid_sfont_iteration_next(_sf,_pr) (*(_sf)->iteration_next)(_sf,_pr)
|
||||
#define fluid_sfont_get_data(_sf) (_sf)->data
|
||||
#define fluid_sfont_set_data(_sf,_p) { (_sf)->data = (void*) (_p); }
|
||||
#define fluid_sfont_iteration_start(_sf) { if((_sf) && (_sf)->iteration_start) (*(_sf)->iteration_start)(_sf); }
|
||||
#define fluid_sfont_iteration_next(_sf,_pr) (((_sf) && (_sf)->iteration_start) ? (*(_sf)->iteration_next)(_sf,_pr) : 0)
|
||||
|
||||
|
||||
#define delete_fluid_preset(_preset) \
|
||||
#define fluid_preset_delete_internal(_preset) \
|
||||
{ if ((_preset) && (_preset)->free) { (*(_preset)->free)(_preset); }}
|
||||
|
||||
#define fluid_preset_get_data(_preset) (_preset)->data
|
||||
#define fluid_preset_set_data(_preset,_p) { (_preset)->data = (void*) (_p); }
|
||||
#define fluid_preset_get_name(_preset) (*(_preset)->get_name)(_preset)
|
||||
#define fluid_preset_get_banknum(_preset) (*(_preset)->get_banknum)(_preset)
|
||||
#define fluid_preset_get_num(_preset) (*(_preset)->get_num)(_preset)
|
||||
|
@ -67,4 +64,141 @@
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* File callback structure to enable custom soundfont loading (e.g. from memory).
|
||||
*/
|
||||
struct _fluid_file_callbacks_t
|
||||
{
|
||||
fluid_sfloader_callback_open_t fopen;
|
||||
fluid_sfloader_callback_read_t fread;
|
||||
fluid_sfloader_callback_seek_t fseek;
|
||||
fluid_sfloader_callback_close_t fclose;
|
||||
fluid_sfloader_callback_tell_t ftell;
|
||||
};
|
||||
|
||||
/**
|
||||
* SoundFont loader structure.
|
||||
*/
|
||||
struct _fluid_sfloader_t {
|
||||
void* data; /**< User defined data pointer used by _fluid_sfloader_t::load() */
|
||||
|
||||
/** Callback structure specifying file operations used during soundfont loading to allow custom loading, such as from memory */
|
||||
fluid_file_callbacks_t file_callbacks;
|
||||
|
||||
fluid_sfloader_free_t free;
|
||||
|
||||
fluid_sfloader_load_t load;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start virtual SoundFont preset iteration method.
|
||||
* @param sfont Virtual SoundFont
|
||||
*
|
||||
* Starts/re-starts virtual preset iteration in a SoundFont.
|
||||
*/
|
||||
typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t* sfont);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset iteration function.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param preset Caller supplied uninitialized buffer to fill in with current preset information
|
||||
* @return 0 when no more presets are available, 1 otherwise
|
||||
*
|
||||
* Should store preset information to the caller supplied \a preset structure
|
||||
* and advance the internal iteration state to the next preset for subsequent
|
||||
* calls.
|
||||
*/
|
||||
typedef int (*fluid_sfont_iteration_next_t)(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
|
||||
void fluid_sfont_set_iteration_start(fluid_sfont_t* sfont, fluid_sfont_iteration_start_t iter_start);
|
||||
void fluid_sfont_set_iteration_next(fluid_sfont_t* sfont, fluid_sfont_iteration_next_t iter_next);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont instance structure.
|
||||
*/
|
||||
struct _fluid_sfont_t {
|
||||
void* data; /**< User defined data */
|
||||
unsigned int id; /**< SoundFont ID */
|
||||
|
||||
fluid_sfont_free_t free;
|
||||
|
||||
fluid_sfont_get_name_t get_name;
|
||||
|
||||
fluid_sfont_get_preset_t get_preset;
|
||||
|
||||
fluid_sfont_iteration_start_t iteration_start;
|
||||
|
||||
fluid_sfont_iteration_next_t iteration_next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset.
|
||||
*/
|
||||
struct _fluid_preset_t {
|
||||
void* data; /**< User supplied data */
|
||||
fluid_sfont_t* sfont; /**< Parent virtual SoundFont */
|
||||
|
||||
fluid_preset_free_t free;
|
||||
|
||||
fluid_preset_get_name_t get_name;
|
||||
|
||||
fluid_preset_get_banknum_t get_banknum;
|
||||
|
||||
fluid_preset_get_num_t get_num;
|
||||
|
||||
fluid_preset_noteon_t noteon;
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset notify method.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
|
||||
* @param chan MIDI channel number
|
||||
* @return Should return #FLUID_OK
|
||||
*
|
||||
* Implement this optional method if the preset needs to be notified about
|
||||
* preset select and unselect events.
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*/
|
||||
int (*notify)(fluid_preset_t* preset, int reason, int chan);
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont sample.
|
||||
*/
|
||||
struct _fluid_sample_t
|
||||
{
|
||||
char name[21]; /**< Sample name */
|
||||
unsigned int start; /**< Start index */
|
||||
unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
|
||||
unsigned int loopstart; /**< Loop start index */
|
||||
unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
|
||||
unsigned int samplerate; /**< Sample rate */
|
||||
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 */
|
||||
|
||||
int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
|
||||
double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
|
||||
|
||||
unsigned int refcount; /**< Count of voices using this sample */
|
||||
|
||||
/**
|
||||
* Implement this function to receive notification when sample is no longer used.
|
||||
* @param sample Virtual SoundFont sample
|
||||
* @param reason #FLUID_SAMPLE_DONE only currently
|
||||
* @return Should return #FLUID_OK
|
||||
*/
|
||||
int (*notify)(fluid_sample_t* sample, int reason);
|
||||
|
||||
void* userdata; /**< User defined data */
|
||||
};
|
||||
|
||||
|
||||
#endif /* _PRIV_FLUID_SFONT_H */
|
||||
|
|
|
@ -185,7 +185,7 @@ delete_fluid_channel(fluid_channel_t* chan)
|
|||
{
|
||||
fluid_return_if_fail(chan != NULL);
|
||||
|
||||
delete_fluid_preset (chan->preset);
|
||||
fluid_preset_delete_internal (chan->preset);
|
||||
FLUID_FREE(chan);
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
|
|||
if (chan->preset) {
|
||||
fluid_sfont_t *sfont;
|
||||
sfont = chan->preset->sfont;
|
||||
delete_fluid_preset (chan->preset);
|
||||
fluid_preset_delete_internal (chan->preset);
|
||||
fluid_synth_sfont_unref (chan->synth, sfont); /* -- unref preset's SoundFont */
|
||||
}
|
||||
|
||||
|
|
|
@ -442,6 +442,16 @@ delete_fluid_mod (fluid_mod_t *mod)
|
|||
FLUID_FREE(mod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the fluid_mod_t structure.
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a modulator on the stack.
|
||||
*/
|
||||
size_t fluid_mod_sizeof()
|
||||
{
|
||||
return sizeof(fluid_mod_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if two modulators are identical in sources, flags and destination.
|
||||
* @param mod1 First modulator
|
||||
|
|
|
@ -848,7 +848,7 @@ delete_fluid_synth(fluid_synth_t* synth)
|
|||
/* delete all the SoundFonts */
|
||||
for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
|
||||
sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
|
||||
delete_fluid_sfont (sfont_info->sfont);
|
||||
fluid_sfont_delete_internal (sfont_info->sfont);
|
||||
FLUID_FREE (sfont_info);
|
||||
}
|
||||
|
||||
|
@ -3432,7 +3432,7 @@ fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets
|
|||
|
||||
if (!sfont_info)
|
||||
{
|
||||
delete_fluid_sfont (sfont);
|
||||
fluid_sfont_delete_internal (sfont);
|
||||
FLUID_API_RETURN(FLUID_FAILED);
|
||||
}
|
||||
|
||||
|
@ -3537,7 +3537,7 @@ fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont)
|
|||
|
||||
if (refcount == 0) /* No more references? - Attempt delete */
|
||||
{
|
||||
if (delete_fluid_sfont (sfont_info->sfont) == 0) /* SoundFont loader can block SoundFont unload */
|
||||
if (fluid_sfont_delete_internal (sfont_info->sfont) == 0) /* SoundFont loader can block SoundFont unload */
|
||||
{
|
||||
FLUID_FREE (sfont_info);
|
||||
FLUID_LOG (FLUID_DBG, "Unloaded SoundFont");
|
||||
|
@ -3553,7 +3553,7 @@ fluid_synth_sfunload_callback(void* data, unsigned int msec)
|
|||
{
|
||||
fluid_sfont_info_t *sfont_info = (fluid_sfont_info_t *)data;
|
||||
|
||||
if (delete_fluid_sfont (sfont_info->sfont) == 0)
|
||||
if (fluid_sfont_delete_internal (sfont_info->sfont) == 0)
|
||||
{
|
||||
FLUID_FREE (sfont_info);
|
||||
FLUID_LOG (FLUID_DBG, "Unloaded SoundFont");
|
||||
|
@ -3612,7 +3612,7 @@ fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
|
|||
|
||||
if (!sfont_info)
|
||||
{
|
||||
delete_fluid_sfont (sfont);
|
||||
fluid_sfont_delete_internal (sfont);
|
||||
FLUID_API_RETURN(FLUID_FAILED);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue