2003-03-11 16:56:45 +00:00
/* FluidSynth - A Software Synthesizer
*
* Copyright ( C ) 2003 Peter Hanappe and others .
*
* This library is free software ; you can redistribute it and / or
2017-07-12 15:45:23 +00:00
* modify it under the terms of the GNU Lesser General Public License
2017-07-12 15:53:03 +00:00
* as published by the Free Software Foundation ; either version 2.1 of
2003-03-11 16:56:45 +00:00
* 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
2017-07-12 15:45:23 +00:00
* Lesser General Public License for more details .
2007-03-04 16:45:05 +00:00
*
2017-07-12 15:54:54 +00:00
* You should have received a copy of the GNU Lesser General Public
2003-03-11 16:56:45 +00:00
* License along with this library ; if not , write to the Free
2011-08-15 12:57:10 +00:00
* Software Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA
2003-03-11 16:56:45 +00:00
*/
2006-11-21 20:04:31 +00:00
# include <math.h>
2003-03-11 16:56:45 +00:00
# include "fluid_synth.h"
# include "fluid_sys.h"
# include "fluid_chan.h"
# include "fluid_tuning.h"
# include "fluid_settings.h"
# include "fluid_sfont.h"
2009-09-22 07:04:07 +00:00
# include "fluid_hash.h"
2012-12-08 06:25:21 +00:00
# include "fluid_defsfont.h"
2003-03-11 16:56:45 +00:00
2007-11-11 20:52:56 +00:00
# ifdef TRAP_ON_FPE
# define _GNU_SOURCE
# include <fenv.h>
/* seems to not be declared in fenv.h */
extern int feenableexcept ( int excepts ) ;
# endif
2009-06-07 05:16:47 +00:00
static void fluid_synth_init ( void ) ;
2010-07-14 08:44:51 +00:00
2009-09-22 07:04:07 +00:00
static int fluid_synth_noteon_LOCAL ( fluid_synth_t * synth , int chan , int key ,
int vel ) ;
static int fluid_synth_noteoff_LOCAL ( fluid_synth_t * synth , int chan , int key ) ;
2009-11-17 08:13:23 +00:00
static int fluid_synth_cc_LOCAL ( fluid_synth_t * synth , int channum , int num ) ;
2009-09-26 20:10:14 +00:00
static int fluid_synth_update_device_id ( fluid_synth_t * synth , char * name ,
int value ) ;
2010-07-31 20:50:47 +00:00
static int fluid_synth_update_overflow ( fluid_synth_t * synth , char * name ,
fluid_real_t value ) ;
2009-10-28 19:38:10 +00:00
static int fluid_synth_sysex_midi_tuning ( fluid_synth_t * synth , const char * data ,
2009-10-08 05:31:11 +00:00
int len , char * response ,
int * response_len , int avail_response ,
int * handled , int dryrun ) ;
2009-09-22 07:04:07 +00:00
static int fluid_synth_all_notes_off_LOCAL ( fluid_synth_t * synth , int chan ) ;
static int fluid_synth_all_sounds_off_LOCAL ( fluid_synth_t * synth , int chan ) ;
static int fluid_synth_system_reset_LOCAL ( fluid_synth_t * synth ) ;
static int fluid_synth_modulate_voices_LOCAL ( fluid_synth_t * synth , int chan ,
int is_cc , int ctrl ) ;
static int fluid_synth_modulate_voices_all_LOCAL ( fluid_synth_t * synth , int chan ) ;
2009-11-05 04:37:51 +00:00
static int fluid_synth_update_channel_pressure_LOCAL ( fluid_synth_t * synth , int channum ) ;
static int fluid_synth_update_pitch_bend_LOCAL ( fluid_synth_t * synth , int chan ) ;
static int fluid_synth_update_pitch_wheel_sens_LOCAL ( fluid_synth_t * synth , int chan ) ;
2009-09-22 07:04:07 +00:00
static int fluid_synth_set_preset ( fluid_synth_t * synth , int chan ,
fluid_preset_t * preset ) ;
2009-06-07 05:16:47 +00:00
static fluid_preset_t *
fluid_synth_get_preset ( fluid_synth_t * synth , unsigned int sfontnum ,
2009-09-22 07:04:07 +00:00
unsigned int banknum , unsigned int prognum ) ;
2009-06-07 05:16:47 +00:00
static fluid_preset_t *
2009-09-22 07:04:07 +00:00
fluid_synth_get_preset_by_sfont_name ( fluid_synth_t * synth , const char * sfontname ,
unsigned int banknum , unsigned int prognum ) ;
2009-06-07 05:16:47 +00:00
static void fluid_synth_update_presets ( fluid_synth_t * synth ) ;
2010-07-14 08:45:17 +00:00
static int fluid_synth_update_sample_rate ( fluid_synth_t * synth ,
char * name , double value ) ;
2009-06-07 05:16:47 +00:00
static int fluid_synth_update_gain ( fluid_synth_t * synth ,
char * name , double value ) ;
2009-11-05 04:37:51 +00:00
static void fluid_synth_update_gain_LOCAL ( fluid_synth_t * synth ) ;
2009-06-07 05:16:47 +00:00
static int fluid_synth_update_polyphony ( fluid_synth_t * synth ,
char * name , int value ) ;
2010-10-17 10:20:57 +00:00
static int fluid_synth_update_polyphony_LOCAL ( fluid_synth_t * synth , int new_polyphony ) ;
2009-06-07 05:16:47 +00:00
static void init_dither ( void ) ;
static inline int roundi ( float x ) ;
2010-07-03 12:25:43 +00:00
static int fluid_synth_render_blocks ( fluid_synth_t * synth , int blockcount ) ;
2017-08-25 19:49:51 +00:00
2009-09-22 07:04:07 +00:00
static fluid_voice_t * fluid_synth_free_voice_by_kill_LOCAL ( fluid_synth_t * synth ) ;
static void fluid_synth_kill_by_exclusive_class_LOCAL ( fluid_synth_t * synth ,
fluid_voice_t * new_voice ) ;
static fluid_sfont_info_t * new_fluid_sfont_info ( fluid_synth_t * synth ,
fluid_sfont_t * sfont ) ;
2009-06-07 05:16:47 +00:00
static int fluid_synth_sfunload_callback ( void * data , unsigned int msec ) ;
2009-09-22 07:04:07 +00:00
static void fluid_synth_release_voice_on_same_note_LOCAL ( fluid_synth_t * synth ,
int chan , int key ) ;
2009-06-07 05:16:47 +00:00
static fluid_tuning_t * fluid_synth_get_tuning ( fluid_synth_t * synth ,
int bank , int prog ) ;
2009-09-25 00:56:48 +00:00
static int fluid_synth_replace_tuning_LOCK ( fluid_synth_t * synth ,
fluid_tuning_t * tuning ,
int bank , int prog , int apply ) ;
static void fluid_synth_replace_tuning_LOCAL ( fluid_synth_t * synth ,
fluid_tuning_t * old_tuning ,
fluid_tuning_t * new_tuning ,
int apply , int unref_new ) ;
static void fluid_synth_update_voice_tuning_LOCAL ( fluid_synth_t * synth ,
fluid_channel_t * channel ) ;
static int fluid_synth_set_tuning_LOCAL ( fluid_synth_t * synth , int chan ,
fluid_tuning_t * tuning , int apply ) ;
2009-09-22 07:04:07 +00:00
static void fluid_synth_set_gen_LOCAL ( fluid_synth_t * synth , int chan ,
int param , float value , int absolute ) ;
static void fluid_synth_stop_LOCAL ( fluid_synth_t * synth , unsigned int id ) ;
2009-06-07 05:16:47 +00:00
2003-03-11 16:56:45 +00:00
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
/***************************************************************
*
* GLOBAL
*/
/* has the synth module been initialized? */
2007-03-04 16:45:05 +00:00
static int fluid_synth_initialized = 0 ;
2003-03-11 16:56:45 +00:00
static void fluid_synth_init ( void ) ;
2006-11-21 20:04:31 +00:00
static void init_dither ( void ) ;
2003-03-11 16:56:45 +00:00
/* default modulators
* SF2 .01 page 52 ff :
*
* There is a set of predefined default modulators . They have to be
2007-03-04 16:45:05 +00:00
* explicitly overridden by the sound font in order to turn them off .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
fluid_mod_t default_vel2att_mod ; /* SF2.01 section 8.4.1 */
2009-01-29 23:05:59 +00:00
fluid_mod_t default_vel2filter_mod ; /* SF2.01 section 8.4.2 */
2003-03-11 16:56:45 +00:00
fluid_mod_t default_at2viblfo_mod ; /* SF2.01 section 8.4.3 */
fluid_mod_t default_mod2viblfo_mod ; /* SF2.01 section 8.4.4 */
fluid_mod_t default_att_mod ; /* SF2.01 section 8.4.5 */
fluid_mod_t default_pan_mod ; /* SF2.01 section 8.4.6 */
fluid_mod_t default_expr_mod ; /* SF2.01 section 8.4.7 */
fluid_mod_t default_reverb_mod ; /* SF2.01 section 8.4.8 */
fluid_mod_t default_chorus_mod ; /* SF2.01 section 8.4.9 */
fluid_mod_t default_pitch_bend_mod ; /* SF2.01 section 8.4.10 */
/* reverb presets */
static fluid_revmodel_presets_t revmodel_preset [ ] = {
/* name */ /* roomsize */ /* damp */ /* width */ /* level */
2007-03-04 16:45:05 +00:00
{ " Test 1 " , 0.2f , 0.0f , 0.5f , 0.9f } ,
{ " Test 2 " , 0.4f , 0.2f , 0.5f , 0.8f } ,
{ " Test 3 " , 0.6f , 0.4f , 0.5f , 0.7f } ,
{ " Test 4 " , 0.8f , 0.7f , 0.5f , 0.6f } ,
{ " Test 5 " , 0.8f , 1.0f , 0.5f , 0.5f } ,
2003-03-11 16:56:45 +00:00
{ NULL , 0.0f , 0.0f , 0.0f , 0.0f }
} ;
/***************************************************************
*
* INITIALIZATION & UTILITIES
*/
2010-07-31 20:50:47 +00:00
static void fluid_synth_register_overflow ( fluid_settings_t * settings ,
fluid_num_update_t update_func ,
void * update_data )
{
2010-08-01 18:16:54 +00:00
fluid_settings_register_num ( settings , " synth.overflow.percussion " ,
2010-07-31 20:50:47 +00:00
4000 , - 10000 , 10000 , 0 , update_func , update_data ) ;
fluid_settings_register_num ( settings , " synth.overflow.sustained " ,
- 1000 , - 10000 , 10000 , 0 , update_func , update_data ) ;
fluid_settings_register_num ( settings , " synth.overflow.released " ,
- 2000 , - 10000 , 10000 , 0 , update_func , update_data ) ;
fluid_settings_register_num ( settings , " synth.overflow.age " ,
1000 , - 10000 , 10000 , 0 , update_func , update_data ) ;
fluid_settings_register_num ( settings , " synth.overflow.volume " ,
500 , - 10000 , 10000 , 0 , update_func , update_data ) ;
}
2003-04-03 21:32:56 +00:00
2003-03-11 16:56:45 +00:00
void fluid_synth_settings ( fluid_settings_t * settings )
{
2009-10-22 18:41:01 +00:00
fluid_settings_register_int ( settings , " synth.verbose " , 0 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
fluid_settings_register_int ( settings , " synth.dump " , 0 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
fluid_settings_register_int ( settings , " synth.reverb.active " , 1 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
fluid_settings_register_int ( settings , " synth.chorus.active " , 1 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
fluid_settings_register_int ( settings , " synth.ladspa.active " , 0 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
2012-12-08 06:25:21 +00:00
fluid_settings_register_int ( settings , " synth.lock-memory " , 1 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
2008-09-15 04:17:24 +00:00
fluid_settings_register_str ( settings , " midi.portname " , " " , 0 , NULL , NULL ) ;
2003-03-11 16:56:45 +00:00
2013-05-05 09:12:14 +00:00
fluid_settings_register_str ( settings , " synth.default-soundfont " ,
DEFAULT_SOUNDFONT , 0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_int ( settings , " synth.polyphony " ,
2010-07-31 20:50:47 +00:00
256 , 1 , 65535 , 0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_int ( settings , " synth.midi-channels " ,
2009-09-26 20:10:14 +00:00
16 , 16 , 256 , 0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_num ( settings , " synth.gain " ,
2009-09-26 20:10:14 +00:00
0.2f , 0.0f , 10.0f ,
0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_int ( settings , " synth.audio-channels " ,
2009-10-22 07:06:26 +00:00
1 , 1 , 128 , 0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_int ( settings , " synth.audio-groups " ,
2009-10-22 07:06:26 +00:00
1 , 1 , 128 , 0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_int ( settings , " synth.effects-channels " ,
2009-09-26 20:10:14 +00:00
2 , 2 , 2 , 0 , NULL , NULL ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_num ( settings , " synth.sample-rate " ,
2010-10-06 06:15:45 +00:00
44100.0f , 8000.0f , 96000.0f ,
2009-09-26 20:10:14 +00:00
0 , NULL , NULL ) ;
fluid_settings_register_int ( settings , " synth.device-id " ,
2009-10-05 07:03:42 +00:00
0 , 0 , 126 , 0 , NULL , NULL ) ;
Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.
Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
2009-09-29 21:40:28 +00:00
fluid_settings_register_int ( settings , " synth.cpu-cores " , 1 , 1 , 256 , 0 , NULL , NULL ) ;
2009-10-06 06:53:53 +00:00
2009-10-14 07:27:30 +00:00
fluid_settings_register_int ( settings , " synth.min-note-length " , 10 , 0 , 65535 , 0 , NULL , NULL ) ;
2010-07-01 11:36:59 +00:00
fluid_settings_register_int ( settings , " synth.threadsafe-api " , 1 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
fluid_settings_register_int ( settings , " synth.parallel-render " , 1 , 0 , 1 ,
FLUID_HINT_TOGGLED , NULL , NULL ) ;
2010-08-10 09:55:34 +00:00
2010-07-31 20:50:47 +00:00
fluid_synth_register_overflow ( settings , NULL , NULL ) ;
2010-08-10 09:55:34 +00:00
fluid_settings_register_str ( settings , " synth.midi-bank-select " , " gs " , 0 , NULL , NULL ) ;
fluid_settings_add_option ( settings , " synth.midi-bank-select " , " gm " ) ;
fluid_settings_add_option ( settings , " synth.midi-bank-select " , " gs " ) ;
fluid_settings_add_option ( settings , " synth.midi-bank-select " , " xg " ) ;
fluid_settings_add_option ( settings , " synth.midi-bank-select " , " mma " ) ;
2003-03-11 16:56:45 +00:00
}
2009-10-28 19:38:10 +00:00
/**
* Get FluidSynth runtime version .
* @ param major Location to store major number
* @ param minor Location to store minor number
* @ param micro Location to store micro number
2003-03-13 08:07:16 +00:00
*/
void fluid_version ( int * major , int * minor , int * micro )
{
* major = FLUIDSYNTH_VERSION_MAJOR ;
* minor = FLUIDSYNTH_VERSION_MINOR ;
* micro = FLUIDSYNTH_VERSION_MICRO ;
}
2009-10-28 19:38:10 +00:00
/**
* Get FluidSynth runtime version as a string .
* @ return FluidSynth version string , which is internal and should not be
* modified or freed .
2003-03-13 08:07:16 +00:00
*/
2009-10-28 19:38:10 +00:00
char *
fluid_version_str ( void )
2003-03-13 08:07:16 +00:00
{
return FLUIDSYNTH_VERSION ;
}
2010-07-01 11:14:55 +00:00
# define FLUID_API_ENTRY_CHAN(fail_value) \
fluid_return_val_if_fail ( synth ! = NULL , fail_value ) ; \
fluid_return_val_if_fail ( chan > = 0 , fail_value ) ; \
fluid_synth_api_enter ( synth ) ; \
if ( chan > = synth - > midi_channels ) { \
fluid_synth_api_exit ( synth ) ; \
return fail_value ; \
} \
2003-03-13 08:07:16 +00:00
2010-07-01 11:14:55 +00:00
# define FLUID_API_RETURN(return_value) \
do { fluid_synth_api_exit ( synth ) ; \
return return_value ; } while ( 0 )
2003-03-11 16:56:45 +00:00
/*
* void fluid_synth_init
*
* Does all the initialization for this module .
*/
2007-03-04 16:45:05 +00:00
static void
2009-06-07 05:16:47 +00:00
fluid_synth_init ( void )
2003-03-11 16:56:45 +00:00
{
fluid_synth_initialized + + ;
2007-11-11 20:52:56 +00:00
# ifdef TRAP_ON_FPE
/* Turn on floating point exception traps */
feenableexcept ( FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID ) ;
# endif
2003-03-11 16:56:45 +00:00
fluid_conversion_config ( ) ;
2010-06-26 15:02:58 +00:00
fluid_rvoice_dsp_config ( ) ;
2003-03-11 16:56:45 +00:00
fluid_sys_config ( ) ;
2007-11-11 20:52:56 +00:00
init_dither ( ) ;
2006-11-21 20:04:31 +00:00
2003-03-11 16:56:45 +00:00
/* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
fluid_mod_set_source1 ( & default_vel2att_mod , /* The modulator we are programming here */
FLUID_MOD_VELOCITY , /* Source. VELOCITY corresponds to 'index=2'. */
FLUID_MOD_GC /* Not a MIDI continuous controller */
2007-03-04 16:45:05 +00:00
| FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */
| FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */
) ;
fluid_mod_set_source2 ( & default_vel2att_mod , 0 , 0 ) ; /* No 2nd source */
fluid_mod_set_dest ( & default_vel2att_mod , GEN_ATTENUATION ) ; /* Target: Initial attenuation */
fluid_mod_set_amount ( & default_vel2att_mod , 960.0 ) ; /* Modulation amount: 960 */
2009-01-29 23:05:59 +00:00
/* SF2.01 page 53 section 8.4.2: MIDI Note-On Velocity to Filter Cutoff
* Have to make a design decision here . The specs don ' t make any sense this way or another .
* One sound font , ' Kingston Piano ' , which has been praised for its quality , tries to
* override this modulator with an amount of 0 and positive polarity ( instead of what
* the specs say , D = 1 ) for the secondary source .
* So if we change the polarity to ' positive ' , one of the best free sound fonts works . . .
*/
fluid_mod_set_source1 ( & default_vel2filter_mod , FLUID_MOD_VELOCITY , /* Index=2 */
2003-03-11 16:56:45 +00:00
FLUID_MOD_GC /* CC=0 */
| FLUID_MOD_LINEAR /* type=0 */
| FLUID_MOD_UNIPOLAR /* P=0 */
2009-01-29 23:05:59 +00:00
| FLUID_MOD_NEGATIVE /* D=1 */
2003-03-11 16:56:45 +00:00
) ;
2009-01-29 23:05:59 +00:00
fluid_mod_set_source2 ( & default_vel2filter_mod , FLUID_MOD_VELOCITY , /* Index=2 */
2003-03-11 16:56:45 +00:00
FLUID_MOD_GC /* CC=0 */
| FLUID_MOD_SWITCH /* type=3 */
2007-03-04 16:45:05 +00:00
| FLUID_MOD_UNIPOLAR /* P=0 */
2009-01-29 23:05:59 +00:00
// do not remove | FLUID_MOD_NEGATIVE /* D=1 */
| FLUID_MOD_POSITIVE /* D=0 */
2003-03-11 16:56:45 +00:00
) ;
2009-01-29 23:05:59 +00:00
fluid_mod_set_dest ( & default_vel2filter_mod , GEN_FILTERFC ) ; /* Target: Initial filter cutoff */
fluid_mod_set_amount ( & default_vel2filter_mod , - 2400 ) ;
2003-03-11 16:56:45 +00:00
/* SF2.01 page 53 section 8.4.3: MIDI Channel pressure to Vibrato LFO pitch depth */
fluid_mod_set_source1 ( & default_at2viblfo_mod , FLUID_MOD_CHANNELPRESSURE , /* Index=13 */
FLUID_MOD_GC /* CC=0 */
| FLUID_MOD_LINEAR /* type=0 */
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_POSITIVE /* D=0 */
) ;
fluid_mod_set_source2 ( & default_at2viblfo_mod , 0 , 0 ) ; /* no second source */
fluid_mod_set_dest ( & default_at2viblfo_mod , GEN_VIBLFOTOPITCH ) ; /* Target: Vib. LFO => pitch */
fluid_mod_set_amount ( & default_at2viblfo_mod , 50 ) ;
/* SF2.01 page 53 section 8.4.4: Mod wheel (Controller 1) to Vibrato LFO pitch depth */
fluid_mod_set_source1 ( & default_mod2viblfo_mod , 1 , /* Index=1 */
FLUID_MOD_CC /* CC=1 */
| FLUID_MOD_LINEAR /* type=0 */
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_POSITIVE /* D=0 */
) ;
fluid_mod_set_source2 ( & default_mod2viblfo_mod , 0 , 0 ) ; /* no second source */
fluid_mod_set_dest ( & default_mod2viblfo_mod , GEN_VIBLFOTOPITCH ) ; /* Target: Vib. LFO => pitch */
fluid_mod_set_amount ( & default_mod2viblfo_mod , 50 ) ;
/* SF2.01 page 55 section 8.4.5: MIDI continuous controller 7 to initial attenuation*/
2007-03-04 16:45:05 +00:00
fluid_mod_set_source1 ( & default_att_mod , 7 , /* index=7 */
FLUID_MOD_CC /* CC=1 */
| FLUID_MOD_CONCAVE /* type=1 */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_NEGATIVE /* D=1 */
) ;
fluid_mod_set_source2 ( & default_att_mod , 0 , 0 ) ; /* No second source */
fluid_mod_set_dest ( & default_att_mod , GEN_ATTENUATION ) ; /* Target: Initial attenuation */
fluid_mod_set_amount ( & default_att_mod , 960.0 ) ; /* Amount: 960 */
/* SF2.01 page 55 section 8.4.6 MIDI continuous controller 10 to Pan Position */
fluid_mod_set_source1 ( & default_pan_mod , 10 , /* index=10 */
FLUID_MOD_CC /* CC=1 */
2007-03-04 16:45:05 +00:00
| FLUID_MOD_LINEAR /* type=0 */
| FLUID_MOD_BIPOLAR /* P=1 */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_POSITIVE /* D=0 */
) ;
fluid_mod_set_source2 ( & default_pan_mod , 0 , 0 ) ; /* No second source */
fluid_mod_set_dest ( & default_pan_mod , GEN_PAN ) ; /* Target: pan */
/* Amount: 500. The SF specs $8.4.6, p. 55 syas: "Amount = 1000
tenths of a percent " . The center value (64) corresponds to 50%,
so it follows that amount = 50 % x 1000 / % = 500. */
2007-03-04 16:45:05 +00:00
fluid_mod_set_amount ( & default_pan_mod , 500.0 ) ;
2003-03-11 16:56:45 +00:00
/* SF2.01 page 55 section 8.4.7: MIDI continuous controller 11 to initial attenuation*/
2007-03-04 16:45:05 +00:00
fluid_mod_set_source1 ( & default_expr_mod , 11 , /* index=11 */
FLUID_MOD_CC /* CC=1 */
| FLUID_MOD_CONCAVE /* type=1 */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_NEGATIVE /* D=1 */
) ;
fluid_mod_set_source2 ( & default_expr_mod , 0 , 0 ) ; /* No second source */
fluid_mod_set_dest ( & default_expr_mod , GEN_ATTENUATION ) ; /* Target: Initial attenuation */
fluid_mod_set_amount ( & default_expr_mod , 960.0 ) ; /* Amount: 960 */
/* SF2.01 page 55 section 8.4.8: MIDI continuous controller 91 to Reverb send */
2007-03-04 16:45:05 +00:00
fluid_mod_set_source1 ( & default_reverb_mod , 91 , /* index=91 */
FLUID_MOD_CC /* CC=1 */
| FLUID_MOD_LINEAR /* type=0 */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_POSITIVE /* D=0 */
) ;
fluid_mod_set_source2 ( & default_reverb_mod , 0 , 0 ) ; /* No second source */
fluid_mod_set_dest ( & default_reverb_mod , GEN_REVERBSEND ) ; /* Target: Reverb send */
fluid_mod_set_amount ( & default_reverb_mod , 200 ) ; /* Amount: 200 ('tenths of a percent') */
2009-07-08 09:42:17 +00:00
/* SF2.01 page 55 section 8.4.9: MIDI continuous controller 93 to Chorus send */
2007-03-04 16:45:05 +00:00
fluid_mod_set_source1 ( & default_chorus_mod , 93 , /* index=93 */
FLUID_MOD_CC /* CC=1 */
| FLUID_MOD_LINEAR /* type=0 */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_POSITIVE /* D=0 */
) ;
fluid_mod_set_source2 ( & default_chorus_mod , 0 , 0 ) ; /* No second source */
fluid_mod_set_dest ( & default_chorus_mod , GEN_CHORUSSEND ) ; /* Target: Chorus */
fluid_mod_set_amount ( & default_chorus_mod , 200 ) ; /* Amount: 200 ('tenths of a percent') */
/* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
2007-03-04 16:45:05 +00:00
fluid_mod_set_source1 ( & default_pitch_bend_mod , FLUID_MOD_PITCHWHEEL , /* Index=14 */
2003-03-11 16:56:45 +00:00
FLUID_MOD_GC /* CC =0 */
| FLUID_MOD_LINEAR /* type=0 */
2007-03-04 16:45:05 +00:00
| FLUID_MOD_BIPOLAR /* P=1 */
2003-03-11 16:56:45 +00:00
| FLUID_MOD_POSITIVE /* D=0 */
) ;
fluid_mod_set_source2 ( & default_pitch_bend_mod , FLUID_MOD_PITCHWHEELSENS , /* Index = 16 */
FLUID_MOD_GC /* CC=0 */
| FLUID_MOD_LINEAR /* type=0 */
| FLUID_MOD_UNIPOLAR /* P=0 */
| FLUID_MOD_POSITIVE /* D=0 */
2007-03-04 16:45:05 +00:00
) ;
2003-03-11 16:56:45 +00:00
fluid_mod_set_dest ( & default_pitch_bend_mod , GEN_PITCH ) ; /* Destination: Initial pitch */
fluid_mod_set_amount ( & default_pitch_bend_mod , 12700.0 ) ; /* Amount: 12700 cents */
}
2010-07-31 20:50:47 +00:00
static FLUID_INLINE unsigned int fluid_synth_get_ticks ( fluid_synth_t * synth )
{
if ( synth - > eventhandler - > is_threadsafe )
return fluid_atomic_int_get ( & synth - > ticks_since_start ) ;
else
return synth - > ticks_since_start ;
}
static FLUID_INLINE void fluid_synth_add_ticks ( fluid_synth_t * synth , int val )
{
if ( synth - > eventhandler - > is_threadsafe )
fluid_atomic_int_add ( ( int * ) & synth - > ticks_since_start , val ) ;
else
synth - > ticks_since_start + = val ;
}
2003-03-11 16:56:45 +00:00
2009-04-25 15:17:15 +00:00
/***************************************************************
* FLUID SAMPLE TIMERS
* Timers that use written audio data as timing reference
*/
struct _fluid_sample_timer_t
{
fluid_sample_timer_t * next ; /* Single linked list of timers */
unsigned long starttick ;
fluid_timer_callback_t callback ;
void * data ;
int isfinished ;
} ;
/*
* fluid_sample_timer_process - called when synth - > ticks is updated
*/
void fluid_sample_timer_process ( fluid_synth_t * synth )
{
fluid_sample_timer_t * st ;
long msec ;
int cont ;
2010-07-31 20:50:47 +00:00
unsigned int ticks = fluid_synth_get_ticks ( synth ) ;
2009-04-25 15:17:15 +00:00
for ( st = synth - > sample_timers ; st ; st = st - > next ) {
if ( st - > isfinished ) {
continue ;
}
2010-07-31 20:50:47 +00:00
msec = ( long ) ( 1000.0 * ( ( double ) ( ticks - st - > starttick ) ) / synth - > sample_rate ) ;
2009-04-25 15:17:15 +00:00
cont = ( * st - > callback ) ( st - > data , msec ) ;
if ( cont = = 0 ) {
st - > isfinished = 1 ;
}
}
}
fluid_sample_timer_t * new_fluid_sample_timer ( fluid_synth_t * synth , fluid_timer_callback_t callback , void * data )
{
fluid_sample_timer_t * result = FLUID_NEW ( fluid_sample_timer_t ) ;
if ( result = = NULL ) {
FLUID_LOG ( FLUID_ERR , " Out of memory " ) ;
return NULL ;
}
2010-07-31 20:50:47 +00:00
result - > starttick = fluid_synth_get_ticks ( synth ) ;
2009-04-25 15:17:15 +00:00
result - > isfinished = 0 ;
result - > data = data ;
result - > callback = callback ;
result - > next = synth - > sample_timers ;
synth - > sample_timers = result ;
return result ;
}
int delete_fluid_sample_timer ( fluid_synth_t * synth , fluid_sample_timer_t * timer )
{
fluid_sample_timer_t * * ptr = & synth - > sample_timers ;
while ( * ptr ) {
if ( * ptr = = timer ) {
* ptr = timer - > next ;
FLUID_FREE ( timer ) ;
return FLUID_OK ;
}
ptr = & ( ( * ptr ) - > next ) ;
}
FLUID_LOG ( FLUID_ERR , " delete_fluid_sample_timer failed, no timer found " ) ;
return FLUID_FAILED ;
}
2003-03-11 16:56:45 +00:00
/***************************************************************
*
* FLUID SYNTH
*/
2010-07-14 08:45:38 +00:00
static FLUID_INLINE void
fluid_synth_update_mixer ( fluid_synth_t * synth , void * method , int intparam ,
fluid_real_t realparam )
{
2015-09-22 05:10:05 +00:00
fluid_return_if_fail ( synth ! = NULL & & synth - > eventhandler ! = NULL ) ;
2010-07-14 08:45:38 +00:00
fluid_return_if_fail ( synth - > eventhandler - > mixer ! = NULL ) ;
fluid_rvoice_eventhandler_push ( synth - > eventhandler , method ,
synth - > eventhandler - > mixer ,
intparam , realparam ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Create new FluidSynth instance .
* @ param settings Configuration parameters to use ( used directly ) .
* @ return New FluidSynth instance or NULL on error
*
2017-08-13 13:16:55 +00:00
* @ note The settings parameter is used directly and should not be modified
2009-09-22 07:04:07 +00:00
* or freed independently .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
fluid_synth_t *
2003-03-11 16:56:45 +00:00
new_fluid_synth ( fluid_settings_t * settings )
{
fluid_synth_t * synth ;
fluid_sfloader_t * loader ;
2009-11-05 04:37:51 +00:00
double gain ;
2010-06-30 16:39:20 +00:00
int i , nbuf ;
2003-03-11 16:56:45 +00:00
/* initialize all the conversion tables and other stuff */
if ( fluid_synth_initialized = = 0 ) {
fluid_synth_init ( ) ;
}
/* allocate a new synthesizer object */
synth = FLUID_NEW ( fluid_synth_t ) ;
if ( synth = = NULL ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR , " Out of memory " ) ;
2003-03-11 16:56:45 +00:00
return NULL ;
}
FLUID_MEMSET ( synth , 0 , sizeof ( fluid_synth_t ) ) ;
2007-03-04 16:45:05 +00:00
Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.
Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
2009-09-29 21:40:28 +00:00
fluid_rec_mutex_init ( synth - > mutex ) ;
2010-07-01 11:36:59 +00:00
fluid_settings_getint ( settings , " synth.threadsafe-api " , & synth - > use_mutex ) ;
2010-07-01 11:14:55 +00:00
synth - > public_api_count = 0 ;
2003-03-11 16:56:45 +00:00
synth - > settings = settings ;
2009-10-22 18:41:01 +00:00
fluid_settings_getint ( settings , " synth.reverb.active " , & synth - > with_reverb ) ;
fluid_settings_getint ( settings , " synth.chorus.active " , & synth - > with_chorus ) ;
fluid_settings_getint ( settings , " synth.verbose " , & synth - > verbose ) ;
fluid_settings_getint ( settings , " synth.dump " , & synth - > dump ) ;
2003-03-11 16:56:45 +00:00
fluid_settings_getint ( settings , " synth.polyphony " , & synth - > polyphony ) ;
fluid_settings_getnum ( settings , " synth.sample-rate " , & synth - > sample_rate ) ;
fluid_settings_getint ( settings , " synth.midi-channels " , & synth - > midi_channels ) ;
fluid_settings_getint ( settings , " synth.audio-channels " , & synth - > audio_channels ) ;
fluid_settings_getint ( settings , " synth.audio-groups " , & synth - > audio_groups ) ;
fluid_settings_getint ( settings , " synth.effects-channels " , & synth - > effects_channels ) ;
2009-11-05 04:37:51 +00:00
fluid_settings_getnum ( settings , " synth.gain " , & gain ) ;
synth - > gain = gain ;
2009-09-26 20:10:14 +00:00
fluid_settings_getint ( settings , " synth.device-id " , & synth - > device_id ) ;
Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.
Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
2009-09-29 21:40:28 +00:00
fluid_settings_getint ( settings , " synth.cpu-cores " , & synth - > cores ) ;
2003-03-11 16:56:45 +00:00
2003-04-03 21:32:56 +00:00
/* register the callbacks */
2010-07-14 08:45:17 +00:00
fluid_settings_register_num ( settings , " synth.sample-rate " ,
2010-10-06 06:15:45 +00:00
44100.0f , 8000.0f , 96000.0f , 0 ,
2010-07-14 08:45:17 +00:00
( fluid_num_update_t ) fluid_synth_update_sample_rate , synth ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_num ( settings , " synth.gain " ,
0.2f , 0.0f , 10.0f , 0 ,
2003-04-03 21:32:56 +00:00
( fluid_num_update_t ) fluid_synth_update_gain , synth ) ;
2007-03-04 16:45:05 +00:00
fluid_settings_register_int ( settings , " synth.polyphony " ,
2010-07-31 20:50:47 +00:00
synth - > polyphony , 1 , 65535 , 0 ,
2005-06-08 03:51:13 +00:00
( fluid_int_update_t ) fluid_synth_update_polyphony ,
synth ) ;
2009-09-26 20:10:14 +00:00
fluid_settings_register_int ( settings , " synth.device-id " ,
synth - > device_id , 126 , 0 , 0 ,
2009-10-08 05:31:11 +00:00
( fluid_int_update_t ) fluid_synth_update_device_id , synth ) ;
2003-04-03 21:32:56 +00:00
2010-07-31 20:50:47 +00:00
fluid_synth_register_overflow ( settings ,
( fluid_num_update_t ) fluid_synth_update_overflow , synth ) ;
2003-03-11 16:56:45 +00:00
/* do some basic sanity checking on the settings */
2004-05-05 20:27:22 +00:00
if ( synth - > midi_channels % 16 ! = 0 ) {
int n = synth - > midi_channels / 16 ;
synth - > midi_channels = ( n + 1 ) * 16 ;
fluid_settings_setint ( settings , " synth.midi-channels " , synth - > midi_channels ) ;
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_WARN , " Requested number of MIDI channels is not a multiple of 16. "
" I'll increase the number of channels to the next multiple. " ) ;
2003-03-11 16:56:45 +00:00
}
if ( synth - > audio_channels < 1 ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_WARN , " Requested number of audio channels is smaller than 1. "
" Changing this setting to 1. " ) ;
2003-03-11 16:56:45 +00:00
synth - > audio_channels = 1 ;
} else if ( synth - > audio_channels > 128 ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_WARN , " Requested number of audio channels is too big (%d). "
" Limiting this setting to 128. " , synth - > audio_channels ) ;
2003-03-11 16:56:45 +00:00
synth - > audio_channels = 128 ;
}
if ( synth - > audio_groups < 1 ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_WARN , " Requested number of audio groups is smaller than 1. "
" Changing this setting to 1. " ) ;
2003-03-11 16:56:45 +00:00
synth - > audio_groups = 1 ;
} else if ( synth - > audio_groups > 128 ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_WARN , " Requested number of audio groups is too big (%d). "
" Limiting this setting to 128. " , synth - > audio_groups ) ;
2003-03-11 16:56:45 +00:00
synth - > audio_groups = 128 ;
}
2009-07-27 10:51:05 +00:00
if ( synth - > effects_channels < 2 ) {
2003-03-11 16:56:45 +00:00
FLUID_LOG ( FLUID_WARN , " Invalid number of effects channels (%d). "
" Setting effects channels to 2. " , synth - > effects_channels ) ;
synth - > effects_channels = 2 ;
}
/* The number of buffers is determined by the higher number of nr
* groups / nr audio channels . If LADSPA is unused , they should be
* the same . */
2010-06-30 16:39:20 +00:00
nbuf = synth - > audio_channels ;
if ( synth - > audio_groups > nbuf ) {
nbuf = synth - > audio_groups ;
2003-03-11 16:56:45 +00:00
}
/* as soon as the synth is created it starts playing. */
synth - > state = FLUID_SYNTH_PLAYING ;
2009-09-22 07:04:07 +00:00
synth - > sfont_info = NULL ;
synth - > sfont_hash = new_fluid_hashtable ( NULL , NULL ) ;
2003-03-11 16:56:45 +00:00
synth - > noteid = 0 ;
2010-07-31 20:50:47 +00:00
synth - > ticks_since_start = 0 ;
2003-03-11 16:56:45 +00:00
synth - > tuning = NULL ;
2009-09-25 00:56:48 +00:00
fluid_private_init ( synth - > tuning_iter ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:36:59 +00:00
/* Allocate event queue for rvoice mixer */
fluid_settings_getint ( settings , " synth.parallel-render " , & i ) ;
2010-07-31 20:50:47 +00:00
/* In an overflow situation, a new voice takes about 50 spaces in the queue! */
2010-10-17 10:43:48 +00:00
synth - > eventhandler = new_fluid_rvoice_eventhandler ( i , synth - > polyphony * 64 ,
synth - > polyphony , nbuf , synth - > effects_channels , synth - > sample_rate ) ;
2010-07-01 11:14:55 +00:00
if ( synth - > eventhandler = = NULL )
goto error_recovery ;
2010-09-04 07:19:57 +00:00
2017-09-07 08:45:46 +00:00
/* Setup the list of default modulators.
* Needs to happen after eventhandler has been set up , as fluid_synth_enter_api is called in the process */
synth - > default_mod = NULL ;
fluid_synth_add_default_mod ( synth , & default_vel2att_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_vel2filter_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_at2viblfo_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_mod2viblfo_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_att_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_pan_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_expr_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_reverb_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_chorus_mod , FLUID_SYNTH_ADD ) ;
fluid_synth_add_default_mod ( synth , & default_pitch_bend_mod , FLUID_SYNTH_ADD ) ;
2010-09-04 07:19:57 +00:00
# ifdef LADSPA
/* Create and initialize the Fx unit.*/
synth - > LADSPA_FxUnit = new_fluid_LADSPA_FxUnit ( synth ) ;
fluid_rvoice_mixer_set_ladspa ( synth - > eventhandler - > mixer , synth - > LADSPA_FxUnit ) ;
# endif
2003-03-11 16:56:45 +00:00
/* allocate and add the default sfont loader */
2012-12-08 06:25:21 +00:00
loader = new_fluid_defsfloader ( settings ) ;
2003-03-11 16:56:45 +00:00
if ( loader = = NULL ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_WARN , " Failed to create the default SoundFont loader " ) ;
2003-03-11 16:56:45 +00:00
} else {
fluid_synth_add_sfloader ( synth , loader ) ;
}
/* allocate all channel objects */
synth - > channel = FLUID_ARRAY ( fluid_channel_t * , synth - > midi_channels ) ;
if ( synth - > channel = = NULL ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR , " Out of memory " ) ;
2003-03-11 16:56:45 +00:00
goto error_recovery ;
}
for ( i = 0 ; i < synth - > midi_channels ; i + + ) {
synth - > channel [ i ] = new_fluid_channel ( synth , i ) ;
if ( synth - > channel [ i ] = = NULL ) {
goto error_recovery ;
}
}
/* allocate all synthesis processes */
synth - > nvoice = synth - > polyphony ;
synth - > voice = FLUID_ARRAY ( fluid_voice_t * , synth - > nvoice ) ;
if ( synth - > voice = = NULL ) {
goto error_recovery ;
}
for ( i = 0 ; i < synth - > nvoice ; i + + ) {
synth - > voice [ i ] = new_fluid_voice ( synth - > sample_rate ) ;
if ( synth - > voice [ i ] = = NULL ) {
goto error_recovery ;
}
}
2010-07-14 08:45:17 +00:00
fluid_synth_set_sample_rate ( synth , synth - > sample_rate ) ;
2010-07-31 20:50:47 +00:00
fluid_synth_update_overflow ( synth , " " , 0.0f ) ;
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_set_polyphony ,
synth - > polyphony , 0.0f ) ;
2010-06-30 16:39:20 +00:00
fluid_synth_set_reverb_on ( synth , synth - > with_reverb ) ;
fluid_synth_set_chorus_on ( synth , synth - > with_chorus ) ;
2003-03-11 16:56:45 +00:00
synth - > cur = FLUID_BUFSIZE ;
2010-07-03 12:25:43 +00:00
synth - > curmax = 0 ;
2006-11-21 20:04:31 +00:00
synth - > dither_index = 0 ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
synth - > reverb_roomsize = FLUID_REVERB_DEFAULT_ROOMSIZE ;
synth - > reverb_damping = FLUID_REVERB_DEFAULT_DAMP ;
synth - > reverb_width = FLUID_REVERB_DEFAULT_WIDTH ;
synth - > reverb_level = FLUID_REVERB_DEFAULT_LEVEL ;
2010-06-30 16:39:20 +00:00
fluid_rvoice_eventhandler_push5 ( synth - > eventhandler ,
fluid_rvoice_mixer_set_reverb_params ,
synth - > eventhandler - > mixer ,
FLUID_REVMODEL_SET_ALL , synth - > reverb_roomsize ,
synth - > reverb_damping , synth - > reverb_width ,
synth - > reverb_level , 0.0f ) ;
2003-03-11 16:56:45 +00:00
Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.
Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
2009-09-29 21:40:28 +00:00
/* Initialize multi-core variables if multiple cores enabled */
if ( synth - > cores > 1 )
{
2009-10-30 21:49:54 +00:00
int prio_level = 0 ;
2010-07-03 12:25:16 +00:00
fluid_settings_getint ( synth - > settings , " audio.realtime-prio " , & prio_level ) ;
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_set_threads ,
synth - > cores - 1 , prio_level ) ;
Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.
Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
2009-09-29 21:40:28 +00:00
}
2010-08-10 09:55:34 +00:00
synth - > bank_select = FLUID_BANK_STYLE_GS ;
if ( fluid_settings_str_equal ( settings , " synth.midi-bank-select " , " gm " ) = = 1 )
synth - > bank_select = FLUID_BANK_STYLE_GM ;
else if ( fluid_settings_str_equal ( settings , " synth.midi-bank-select " , " gs " ) = = 1 )
synth - > bank_select = FLUID_BANK_STYLE_GS ;
else if ( fluid_settings_str_equal ( settings , " synth.midi-bank-select " , " xg " ) = = 1 )
synth - > bank_select = FLUID_BANK_STYLE_XG ;
else if ( fluid_settings_str_equal ( settings , " synth.midi-bank-select " , " mma " ) = = 1 )
synth - > bank_select = FLUID_BANK_STYLE_MMA ;
2011-02-07 07:30:50 +00:00
fluid_synth_process_event_queue ( synth ) ;
2003-03-11 16:56:45 +00:00
/* FIXME */
synth - > start = fluid_curtime ( ) ;
return synth ;
error_recovery :
delete_fluid_synth ( synth ) ;
return NULL ;
}
2009-09-22 07:04:07 +00:00
/**
* Delete a FluidSynth instance .
* @ param synth FluidSynth instance to delete
* @ return FLUID_OK
*
2017-08-13 13:16:55 +00:00
* @ note Other users of a synthesizer instance , such as audio and MIDI drivers ,
2009-09-22 07:04:07 +00:00
* should be deleted prior to freeing the FluidSynth instance .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
delete_fluid_synth ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
int i , k ;
fluid_list_t * list ;
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
2003-03-11 16:56:45 +00:00
fluid_sfloader_t * loader ;
2017-09-07 08:45:46 +00:00
fluid_mod_t * default_mod ;
fluid_mod_t * mod ;
2003-03-11 16:56:45 +00:00
if ( synth = = NULL ) {
return FLUID_OK ;
}
fluid_profiling_print ( ) ;
2006-12-10 16:02:04 +00:00
/* turn off all voices, needed to unload SoundFont data */
if ( synth - > voice ! = NULL ) {
for ( i = 0 ; i < synth - > nvoice ; i + + ) {
2011-05-22 12:11:19 +00:00
fluid_voice_t * voice = synth - > voice [ i ] ;
if ( ! voice )
continue ;
fluid_voice_unlock_rvoice ( voice ) ;
fluid_voice_overflow_rvoice_finished ( voice ) ;
2017-07-01 15:57:43 +00:00
if ( fluid_voice_is_playing ( voice ) ) {
fluid_voice_off ( voice ) ;
/* If we only use fluid_voice_off(voice) it will trigger a delayed
* fluid_voice_stop ( voice ) via fluid_synth_check_finished_voices ( ) .
* But here , we are deleting the fluid_synth_t instance so
* fluid_voice_stop ( ) will be never triggered resulting in
* SoundFont data never unloaded ( i . e a serious memory leak ) .
* So , fluid_voice_stop ( ) must be explicitly called to insure
* unloading SoundFont data
*/
fluid_voice_stop ( voice ) ;
}
2006-12-10 16:02:04 +00:00
}
}
2013-05-12 10:21:43 +00:00
/* also unset all presets for clean SoundFont unload */
if ( synth - > channel ! = NULL )
for ( i = 0 ; i < synth - > midi_channels ; i + + )
if ( synth - > channel [ i ] ! = NULL )
fluid_channel_set_preset ( synth - > channel [ i ] , NULL ) ;
2010-06-28 20:03:12 +00:00
if ( synth - > eventhandler )
delete_fluid_rvoice_eventhandler ( synth - > eventhandler ) ;
2003-03-11 16:56:45 +00:00
/* delete all the SoundFonts */
2009-09-22 07:04:07 +00:00
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_FREE ( sfont_info ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
delete_fluid_list ( synth - > sfont_info ) ;
2007-03-04 16:45:05 +00:00
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
/* Delete the SoundFont info hash */
if ( synth - > sfont_hash ) delete_fluid_hashtable ( synth - > sfont_hash ) ;
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
/* delete all the SoundFont loaders */
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
for ( list = synth - > loaders ; list ; list = fluid_list_next ( list ) ) {
loader = ( fluid_sfloader_t * ) fluid_list_get ( list ) ;
fluid_sfloader_delete ( loader ) ;
}
delete_fluid_list ( synth - > loaders ) ;
if ( synth - > channel ! = NULL ) {
for ( i = 0 ; i < synth - > midi_channels ; i + + ) {
if ( synth - > channel [ i ] ! = NULL ) {
delete_fluid_channel ( synth - > channel [ i ] ) ;
}
}
FLUID_FREE ( synth - > channel ) ;
}
2004-08-18 15:11:47 +00:00
2003-03-11 16:56:45 +00:00
if ( synth - > voice ! = NULL ) {
for ( i = 0 ; i < synth - > nvoice ; i + + ) {
if ( synth - > voice [ i ] ! = NULL ) {
delete_fluid_voice ( synth - > voice [ i ] ) ;
}
}
FLUID_FREE ( synth - > voice ) ;
}
/* free the tunings, if any */
if ( synth - > tuning ! = NULL ) {
for ( i = 0 ; i < 128 ; i + + ) {
if ( synth - > tuning [ i ] ! = NULL ) {
for ( k = 0 ; k < 128 ; k + + ) {
if ( synth - > tuning [ i ] [ k ] ! = NULL ) {
2009-09-22 07:04:07 +00:00
delete_fluid_tuning ( synth - > tuning [ i ] [ k ] ) ;
2003-03-11 16:56:45 +00:00
}
}
FLUID_FREE ( synth - > tuning [ i ] ) ;
}
}
FLUID_FREE ( synth - > tuning ) ;
}
2009-09-25 00:56:48 +00:00
fluid_private_free ( synth - > tuning_iter ) ;
2003-03-11 16:56:45 +00:00
# ifdef LADSPA
/* Release the LADSPA Fx unit */
fluid_LADSPA_shutdown ( synth - > LADSPA_FxUnit ) ;
FLUID_FREE ( synth - > LADSPA_FxUnit ) ;
# endif
2007-03-04 16:45:05 +00:00
2017-09-07 08:45:46 +00:00
/* delete all default modulators */
default_mod = synth - > default_mod ;
while ( default_mod ! = NULL ) {
mod = default_mod ;
default_mod = mod - > next ;
fluid_mod_delete ( mod ) ;
}
Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.
Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
2009-09-29 21:40:28 +00:00
fluid_rec_mutex_destroy ( synth - > mutex ) ;
2004-05-05 20:27:22 +00:00
2003-03-11 16:56:45 +00:00
FLUID_FREE ( synth ) ;
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Get a textual representation of the last error
* @ param synth FluidSynth instance
* @ return Pointer to string of last error message . Valid until the same
* calling thread calls another FluidSynth function which fails . String is
* internal and should not be modified or freed .
*/
/* FIXME - The error messages are not thread-safe, yet. They are still stored
* in a global message buffer ( see fluid_sys . c ) . */
2007-03-04 16:45:05 +00:00
char *
2003-03-11 16:56:45 +00:00
fluid_synth_error ( fluid_synth_t * synth )
{
return fluid_error ( ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Send a note - on event to a FluidSynth object .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param key MIDI note number ( 0 - 127 )
* @ param vel MIDI velocity ( 0 - 127 , 0 = noteoff )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
fluid_synth_noteon ( fluid_synth_t * synth , int chan , int key , int vel )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( key > = 0 & & key < = 127 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( vel > = 0 & & vel < = 127 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2010-07-14 08:44:51 +00:00
2010-10-17 10:20:57 +00:00
result = fluid_synth_noteon_LOCAL ( synth , chan , key , vel ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
/* Local synthesis thread variant of fluid_synth_noteon */
static int
fluid_synth_noteon_LOCAL ( fluid_synth_t * synth , int chan , int key , int vel )
{
fluid_channel_t * channel ;
/* notes with velocity zero go to noteoff */
if ( vel = = 0 ) return fluid_synth_noteoff_LOCAL ( synth , chan , key ) ;
2003-03-11 16:56:45 +00:00
channel = synth - > channel [ chan ] ;
2010-06-30 16:39:20 +00:00
2003-03-11 16:56:45 +00:00
/* make sure this channel has a preset */
if ( channel - > preset = = NULL ) {
if ( synth - > verbose ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_INFO , " noteon \t %d \t %d \t %d \t %05d \t %.3f \t %.3f \t %.3f \t %d \t %s " ,
chan , key , vel , 0 ,
2010-07-31 20:50:47 +00:00
fluid_synth_get_ticks ( synth ) / 44100.0f ,
2003-03-11 16:56:45 +00:00
( fluid_curtime ( ) - synth - > start ) / 1000.0f ,
0.0f , 0 , " channel has no preset " ) ;
}
2004-05-05 20:27:22 +00:00
return FLUID_FAILED ;
2007-03-04 16:45:05 +00:00
}
2003-03-11 16:56:45 +00:00
2004-08-06 09:56:24 +00:00
/* If there is another voice process on the same channel and key,
advance it to the release phase . */
2009-09-22 07:04:07 +00:00
fluid_synth_release_voice_on_same_note_LOCAL ( synth , chan , key ) ;
2004-08-06 09:56:24 +00:00
2009-09-22 07:04:07 +00:00
return fluid_preset_noteon ( channel - > preset , synth , chan , key , vel ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Send a note - off event to a FluidSynth object .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param key MIDI note number ( 0 - 127 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise ( may just mean that no
* voices matched the note off event )
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_noteoff ( fluid_synth_t * synth , int chan , int key )
2009-09-22 07:04:07 +00:00
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( key > = 0 & & key < = 127 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2010-07-14 08:44:51 +00:00
2010-10-17 10:20:57 +00:00
result = fluid_synth_noteoff_LOCAL ( synth , chan , key ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
/* Local synthesis thread variant of fluid_synth_noteoff */
static int
fluid_synth_noteoff_LOCAL ( fluid_synth_t * synth , int chan , int key )
2003-03-11 16:56:45 +00:00
{
fluid_voice_t * voice ;
int status = FLUID_FAILED ;
2009-10-08 05:31:11 +00:00
int i ;
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2017-09-02 22:22:07 +00:00
if ( fluid_voice_is_on ( voice ) & & ( fluid_voice_get_channel ( voice ) = = chan ) & & ( fluid_voice_get_key ( voice ) = = key ) ) {
2003-03-11 16:56:45 +00:00
if ( synth - > verbose ) {
int used_voices = 0 ;
int k ;
2005-06-08 03:51:13 +00:00
for ( k = 0 ; k < synth - > polyphony ; k + + ) {
2003-03-11 16:56:45 +00:00
if ( ! _AVAILABLE ( synth - > voice [ k ] ) ) {
used_voices + + ;
}
}
2010-06-26 15:02:58 +00:00
FLUID_LOG ( FLUID_INFO , " noteoff \t %d \t %d \t %d \t %05d \t %.3f \t %d " ,
2017-09-02 22:22:07 +00:00
fluid_voice_get_channel ( voice ) , fluid_voice_get_key ( voice ) , 0 , fluid_voice_get_id ( voice ) ,
2003-03-11 16:56:45 +00:00
( fluid_curtime ( ) - synth - > start ) / 1000.0f ,
used_voices ) ;
} /* if verbose */
2009-09-22 07:04:07 +00:00
2009-10-14 07:27:30 +00:00
fluid_voice_noteoff ( voice ) ;
2003-03-11 16:56:45 +00:00
status = FLUID_OK ;
} /* if voice on */
} /* for all voices */
return status ;
}
2015-04-07 11:48:04 +00:00
/* Damp voices on a channel (turn notes off), if they're sustained by
sustain pedal */
2009-09-22 07:04:07 +00:00
static int
2015-04-07 11:48:04 +00:00
fluid_synth_damp_voices_by_sustain_LOCAL ( fluid_synth_t * synth , int chan )
2003-03-11 16:56:45 +00:00
{
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2004-03-29 10:05:18 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2009-09-22 07:04:07 +00:00
2017-09-02 22:22:07 +00:00
if ( ( fluid_voice_get_channel ( voice ) = = chan ) & & fluid_voice_is_sustained ( voice ) )
2015-04-07 11:48:04 +00:00
fluid_voice_release ( voice ) ;
}
return FLUID_OK ;
}
/* Damp voices on a channel (turn notes off), if they're sustained by
sostenuto pedal */
static int
fluid_synth_damp_voices_by_sostenuto_LOCAL ( fluid_synth_t * synth , int chan )
{
fluid_voice_t * voice ;
int i ;
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
voice = synth - > voice [ i ] ;
2017-09-02 22:22:07 +00:00
if ( ( fluid_voice_get_channel ( voice ) = = chan ) & & fluid_voice_is_sostenuto ( voice ) )
2015-04-07 11:48:04 +00:00
fluid_voice_release ( voice ) ;
2003-03-11 16:56:45 +00:00
}
return FLUID_OK ;
}
2017-09-07 08:45:46 +00:00
/**
* Adds a default modulator to the synth .
* @ param synth FluidSynth instance
* @ param mod Modulator info ( values copied , passed in object can be freed again immediately )
* @ param mode Determines how to handle an existing identical modulator
* # FLUID_SYNTH_ADD to add ( offset ) the modulator amounts ,
* # FLUID_SYNTH_OVERWRITE to replace the modulator ,
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
fluid_synth_add_default_mod ( fluid_synth_t * synth , fluid_mod_t * mod , int mode )
{
fluid_mod_t * default_mod ;
fluid_mod_t * last_mod = NULL ;
fluid_mod_t * new_mod ;
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
default_mod = synth - > default_mod ;
while ( default_mod ! = NULL ) {
if ( fluid_mod_test_identity ( default_mod , mod ) ) {
if ( mode = = FLUID_SYNTH_ADD )
default_mod - > amount + = mod - > amount ;
else // FLUID_SYNTH_OVERWRITE
default_mod - > amount = mod - > amount ;
FLUID_API_RETURN ( FLUID_OK ) ;
}
last_mod = default_mod ;
default_mod = default_mod - > next ;
}
/* Add a new modulator (no existing modulator to add / overwrite). */
new_mod = fluid_mod_new ( ) ;
if ( new_mod = = NULL )
FLUID_API_RETURN ( FLUID_FAILED ) ;
fluid_mod_clone ( new_mod , mod ) ;
new_mod - > next = NULL ;
if ( last_mod = = NULL )
synth - > default_mod = new_mod ;
else
last_mod - > next = new_mod ;
FLUID_API_RETURN ( FLUID_OK ) ;
}
2015-04-07 11:48:04 +00:00
2009-09-22 07:04:07 +00:00
/**
* Send a MIDI controller event on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param num MIDI controller number ( 0 - 127 )
* @ param val MIDI controller value ( 0 - 127 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_cc ( fluid_synth_t * synth , int chan , int num , int val )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( num > = 0 & & num < = 127 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( val > = 0 & & val < = 127 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2004-03-29 10:05:18 +00:00
2009-11-15 02:34:24 +00:00
if ( synth - > verbose )
FLUID_LOG ( FLUID_INFO , " cc \t %d \t %d \t %d " , chan , num , val ) ;
fluid_channel_set_cc ( synth - > channel [ chan ] , num , val ) ;
2010-10-17 10:20:57 +00:00
result = fluid_synth_cc_LOCAL ( synth , chan , num ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
2009-11-15 02:34:24 +00:00
/* Local synthesis thread variant of MIDI CC set function. */
2009-09-22 07:04:07 +00:00
static int
2009-11-17 08:13:23 +00:00
fluid_synth_cc_LOCAL ( fluid_synth_t * synth , int channum , int num )
2009-09-22 07:04:07 +00:00
{
fluid_channel_t * chan = synth - > channel [ channum ] ;
2009-11-17 08:13:23 +00:00
int nrpn_select ;
2009-11-15 02:34:24 +00:00
int value ;
2009-09-26 20:10:14 +00:00
2009-11-15 02:34:24 +00:00
value = fluid_channel_get_cc ( chan , num ) ;
2009-09-22 07:04:07 +00:00
switch ( num ) {
case SUSTAIN_SWITCH :
2015-04-07 11:48:04 +00:00
/* Release voices if Sustain switch is released */
if ( value < 64 ) /* Sustain is released */
fluid_synth_damp_voices_by_sustain_LOCAL ( synth , channum ) ;
2009-09-22 07:04:07 +00:00
break ;
2015-04-07 11:48:04 +00:00
case SOSTENUTO_SWITCH :
/* Release voices if Sostetuno switch is released */
if ( value < 64 ) /* Sostenuto is released */
fluid_synth_damp_voices_by_sostenuto_LOCAL ( synth , channum ) ;
else /* Sostenuto is depressed */
/* Update sostenuto order id when pedaling on Sostenuto */
chan - > sostenuto_orderid = synth - > noteid ; /* future voice id value */
break ;
2009-09-22 07:04:07 +00:00
case BANK_SELECT_MSB :
fluid_channel_set_bank_msb ( chan , value & 0x7F ) ;
break ;
case BANK_SELECT_LSB :
fluid_channel_set_bank_lsb ( chan , value & 0x7F ) ;
break ;
case ALL_NOTES_OFF :
fluid_synth_all_notes_off_LOCAL ( synth , channum ) ;
break ;
case ALL_SOUND_OFF :
fluid_synth_all_sounds_off_LOCAL ( synth , channum ) ;
break ;
case ALL_CTRL_OFF :
fluid_channel_init_ctrl ( chan , 1 ) ;
fluid_synth_modulate_voices_all_LOCAL ( synth , channum ) ;
break ;
case DATA_ENTRY_MSB :
{
int data = ( value < < 7 ) + fluid_channel_get_cc ( chan , DATA_ENTRY_LSB ) ;
2010-10-17 10:20:57 +00:00
if ( chan - > nrpn_active ) /* NRPN is active? */
2009-09-22 07:04:07 +00:00
{ /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
if ( ( fluid_channel_get_cc ( chan , NRPN_MSB ) = = 120 )
& & ( fluid_channel_get_cc ( chan , NRPN_LSB ) < 100 ) )
{
2010-10-17 10:20:57 +00:00
nrpn_select = chan - > nrpn_select ;
2009-09-22 07:04:07 +00:00
if ( nrpn_select < GEN_LAST )
{
float val = fluid_gen_scale_nrpn ( nrpn_select , data ) ;
fluid_synth_set_gen_LOCAL ( synth , channum , nrpn_select , val , FALSE ) ;
}
2010-10-17 10:20:57 +00:00
chan - > nrpn_select = 0 ; /* Reset to 0 */
2009-09-22 07:04:07 +00:00
}
}
2009-11-17 08:13:23 +00:00
else if ( fluid_channel_get_cc ( chan , RPN_MSB ) = = 0 ) /* RPN is active: MSB = 0? */
2009-09-22 07:04:07 +00:00
{
2009-11-17 08:13:23 +00:00
switch ( fluid_channel_get_cc ( chan , RPN_LSB ) )
2009-09-22 07:04:07 +00:00
{
2009-11-05 04:37:51 +00:00
case RPN_PITCH_BEND_RANGE : /* Set bend range in semitones */
fluid_channel_set_pitch_wheel_sensitivity ( synth - > channel [ channum ] , value ) ;
fluid_synth_update_pitch_wheel_sens_LOCAL ( synth , channum ) ; /* Update bend range */
2009-09-22 07:04:07 +00:00
/* FIXME - Handle LSB? (Fine bend range in cents) */
break ;
2017-08-05 12:58:10 +00:00
case RPN_CHANNEL_FINE_TUNE : /* Fine tune is 14 bit over +/-1 semitone (+/- 100 cents, 8192 = center) */
2009-09-22 07:04:07 +00:00
fluid_synth_set_gen_LOCAL ( synth , channum , GEN_FINETUNE ,
2017-08-05 12:58:10 +00:00
( data - 8192 ) / 8192.0 * 100.0 , FALSE ) ;
2009-09-22 07:04:07 +00:00
break ;
case RPN_CHANNEL_COARSE_TUNE : /* Coarse tune is 7 bit and in semitones (64 is center) */
fluid_synth_set_gen_LOCAL ( synth , channum , GEN_COARSETUNE ,
value - 64 , FALSE ) ;
break ;
case RPN_TUNING_PROGRAM_CHANGE :
2009-09-26 20:10:14 +00:00
fluid_channel_set_tuning_prog ( chan , value ) ;
fluid_synth_activate_tuning ( synth , channum ,
fluid_channel_get_tuning_bank ( chan ) ,
value , TRUE ) ;
2009-09-22 07:04:07 +00:00
break ;
case RPN_TUNING_BANK_SELECT :
2009-09-26 20:10:14 +00:00
fluid_channel_set_tuning_bank ( chan , value ) ;
2009-09-22 07:04:07 +00:00
break ;
case RPN_MODULATION_DEPTH_RANGE :
break ;
}
}
break ;
}
case NRPN_MSB :
fluid_channel_set_cc ( chan , NRPN_LSB , 0 ) ;
2010-10-17 10:20:57 +00:00
chan - > nrpn_select = 0 ;
chan - > nrpn_active = 1 ;
2009-09-22 07:04:07 +00:00
break ;
case NRPN_LSB :
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
if ( fluid_channel_get_cc ( chan , NRPN_MSB ) = = 120 ) {
if ( value = = 100 ) {
2010-10-17 10:20:57 +00:00
chan - > nrpn_select + = 100 ;
2009-09-22 07:04:07 +00:00
} else if ( value = = 101 ) {
2010-10-17 10:20:57 +00:00
chan - > nrpn_select + = 1000 ;
2009-09-22 07:04:07 +00:00
} else if ( value = = 102 ) {
2010-10-17 10:20:57 +00:00
chan - > nrpn_select + = 10000 ;
2009-09-22 07:04:07 +00:00
} else if ( value < 100 ) {
2010-10-17 10:20:57 +00:00
chan - > nrpn_select + = value ;
2009-09-22 07:04:07 +00:00
}
}
2003-04-03 21:32:56 +00:00
2010-10-17 10:20:57 +00:00
chan - > nrpn_active = 1 ;
2009-09-22 07:04:07 +00:00
break ;
case RPN_MSB :
case RPN_LSB :
2010-10-17 10:20:57 +00:00
chan - > nrpn_active = 0 ;
2009-09-22 07:04:07 +00:00
break ;
default :
return fluid_synth_modulate_voices_LOCAL ( synth , channum , 1 , num ) ;
}
2003-03-11 16:56:45 +00:00
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Get current MIDI controller value on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param num MIDI controller number ( 0 - 127 )
* @ param pval Location to store MIDI controller value ( 0 - 127 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_get_cc ( fluid_synth_t * synth , int chan , int num , int * pval )
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( num > = 0 & & num < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( pval ! = NULL , FLUID_FAILED ) ;
2007-03-04 16:45:05 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
* pval = fluid_channel_get_cc ( synth - > channel [ chan ] , num ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-26 20:10:14 +00:00
/*
* Handler for synth . device - id setting .
*/
static int
fluid_synth_update_device_id ( fluid_synth_t * synth , char * name , int value )
{
2010-10-17 10:20:57 +00:00
fluid_synth_api_enter ( synth ) ;
synth - > device_id = value ;
fluid_synth_api_exit ( synth ) ;
2009-09-26 20:10:14 +00:00
return 0 ;
}
/**
* Process a MIDI SYSEX ( system exclusive ) message .
* @ param synth FluidSynth instance
* @ param data Buffer containing SYSEX data ( not including 0xF0 and 0xF7 )
* @ param len Length of data in buffer
* @ param response Buffer to store response to or NULL to ignore
* @ param response_len IN / OUT parameter , in : size of response buffer , out :
* amount of data written to response buffer ( if FLUID_FAILED is returned and
* this value is non - zero , it indicates the response buffer is too small )
* @ param handled Optional location to store boolean value if message was
* recognized and handled or not ( set to TRUE if it was handled )
* @ param dryrun TRUE to just do a dry run but not actually execute the SYSEX
* command ( useful for checking if a SYSEX message would be handled )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
* @ since 1.1 .0
*/
/* SYSEX format (0xF0 and 0xF7 not passed to this function):
* Non - realtime : 0xF0 0x7E < DeviceId > [ BODY ] 0xF7
* Realtime : 0xF0 0x7F < DeviceId > [ BODY ] 0xF7
* Tuning messages : 0xF0 0x7E / 0x7F < DeviceId > 0x08 < sub ID2 > [ BODY ] < ChkSum > 0xF7
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_sysex ( fluid_synth_t * synth , const char * data , int len ,
2009-09-26 20:10:14 +00:00
char * response , int * response_len , int * handled , int dryrun )
{
int avail_response = 0 ;
if ( handled ) * handled = FALSE ;
if ( response_len )
{
avail_response = * response_len ;
* response_len = 0 ;
}
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( data ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( len > 0 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( ! response | | response_len , FLUID_FAILED ) ;
2009-10-12 19:18:06 +00:00
if ( len < 4 ) return FLUID_OK ;
2009-09-26 20:10:14 +00:00
2009-10-08 05:31:11 +00:00
/* MIDI tuning SYSEX message? */
if ( ( data [ 0 ] = = MIDI_SYSEX_UNIV_NON_REALTIME | | data [ 0 ] = = MIDI_SYSEX_UNIV_REALTIME )
& & ( data [ 1 ] = = synth - > device_id | | data [ 1 ] = = MIDI_SYSEX_DEVICE_ID_ALL )
& & data [ 2 ] = = MIDI_SYSEX_MIDI_TUNING_ID )
2010-07-01 11:14:55 +00:00
{
int result ;
fluid_synth_api_enter ( synth ) ;
result = fluid_synth_sysex_midi_tuning ( synth , data , len , response ,
response_len , avail_response ,
handled , dryrun ) ;
FLUID_API_RETURN ( result ) ;
}
2009-10-08 05:31:11 +00:00
return FLUID_OK ;
}
/* Handler for MIDI tuning SYSEX messages */
static int
2009-10-28 19:38:10 +00:00
fluid_synth_sysex_midi_tuning ( fluid_synth_t * synth , const char * data , int len ,
2009-10-08 05:31:11 +00:00
char * response , int * response_len , int avail_response ,
int * handled , int dryrun )
{
int realtime , msgid ;
int bank = 0 , prog , channels ;
double tunedata [ 128 ] ;
int keys [ 128 ] ;
char name [ 17 ] ;
int note , frac , frac2 ;
uint8 chksum ;
int i , count , index ;
2009-10-28 19:38:10 +00:00
const char * dataptr ;
char * resptr ; ;
2009-10-08 05:31:11 +00:00
realtime = data [ 0 ] = = MIDI_SYSEX_UNIV_REALTIME ;
2009-09-26 20:10:14 +00:00
msgid = data [ 3 ] ;
switch ( msgid )
{
case MIDI_SYSEX_TUNING_BULK_DUMP_REQ :
case MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK :
if ( data [ 3 ] = = MIDI_SYSEX_TUNING_BULK_DUMP_REQ )
{
if ( len ! = 5 | | data [ 4 ] & 0x80 | | ! response )
return FLUID_OK ;
* response_len = 406 ;
prog = data [ 4 ] ;
}
else
{
if ( len ! = 6 | | data [ 4 ] & 0x80 | | data [ 5 ] & 0x80 | | ! response )
return FLUID_OK ;
* response_len = 407 ;
bank = data [ 4 ] ;
prog = data [ 5 ] ;
}
if ( dryrun )
{
if ( handled ) * handled = TRUE ;
return FLUID_OK ;
}
if ( avail_response < * response_len ) return FLUID_FAILED ;
/* Get tuning data, return if tuning not found */
if ( fluid_synth_tuning_dump ( synth , bank , prog , name , 17 , tunedata ) = = FLUID_FAILED )
{
* response_len = 0 ;
return FLUID_OK ;
}
2009-10-28 19:38:10 +00:00
resptr = response ;
2009-09-26 20:10:14 +00:00
2009-10-28 19:38:10 +00:00
* resptr + + = MIDI_SYSEX_UNIV_NON_REALTIME ;
* resptr + + = synth - > device_id ;
* resptr + + = MIDI_SYSEX_MIDI_TUNING_ID ;
* resptr + + = MIDI_SYSEX_TUNING_BULK_DUMP ;
2009-09-26 20:10:14 +00:00
if ( msgid = = MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK )
2009-10-28 19:38:10 +00:00
* resptr + + = bank ;
2009-09-26 20:10:14 +00:00
2009-10-28 19:38:10 +00:00
* resptr + + = prog ;
FLUID_STRNCPY ( resptr , name , 16 ) ;
resptr + = 16 ;
2009-09-26 20:10:14 +00:00
for ( i = 0 ; i < 128 ; i + + )
{
note = tunedata [ i ] / 100.0 ;
fluid_clip ( note , 0 , 127 ) ;
frac = ( ( tunedata [ i ] - note * 100.0 ) * 16384.0 + 50.0 ) / 100.0 ;
fluid_clip ( frac , 0 , 16383 ) ;
2009-10-28 19:38:10 +00:00
* resptr + + = note ;
* resptr + + = frac > > 7 ;
* resptr + + = frac & 0x7F ;
2009-09-26 20:10:14 +00:00
}
if ( msgid = = MIDI_SYSEX_TUNING_BULK_DUMP_REQ )
{ /* NOTE: Checksum is not as straight forward as the bank based messages */
chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID
^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog ;
for ( i = 21 ; i < 128 * 3 + 21 ; i + + )
chksum ^ = response [ i ] ;
}
else
{
for ( i = 1 , chksum = 0 ; i < 406 ; i + + )
chksum ^ = response [ i ] ;
}
2009-10-28 19:38:10 +00:00
* resptr + + = chksum & 0x7F ;
2009-09-26 20:10:14 +00:00
if ( handled ) * handled = TRUE ;
break ;
case MIDI_SYSEX_TUNING_NOTE_TUNE :
case MIDI_SYSEX_TUNING_NOTE_TUNE_BANK :
dataptr = data + 4 ;
if ( msgid = = MIDI_SYSEX_TUNING_NOTE_TUNE )
{
if ( len < 10 | | data [ 4 ] & 0x80 | | data [ 5 ] & 0x80 | | len ! = data [ 5 ] * 4 + 6 )
return FLUID_OK ;
}
else
{
if ( len < 11 | | data [ 4 ] & 0x80 | | data [ 5 ] & 0x80 | | data [ 6 ] & 0x80
2017-07-01 16:24:02 +00:00
| | len ! = data [ 6 ] * 4 + 7 )
2009-09-26 20:10:14 +00:00
return FLUID_OK ;
bank = * dataptr + + ;
}
if ( dryrun )
{
if ( handled ) * handled = TRUE ;
return FLUID_OK ;
}
prog = * dataptr + + ;
count = * dataptr + + ;
for ( i = 0 , index = 0 ; i < count ; i + + )
{
note = * dataptr + + ;
if ( note & 0x80 ) return FLUID_OK ;
keys [ index ] = note ;
note = * dataptr + + ;
frac = * dataptr + + ;
frac2 = * dataptr + + ;
if ( note & 0x80 | | frac & 0x80 | | frac2 & 0x80 )
return FLUID_OK ;
frac = frac < < 7 | frac2 ;
/* No change pitch value? Doesn't really make sense to send that, but.. */
if ( note = = 0x7F & & frac = = 16383 ) continue ;
tunedata [ index ] = note * 100.0 + ( frac * 100.0 / 16384.0 ) ;
index + + ;
}
if ( index > 0 )
{
if ( fluid_synth_tune_notes ( synth , bank , prog , index , keys , tunedata ,
realtime ) = = FLUID_FAILED )
return FLUID_FAILED ;
}
if ( handled ) * handled = TRUE ;
break ;
case MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE :
case MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE :
if ( ( msgid = = MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE & & len ! = 19 )
| | ( msgid = = MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE & & len ! = 31 ) )
return FLUID_OK ;
if ( data [ 4 ] & 0x80 | | data [ 5 ] & 0x80 | | data [ 6 ] & 0x80 )
return FLUID_OK ;
if ( dryrun )
{
if ( handled ) * handled = TRUE ;
return FLUID_OK ;
}
channels = ( data [ 4 ] & 0x03 ) < < 14 | data [ 5 ] < < 7 | data [ 6 ] ;
if ( msgid = = MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE )
{
for ( i = 0 ; i < 12 ; i + + )
{
frac = data [ i + 7 ] ;
if ( frac & 0x80 ) return FLUID_OK ;
tunedata [ i ] = ( int ) frac - 64 ;
}
}
else
{
for ( i = 0 ; i < 12 ; i + + )
{
frac = data [ i * 2 + 7 ] ;
frac2 = data [ i * 2 + 8 ] ;
if ( frac & 0x80 | | frac2 & 0x80 ) return FLUID_OK ;
tunedata [ i ] = ( ( ( int ) frac < < 7 | ( int ) frac2 ) - 8192 ) * ( 200.0 / 16384.0 ) ;
}
}
if ( fluid_synth_activate_octave_tuning ( synth , 0 , 0 , " SYSEX " ,
tunedata , realtime ) = = FLUID_FAILED )
return FLUID_FAILED ;
if ( channels )
{
for ( i = 0 ; i < 16 ; i + + )
{
if ( channels & ( 1 < < i ) )
fluid_synth_activate_tuning ( synth , i , 0 , 0 , realtime ) ;
}
}
if ( handled ) * handled = TRUE ;
break ;
}
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Turn off all notes on a MIDI channel ( put them into release phase ) .
* @ param synth FluidSynth instance
2011-02-07 07:30:31 +00:00
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 ) , ( chan = - 1 selects all channels )
2009-09-22 07:04:07 +00:00
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2011-02-07 07:46:37 +00:00
* @ since 1.1 .4
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_all_notes_off ( fluid_synth_t * synth , int chan )
{
2011-02-07 07:46:37 +00:00
int result ;
2009-09-22 07:04:07 +00:00
2011-02-07 07:46:37 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( chan > = - 1 , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
if ( chan > = synth - > midi_channels )
result = FLUID_FAILED ;
else
result = fluid_synth_all_notes_off_LOCAL ( synth , chan ) ;
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
2011-02-07 07:30:31 +00:00
/* Local synthesis thread variant of all notes off, (chan=-1 selects all channels) */
2009-09-22 07:04:07 +00:00
static int
fluid_synth_all_notes_off_LOCAL ( fluid_synth_t * synth , int chan )
{
2003-03-11 16:56:45 +00:00
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2003-03-11 16:56:45 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2009-09-22 07:04:07 +00:00
2017-09-02 22:22:07 +00:00
if ( fluid_voice_is_playing ( voice ) & & ( ( - 1 = = chan ) | | ( chan = = fluid_voice_get_channel ( voice ) ) ) )
2009-10-14 07:27:30 +00:00
fluid_voice_noteoff ( voice ) ;
2003-03-11 16:56:45 +00:00
}
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Immediately stop all notes on a MIDI channel ( skips release phase ) .
* @ param synth FluidSynth instance
2011-02-07 07:30:31 +00:00
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 ) , ( chan = - 1 selects all channels )
2009-09-22 07:04:07 +00:00
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2011-02-07 07:46:37 +00:00
* @ since 1.1 .4
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_all_sounds_off ( fluid_synth_t * synth , int chan )
{
2010-10-17 10:20:57 +00:00
int result ;
2009-09-22 07:04:07 +00:00
2011-02-07 07:46:37 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( chan > = - 1 , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
if ( chan > = synth - > midi_channels )
result = FLUID_FAILED ;
else
result = fluid_synth_all_sounds_off_LOCAL ( synth , chan ) ;
2010-10-17 10:20:57 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
2011-02-07 07:30:31 +00:00
/* Local synthesis thread variant of all sounds off, (chan=-1 selects all channels) */
2009-09-22 07:04:07 +00:00
static int
fluid_synth_all_sounds_off_LOCAL ( fluid_synth_t * synth , int chan )
{
2003-03-11 16:56:45 +00:00
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2003-03-11 16:56:45 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2009-09-22 07:04:07 +00:00
2017-09-02 22:22:07 +00:00
if ( fluid_voice_is_playing ( voice ) & & ( ( - 1 = = chan ) | | ( chan = = fluid_voice_get_channel ( voice ) ) ) )
2003-03-11 16:56:45 +00:00
fluid_voice_off ( voice ) ;
}
return FLUID_OK ;
}
2012-11-18 09:30:46 +00:00
/**
* Reset reverb engine
* @ param synth FluidSynth instance
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
fluid_synth_reset_reverb ( fluid_synth_t * synth )
{
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_reset_reverb , 0 , 0.0f ) ;
FLUID_API_RETURN ( FLUID_OK ) ;
}
/**
* Reset chorus engine
* @ param synth FluidSynth instance
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
fluid_synth_reset_chorus ( fluid_synth_t * synth )
{
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_reset_chorus , 0 , 0.0f ) ;
FLUID_API_RETURN ( FLUID_OK ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Send MIDI system reset command ( big red ' panic ' button ) , turns off notes and
* resets controllers .
* @ param synth FluidSynth instance
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_system_reset ( fluid_synth_t * synth )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2010-10-17 10:20:57 +00:00
result = fluid_synth_system_reset_LOCAL ( synth ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
/* Local variant of the system reset command */
static int
fluid_synth_system_reset_LOCAL ( fluid_synth_t * synth )
{
2003-03-11 16:56:45 +00:00
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2003-03-11 16:56:45 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2009-09-22 07:04:07 +00:00
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_playing ( voice ) )
2003-03-11 16:56:45 +00:00
fluid_voice_off ( voice ) ;
}
2009-09-22 07:04:07 +00:00
for ( i = 0 ; i < synth - > midi_channels ; i + + )
2003-03-11 16:56:45 +00:00
fluid_channel_reset ( synth - > channel [ i ] ) ;
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_reset_fx , 0 , 0.0f ) ;
2003-03-11 16:56:45 +00:00
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Update voices on a MIDI channel after a MIDI control change .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param is_cc Boolean value indicating if ctrl is a CC controller or not
* @ param ctrl MIDI controller value
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
static int
fluid_synth_modulate_voices_LOCAL ( fluid_synth_t * synth , int chan , int is_cc , int ctrl )
2003-03-11 16:56:45 +00:00
{
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2004-03-29 10:05:18 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2009-09-22 07:04:07 +00:00
2017-09-02 22:22:07 +00:00
if ( fluid_voice_get_channel ( voice ) = = chan )
2003-03-11 16:56:45 +00:00
fluid_voice_modulate ( voice , is_cc , ctrl ) ;
}
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Update voices on a MIDI channel after all MIDI controllers have been changed .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
static int
fluid_synth_modulate_voices_all_LOCAL ( fluid_synth_t * synth , int chan )
2003-03-11 16:56:45 +00:00
{
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2003-03-11 16:56:45 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2009-09-22 07:04:07 +00:00
2017-09-02 22:22:07 +00:00
if ( fluid_voice_get_channel ( voice ) = = chan )
2003-03-11 16:56:45 +00:00
fluid_voice_modulate_all ( voice ) ;
}
return FLUID_OK ;
}
2009-01-22 16:47:21 +00:00
/**
* Set the MIDI channel pressure controller value .
* @ param synth FluidSynth instance
2009-09-22 07:04:07 +00:00
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param val MIDI channel pressure value ( 0 - 127 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-01-22 16:47:21 +00:00
*/
int
fluid_synth_channel_pressure ( fluid_synth_t * synth , int chan , int val )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( val > = 0 & & val < = 127 , FLUID_FAILED ) ;
2009-01-22 16:47:21 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-05 04:37:51 +00:00
if ( synth - > verbose )
FLUID_LOG ( FLUID_INFO , " channelpressure \t %d \t %d " , chan , val ) ;
fluid_channel_set_channel_pressure ( synth - > channel [ chan ] , val ) ;
2010-10-17 10:20:57 +00:00
result = fluid_synth_update_channel_pressure_LOCAL ( synth , chan ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
2009-01-22 16:47:21 +00:00
2009-11-05 04:37:51 +00:00
/* Updates channel pressure from within synthesis thread */
2009-09-22 07:04:07 +00:00
static int
2009-11-05 04:37:51 +00:00
fluid_synth_update_channel_pressure_LOCAL ( fluid_synth_t * synth , int chan )
2009-09-22 07:04:07 +00:00
{
return fluid_synth_modulate_voices_LOCAL ( synth , chan , 0 , FLUID_MOD_CHANNELPRESSURE ) ;
2009-01-22 16:47:21 +00:00
}
2008-12-23 10:15:01 +00:00
/**
2009-09-22 07:04:07 +00:00
* Set the MIDI pitch bend controller value on a MIDI channel .
2008-12-23 10:15:01 +00:00
* @ param synth FluidSynth instance
2009-09-22 07:04:07 +00:00
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param val MIDI pitch bend value ( 0 - 16383 with 8192 being center )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_pitch_bend ( fluid_synth_t * synth , int chan , int val )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( val > = 0 & & val < = 16383 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-05 04:37:51 +00:00
if ( synth - > verbose )
FLUID_LOG ( FLUID_INFO , " pitchb \t %d \t %d " , chan , val ) ;
fluid_channel_set_pitch_bend ( synth - > channel [ chan ] , val ) ;
2010-10-17 10:20:57 +00:00
result = fluid_synth_update_pitch_bend_LOCAL ( synth , chan ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/* Local synthesis thread variant of pitch bend */
static int
2009-11-05 04:37:51 +00:00
fluid_synth_update_pitch_bend_LOCAL ( fluid_synth_t * synth , int chan )
2009-09-22 07:04:07 +00:00
{
return fluid_synth_modulate_voices_LOCAL ( synth , chan , 0 , FLUID_MOD_PITCHWHEEL ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the MIDI pitch bend controller value on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param ppitch_bend Location to store MIDI pitch bend value ( 0 - 16383 with
* 8192 being center )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_get_pitch_bend ( fluid_synth_t * synth , int chan , int * ppitch_bend )
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( ppitch_bend ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-05 04:37:51 +00:00
* ppitch_bend = fluid_channel_get_pitch_bend ( synth - > channel [ chan ] ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Set MIDI pitch wheel sensitivity on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param val Pitch wheel sensitivity value in semitones
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_pitch_wheel_sens ( fluid_synth_t * synth , int chan , int val )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( val > = 0 & & val < = 72 , FLUID_FAILED ) ; /* 6 octaves!? Better than no limit.. */
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-05 04:37:51 +00:00
if ( synth - > verbose )
FLUID_LOG ( FLUID_INFO , " pitchsens \t %d \t %d " , chan , val ) ;
fluid_channel_set_pitch_wheel_sensitivity ( synth - > channel [ chan ] , val ) ;
2010-10-17 10:20:57 +00:00
result = fluid_synth_update_pitch_wheel_sens_LOCAL ( synth , chan ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/* Local synthesis thread variant of set pitch wheel sensitivity */
static int
2009-11-05 04:37:51 +00:00
fluid_synth_update_pitch_wheel_sens_LOCAL ( fluid_synth_t * synth , int chan )
2009-09-22 07:04:07 +00:00
{
return fluid_synth_modulate_voices_LOCAL ( synth , chan , 0 , FLUID_MOD_PITCHWHEELSENS ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get MIDI pitch wheel sensitivity on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param pval Location to store pitch wheel sensitivity value in semitones
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-10-15 07:00:30 +00:00
* @ since Sometime AFTER v1 .0 API freeze .
2003-05-14 00:37:01 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-05-14 00:37:01 +00:00
fluid_synth_get_pitch_wheel_sens ( fluid_synth_t * synth , int chan , int * pval )
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( pval ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-05 04:37:51 +00:00
* pval = fluid_channel_get_pitch_wheel_sensitivity ( synth - > channel [ chan ] ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Assign a preset to a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param preset Preset to assign to channel or NULL to clear ( ownership is taken over )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
static int
fluid_synth_set_preset ( fluid_synth_t * synth , int chan , fluid_preset_t * preset )
{
2009-11-16 07:43:43 +00:00
fluid_channel_t * channel ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( chan > = 0 & & chan < synth - > midi_channels , FLUID_FAILED ) ;
2009-11-27 22:28:23 +00:00
channel = synth - > channel [ chan ] ;
2010-10-17 10:20:57 +00:00
return fluid_channel_set_preset ( channel , preset ) ;
2003-05-14 00:37:01 +00:00
}
2009-09-22 07:04:07 +00:00
/* Get a preset by SoundFont, bank and program numbers.
* Returns preset pointer or NULL .
*
2017-08-13 13:16:55 +00:00
* @ note The returned preset has been allocated , caller owns it and should
2009-09-22 07:04:07 +00:00
* free it when finished using it .
2003-03-11 16:56:45 +00:00
*/
2009-06-07 05:16:47 +00:00
static fluid_preset_t *
2007-03-04 16:45:05 +00:00
fluid_synth_get_preset ( fluid_synth_t * synth , unsigned int sfontnum ,
2009-09-22 07:04:07 +00:00
unsigned int banknum , unsigned int prognum )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_preset_t * preset = NULL ;
fluid_sfont_info_t * sfont_info ;
fluid_list_t * list ;
2009-12-14 03:57:25 +00:00
/* 128 indicates an "unset" operation" */
if ( prognum = = FLUID_UNSET_PROGRAM ) return NULL ;
2009-09-22 07:04:07 +00:00
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
if ( fluid_sfont_get_id ( sfont_info - > sfont ) = = sfontnum )
{
preset = fluid_sfont_get_preset ( sfont_info - > sfont ,
banknum - sfont_info - > bankofs , prognum ) ;
if ( preset ) sfont_info - > refcount + + ; /* Add reference to SoundFont */
break ;
2003-03-11 16:56:45 +00:00
}
}
2009-09-22 07:04:07 +00:00
return preset ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/* Get a preset by SoundFont name, bank and program.
* Returns preset pointer or NULL .
*
2017-08-13 13:16:55 +00:00
* @ note The returned preset has been allocated , caller owns it and should
2009-09-22 07:04:07 +00:00
* free it when finished using it .
2004-02-28 13:20:07 +00:00
*/
2009-06-07 05:16:47 +00:00
static fluid_preset_t *
2009-09-22 07:04:07 +00:00
fluid_synth_get_preset_by_sfont_name ( fluid_synth_t * synth , const char * sfontname ,
unsigned int banknum , unsigned int prognum )
2004-02-28 13:20:07 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_preset_t * preset = NULL ;
fluid_sfont_info_t * sfont_info ;
fluid_list_t * list ;
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
if ( FLUID_STRCMP ( fluid_sfont_get_name ( sfont_info - > sfont ) , sfontname ) = = 0 )
{
preset = fluid_sfont_get_preset ( sfont_info - > sfont ,
banknum - sfont_info - > bankofs , prognum ) ;
if ( preset ) sfont_info - > refcount + + ; /* Add reference to SoundFont */
break ;
2004-02-28 13:20:07 +00:00
}
}
2009-09-22 07:04:07 +00:00
return preset ;
2004-02-28 13:20:07 +00:00
}
2009-09-22 07:04:07 +00:00
/* Find a preset by bank and program numbers.
* Returns preset pointer or NULL .
*
2017-08-13 13:16:55 +00:00
* @ note The returned preset has been allocated , caller owns it and should
2009-09-22 07:04:07 +00:00
* free it when finished using it . */
fluid_preset_t *
fluid_synth_find_preset ( fluid_synth_t * synth , unsigned int banknum ,
unsigned int prognum )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_preset_t * preset = NULL ;
fluid_sfont_info_t * sfont_info ;
fluid_list_t * list ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
preset = fluid_sfont_get_preset ( sfont_info - > sfont ,
banknum - sfont_info - > bankofs , prognum ) ;
if ( preset )
{
sfont_info - > refcount + + ; /* Add reference to SoundFont */
break ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
}
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
return preset ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Send a program change event on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param prognum MIDI program number ( 0 - 127 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-11-27 22:28:23 +00:00
/* FIXME - Currently not real-time safe, due to preset allocation and mutex lock,
* and may be called from within synthesis context . */
2009-12-14 03:57:25 +00:00
/* As of 1.1.1 prognum can be set to 128 to unset the preset. Not documented
* since fluid_synth_unset_program ( ) should be used instead . */
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_program_change ( fluid_synth_t * synth , int chan , int prognum )
{
fluid_preset_t * preset = NULL ;
fluid_channel_t * channel ;
2011-02-10 09:23:17 +00:00
int subst_bank , subst_prog , banknum = 0 , result ;
2003-03-11 16:56:45 +00:00
2009-12-14 03:57:25 +00:00
fluid_return_val_if_fail ( prognum > = 0 & & prognum < = 128 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-03-16 01:37:21 +00:00
channel = synth - > channel [ chan ] ;
2017-08-04 15:50:01 +00:00
if ( channel - > channel_type = = CHANNEL_TYPE_DRUM )
2011-02-10 09:23:17 +00:00
banknum = DRUM_INST_BANK ;
else
fluid_channel_get_sfont_bank_prog ( channel , NULL , & banknum , NULL ) ;
2003-03-11 16:56:45 +00:00
2009-03-16 01:37:21 +00:00
if ( synth - > verbose )
FLUID_LOG ( FLUID_INFO , " prog \t %d \t %d \t %d " , chan , banknum , prognum ) ;
2003-03-11 16:56:45 +00:00
2011-02-10 09:23:17 +00:00
/* I think this is a hack for MIDI files that do bank changes in GM mode.
* Proper way to handle this would probably be to ignore bank changes when in
* GM mode . - JG
* This is now possible by setting synth . midi - bank - select = gm , but let the hack
* stay for the time being . - DH
2009-03-16 01:37:21 +00:00
*/
2009-12-14 03:57:25 +00:00
if ( prognum ! = FLUID_UNSET_PROGRAM )
{
2011-02-10 09:23:17 +00:00
subst_bank = banknum ;
subst_prog = prognum ;
preset = fluid_synth_find_preset ( synth , subst_bank , subst_prog ) ;
2009-12-14 19:06:59 +00:00
/* Fallback to another preset if not found */
2011-02-10 09:23:17 +00:00
if ( ! preset ) {
/* Percussion: Fallback to preset 0 in percussion bank */
2017-07-15 15:53:10 +00:00
if ( channel - > channel_type = = CHANNEL_TYPE_DRUM ) {
2011-02-10 09:23:17 +00:00
subst_prog = 0 ;
2017-07-15 15:53:10 +00:00
subst_bank = DRUM_INST_BANK ;
2011-02-10 09:23:17 +00:00
preset = fluid_synth_find_preset ( synth , subst_bank , subst_prog ) ;
}
/* Melodic instrument */
else {
2009-12-14 19:06:59 +00:00
/* Fallback first to bank 0:prognum */
2011-02-10 09:23:17 +00:00
subst_bank = 0 ;
preset = fluid_synth_find_preset ( synth , subst_bank , subst_prog ) ;
2009-12-14 19:06:59 +00:00
2011-02-10 09:23:17 +00:00
/* Fallback to first preset in bank 0 (usually piano...) */
if ( ! preset )
2009-12-14 19:06:59 +00:00
{
subst_prog = 0 ;
2011-02-10 09:23:17 +00:00
preset = fluid_synth_find_preset ( synth , subst_bank , subst_prog ) ;
2009-12-14 19:06:59 +00:00
}
}
2003-03-11 16:56:45 +00:00
2009-12-14 19:06:59 +00:00
if ( preset )
FLUID_LOG ( FLUID_WARN , " Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d] " ,
chan , banknum , prognum , subst_bank , subst_prog ) ;
2011-02-10 09:23:17 +00:00
else
FLUID_LOG ( FLUID_WARN , " No preset found on channel %d [bank=%d prog=%d] " ,
chan , banknum , prognum ) ;
2009-12-14 19:06:59 +00:00
}
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/* Assign the SoundFont ID and program number to the channel */
fluid_channel_set_sfont_bank_prog ( channel , preset ? fluid_sfont_get_id ( preset - > sfont ) : 0 ,
- 1 , prognum ) ;
2010-07-01 11:14:55 +00:00
result = fluid_synth_set_preset ( synth , chan , preset ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Set instrument bank number on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param bank MIDI bank number
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_bank_select ( fluid_synth_t * synth , int chan , unsigned int bank )
2003-03-11 16:56:45 +00:00
{
2009-12-14 03:57:25 +00:00
fluid_return_val_if_fail ( bank < = 16383 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-12-14 03:57:25 +00:00
fluid_channel_set_sfont_bank_prog ( synth - > channel [ chan ] , - 1 , bank , - 1 ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2009-09-22 07:04:07 +00:00
}
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/**
* Set SoundFont ID on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param sfont_id ID of a loaded SoundFont
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_sfont_select ( fluid_synth_t * synth , int chan , unsigned int sfont_id )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-12-14 03:57:25 +00:00
fluid_channel_set_sfont_bank_prog ( synth - > channel [ chan ] , sfont_id , - 1 , - 1 ) ;
2009-11-17 08:13:23 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-11-27 22:28:23 +00:00
/**
* Set the preset of a MIDI channel to an unassigned state .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ return # FLUID_OK on success , # FLUID_FAILED otherwise
* @ since 1.1 .1
*
2009-12-14 03:57:25 +00:00
* Note : Channel retains its SoundFont ID and bank numbers , while the program
* number is set to an " unset " state . MIDI program changes may re - assign a
* preset if one matches .
2009-11-27 22:28:23 +00:00
*/
int
fluid_synth_unset_program ( fluid_synth_t * synth , int chan )
{
2010-07-01 11:14:55 +00:00
int result ;
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-27 22:28:23 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_synth_program_change ( synth , chan , FLUID_UNSET_PROGRAM ) ;
FLUID_API_RETURN ( result ) ;
2009-11-27 22:28:23 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get current SoundFont ID , bank number and program number for a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param sfont_id Location to store SoundFont ID
* @ param bank_num Location to store MIDI bank number
* @ param preset_num Location to store MIDI program number
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2009-09-22 07:04:07 +00:00
fluid_synth_get_program ( fluid_synth_t * synth , int chan , unsigned int * sfont_id ,
unsigned int * bank_num , unsigned int * preset_num )
2003-03-11 16:56:45 +00:00
{
fluid_channel_t * channel ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( sfont_id ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( bank_num ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( preset_num ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
channel = synth - > channel [ chan ] ;
fluid_channel_get_sfont_bank_prog ( channel , ( int * ) sfont_id , ( int * ) bank_num ,
( int * ) preset_num ) ;
2009-12-14 03:57:25 +00:00
/* 128 indicates that the preset is unset. Set to 0 to be backwards compatible. */
if ( * preset_num = = FLUID_UNSET_PROGRAM ) * preset_num = 0 ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Select an instrument on a MIDI channel by SoundFont ID , bank and program numbers .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param sfont_id ID of a loaded SoundFont
* @ param bank_num MIDI bank number
* @ param preset_num MIDI program number
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_program_select ( fluid_synth_t * synth , int chan , unsigned int sfont_id ,
unsigned int bank_num , unsigned int preset_num )
2003-03-11 16:56:45 +00:00
{
fluid_preset_t * preset = NULL ;
fluid_channel_t * channel ;
2010-07-01 11:14:55 +00:00
int result ;
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
2003-03-11 16:56:45 +00:00
channel = synth - > channel [ chan ] ;
2009-09-22 07:04:07 +00:00
/* ++ Allocate preset */
preset = fluid_synth_get_preset ( synth , sfont_id , bank_num , preset_num ) ;
2003-03-11 16:56:45 +00:00
if ( preset = = NULL ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR ,
2009-09-22 07:04:07 +00:00
" There is no preset with bank number %d and preset number %d in SoundFont %d " ,
bank_num , preset_num , sfont_id ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
}
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
/* Assign the new SoundFont ID, bank and program number to the channel */
fluid_channel_set_sfont_bank_prog ( channel , sfont_id , bank_num , preset_num ) ;
2010-07-01 11:14:55 +00:00
result = fluid_synth_set_preset ( synth , chan , preset ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Select an instrument on a MIDI channel by SoundFont name , bank and program numbers .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param sfont_name Name of a loaded SoundFont
* @ param bank_num MIDI bank number
* @ param preset_num MIDI program number
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-10-23 02:18:26 +00:00
* @ since 1.1 .0
2004-02-28 13:20:07 +00:00
*/
2009-09-22 07:04:07 +00:00
int
2009-10-23 02:18:26 +00:00
fluid_synth_program_select_by_sfont_name ( fluid_synth_t * synth , int chan ,
2009-10-28 19:38:10 +00:00
const char * sfont_name , unsigned int bank_num ,
2009-10-23 02:18:26 +00:00
unsigned int preset_num )
2004-02-28 13:20:07 +00:00
{
fluid_preset_t * preset = NULL ;
fluid_channel_t * channel ;
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( sfont_name ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2004-02-28 13:20:07 +00:00
2009-09-22 07:04:07 +00:00
channel = synth - > channel [ chan ] ;
2004-02-28 13:20:07 +00:00
2009-09-22 07:04:07 +00:00
/* ++ Allocate preset */
preset = fluid_synth_get_preset_by_sfont_name ( synth , sfont_name , bank_num ,
preset_num ) ;
2004-02-28 13:20:07 +00:00
if ( preset = = NULL ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR ,
" There is no preset with bank number %d and preset number %d in SoundFont %s " ,
2004-02-28 13:20:07 +00:00
bank_num , preset_num , sfont_name ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2004-02-28 13:20:07 +00:00
}
2009-09-22 07:04:07 +00:00
/* Assign the new SoundFont ID, bank and program number to the channel */
fluid_channel_set_sfont_bank_prog ( channel , fluid_sfont_get_id ( preset - > sfont ) ,
bank_num , preset_num ) ;
2010-07-01 11:14:55 +00:00
result = fluid_synth_set_preset ( synth , chan , preset ) ;
FLUID_API_RETURN ( result ) ;
2004-02-28 13:20:07 +00:00
}
2003-03-11 16:56:45 +00:00
/*
2009-09-22 07:04:07 +00:00
* This function assures that every MIDI channel has a valid preset
2009-06-07 05:16:47 +00:00
* ( NULL is okay ) . This function is called after a SoundFont is
* unloaded or reloaded .
2003-03-11 16:56:45 +00:00
*/
2009-06-07 05:16:47 +00:00
static void
fluid_synth_update_presets ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_channel_t * channel ;
fluid_preset_t * preset ;
int sfont , bank , prog ;
2003-03-11 16:56:45 +00:00
int chan ;
for ( chan = 0 ; chan < synth - > midi_channels ; chan + + ) {
channel = synth - > channel [ chan ] ;
2009-09-22 07:04:07 +00:00
fluid_channel_get_sfont_bank_prog ( channel , & sfont , & bank , & prog ) ;
preset = fluid_synth_get_preset ( synth , sfont , bank , prog ) ;
fluid_synth_set_preset ( synth , chan , preset ) ;
2003-03-11 16:56:45 +00:00
}
}
2010-07-14 08:45:17 +00:00
/* Handler for synth.gain setting. */
static int
fluid_synth_update_sample_rate ( fluid_synth_t * synth , char * name , double value )
{
fluid_synth_set_sample_rate ( synth , ( float ) value ) ;
return 0 ;
}
/**
* Set sample rate of the synth .
2017-08-13 13:16:55 +00:00
* @ note This function is currently experimental and should only be
2010-07-14 08:45:17 +00:00
* used when no voices or notes are active , and before any rendering calls .
* @ param synth FluidSynth instance
* @ param sample_rate New sample rate ( Hz )
* @ since 1.1 .2
*/
void
fluid_synth_set_sample_rate ( fluid_synth_t * synth , float sample_rate )
{
int i ;
fluid_return_if_fail ( synth ! = NULL ) ;
fluid_synth_api_enter ( synth ) ;
2010-10-18 05:32:34 +00:00
fluid_clip ( sample_rate , 8000.0f , 96000.0f ) ;
2010-07-14 08:45:17 +00:00
synth - > sample_rate = sample_rate ;
fluid_settings_getint ( synth - > settings , " synth.min-note-length " , & i ) ;
synth - > min_note_length_ticks = ( unsigned int ) ( i * synth - > sample_rate / 1000.0f ) ;
2010-07-14 08:46:03 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + )
fluid_voice_set_output_rate ( synth - > voice [ i ] , sample_rate ) ;
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_set_samplerate ,
0 , sample_rate ) ;
2010-07-14 08:45:17 +00:00
fluid_synth_api_exit ( synth ) ;
}
2009-09-22 07:04:07 +00:00
/* Handler for synth.gain setting. */
2009-06-07 05:16:47 +00:00
static int
fluid_synth_update_gain ( fluid_synth_t * synth , char * name , double value )
2003-04-03 21:32:56 +00:00
{
fluid_synth_set_gain ( synth , ( float ) value ) ;
return 0 ;
}
2009-09-22 07:04:07 +00:00
/**
* Set synth output gain value .
* @ param synth FluidSynth instance
* @ param gain Gain value ( function clamps value to the range 0.0 to 10.0 )
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
void
fluid_synth_set_gain ( fluid_synth_t * synth , float gain )
{
fluid_return_if_fail ( synth ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
fluid_clip ( gain , 0.0f , 10.0f ) ;
2010-10-17 10:20:57 +00:00
synth - > gain = gain ;
fluid_synth_update_gain_LOCAL ( synth ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2009-09-22 07:04:07 +00:00
}
/* Called by synthesis thread to update the gain in all voices */
static void
2009-11-05 04:37:51 +00:00
fluid_synth_update_gain_LOCAL ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2009-11-15 02:34:24 +00:00
fluid_voice_t * voice ;
2009-11-05 04:37:51 +00:00
float gain ;
2003-03-11 16:56:45 +00:00
int i ;
2010-10-17 10:20:57 +00:00
gain = synth - > gain ;
2003-03-11 16:56:45 +00:00
2009-11-15 02:34:24 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + )
{
voice = synth - > voice [ i ] ;
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_playing ( voice ) ) fluid_voice_set_gain ( voice , gain ) ;
2003-03-11 16:56:45 +00:00
}
}
2009-09-22 07:04:07 +00:00
/**
* Get synth output gain value .
* @ param synth FluidSynth instance
* @ return Synth gain value ( 0.0 to 10.0 )
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
float
fluid_synth_get_gain ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-03 13:04:04 +00:00
float result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-10-17 10:20:57 +00:00
result = synth - > gain ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2005-06-08 03:51:13 +00:00
/*
2009-09-22 07:04:07 +00:00
* Handler for synth . polyphony setting .
2005-06-08 03:51:13 +00:00
*/
2009-06-07 05:16:47 +00:00
static int
fluid_synth_update_polyphony ( fluid_synth_t * synth , char * name , int value )
2005-06-08 03:51:13 +00:00
{
fluid_synth_set_polyphony ( synth , value ) ;
return 0 ;
}
2009-09-22 07:04:07 +00:00
/**
* Set synthesizer polyphony ( max number of voices ) .
* @ param synth FluidSynth instance
* @ param polyphony Polyphony to assign
* @ return FLUID_OK on success , FLUID_FAILED otherwise
* @ since 1.0 .6
2005-06-08 03:51:13 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_set_polyphony ( fluid_synth_t * synth , int polyphony )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
2010-07-31 20:50:47 +00:00
fluid_return_val_if_fail ( polyphony > = 1 & & polyphony < = 65535 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-10-17 10:43:48 +00:00
result = fluid_synth_update_polyphony_LOCAL ( synth , polyphony ) ;
2009-11-05 04:37:51 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
/* Called by synthesis thread to update the polyphony value */
static int
2010-10-17 10:20:57 +00:00
fluid_synth_update_polyphony_LOCAL ( fluid_synth_t * synth , int new_polyphony )
2005-06-08 03:51:13 +00:00
{
2009-11-15 02:34:24 +00:00
fluid_voice_t * voice ;
2010-10-17 10:20:57 +00:00
int i ;
2010-07-31 20:50:47 +00:00
2010-08-04 20:56:36 +00:00
if ( new_polyphony > synth - > nvoice ) {
2010-07-31 20:50:47 +00:00
/* Create more voices */
fluid_voice_t * * new_voices = FLUID_REALLOC ( synth - > voice ,
sizeof ( fluid_voice_t * ) * new_polyphony ) ;
if ( new_voices = = NULL )
return FLUID_FAILED ;
synth - > voice = new_voices ;
for ( i = synth - > nvoice ; i < new_polyphony ; i + + ) {
synth - > voice [ i ] = new_fluid_voice ( synth - > sample_rate ) ;
if ( synth - > voice [ i ] = = NULL )
return FLUID_FAILED ;
}
synth - > nvoice = new_polyphony ;
}
synth - > polyphony = new_polyphony ;
2005-06-08 03:51:13 +00:00
/* turn off any voices above the new limit */
2009-11-15 02:34:24 +00:00
for ( i = synth - > polyphony ; i < synth - > nvoice ; i + + )
{
voice = synth - > voice [ i ] ;
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_playing ( voice ) ) fluid_voice_off ( voice ) ;
2005-06-08 03:51:13 +00:00
}
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_set_polyphony ,
synth - > polyphony , 0.0f ) ;
2010-06-28 20:03:12 +00:00
2005-06-08 03:51:13 +00:00
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Get current synthesizer polyphony ( max number of voices ) .
* @ param synth FluidSynth instance
* @ return Synth polyphony value .
* @ since 1.0 .6
2005-06-08 03:51:13 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_get_polyphony ( fluid_synth_t * synth )
2005-06-08 03:51:13 +00:00
{
2010-07-01 11:14:55 +00:00
int result ;
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
2010-10-17 10:20:57 +00:00
result = synth - > polyphony ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2005-06-08 03:51:13 +00:00
}
2009-11-01 22:56:26 +00:00
/**
* Get current number of active voices .
* @ param synth FluidSynth instance
* @ return Number of currently active voices .
* @ since 1.1 .0
*
* Note : To generate accurate continuous statistics of the voice count , caller
* should ensure this function is called synchronously with the audio synthesis
* process . This can be done in the new_fluid_audio_driver2 ( ) audio callback
* function for example .
*/
int
fluid_synth_get_active_voice_count ( fluid_synth_t * synth )
{
2010-07-01 11:14:55 +00:00
int result ;
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
2010-10-17 10:20:57 +00:00
result = synth - > active_voice_count ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2009-11-01 22:56:26 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the internal synthesis buffer size value .
* @ param synth FluidSynth instance
* @ return Internal buffer size in audio frames .
*
* Audio is synthesized this number of frames at a time . Defaults to 64 frames .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_get_internal_bufsize ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
return FLUID_BUFSIZE ;
}
2009-10-28 19:38:10 +00:00
/**
2009-09-22 07:04:07 +00:00
* Resend a bank select and a program change for every channel .
* @ param synth FluidSynth instance
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*
2009-09-22 07:04:07 +00:00
* This function is called mainly after a SoundFont has been loaded ,
* unloaded or reloaded .
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_program_reset ( fluid_synth_t * synth )
2007-03-04 16:45:05 +00:00
{
2009-09-22 07:04:07 +00:00
int i , prog ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2003-03-11 16:56:45 +00:00
/* try to set the correct presets */
for ( i = 0 ; i < synth - > midi_channels ; i + + ) {
2009-09-22 07:04:07 +00:00
fluid_channel_get_sfont_bank_prog ( synth - > channel [ i ] , NULL , NULL , & prog ) ;
fluid_synth_program_change ( synth , i , prog ) ;
2003-03-11 16:56:45 +00:00
}
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
2017-07-15 16:22:29 +00:00
* Synthesize a block of floating point audio to separate audio buffers ( multichannel rendering ) . First effect channel used by reverb , second for chorus .
2009-09-22 07:04:07 +00:00
* @ param synth FluidSynth instance
* @ param len Count of audio frames to synthesize
2017-07-15 16:22:29 +00:00
* @ param left Array of float buffers to store left channel of planar audio ( as many as \ c synth . audio - channels buffers , each of \ c len in size )
* @ param right Array of float buffers to store right channel of planar audio ( size : dito )
2017-07-15 16:25:16 +00:00
* @ param fx_left Since 1.1 .7 : If not \ c NULL , array of float buffers to store left effect channels ( as many as \ c synth . effects - channels buffers , each of \ c len in size )
* @ param fx_right Since 1.1 .7 : If not \ c NULL , array of float buffers to store right effect channels ( size : dito )
2009-09-22 07:04:07 +00:00
* @ return FLUID_OK on success , FLUID_FAIL otherwise
*
2017-07-12 19:44:20 +00:00
* @ note Should only be called from synthesis thread .
2017-07-13 10:02:58 +00:00
*
* Usage example :
* @ code
const int FramesToRender = 64 ;
int channels ;
// retrieve number of stereo audio channels
fluid_settings_getint ( settings , " synth.audio-channels " , & channels ) ;
// we need twice as many (mono-)buffers
channels * = 2 ;
2017-07-15 16:22:29 +00:00
// fluid_synth_nwrite_float renders planar audio, e.g. if synth.audio-channels==16: each midi channel gets rendered to its own stereo buffer, rather than having one buffer and interleaved PCM
2017-07-13 10:02:58 +00:00
float * * mix_buf = new float * [ channels ] ;
for ( int i = 0 ; i < channels ; i + + )
{
mix_buf [ i ] = new float [ FramesToRender ] ;
}
// retrieve number of (stereo) effect channels (internally hardcoded to reverb (first chan) and chrous (second chan))
fluid_settings_getint ( settings , " synth.effects-channels " , & channels ) ;
channels * = 2 ;
float * * fx_buf = new float * [ channels ] ;
for ( int i = 0 ; i < channels ; i + + )
{
fx_buf [ i ] = new float [ FramesToRender ] ;
}
float * * mix_buf_l = mix_buf ;
float * * mix_buf_r = & mix_buf [ channels / 2 ] ;
float * * fx_buf_l = fx_buf ;
float * * fx_buf_r = & fx_buf [ channels / 2 ] ;
fluid_synth_nwrite_float ( synth , FramesToRender , mix_buf_l , mix_buf_r , fx_buf_l , fx_buf_r )
* @ endcode
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_nwrite_float ( fluid_synth_t * synth , int len ,
float * * left , float * * right ,
float * * fx_left , float * * fx_right )
2003-03-11 16:56:45 +00:00
{
2017-07-13 10:02:58 +00:00
fluid_real_t * * left_in , * * fx_left_in ;
fluid_real_t * * right_in , * * fx_right_in ;
2009-09-22 07:04:07 +00:00
double time = fluid_utime ( ) ;
2012-09-23 09:08:45 +00:00
int i , num , available , count ;
# ifdef WITH_FLOAT
int bytes ;
# endif
2009-09-25 00:56:48 +00:00
float cpu_load ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
if ( ! synth - > eventhandler - > is_threadsafe )
fluid_synth_api_enter ( synth ) ;
2003-03-11 16:56:45 +00:00
/* First, take what's still available in the buffer */
count = 0 ;
2005-06-08 03:51:13 +00:00
num = synth - > cur ;
if ( synth - > cur < FLUID_BUFSIZE ) {
available = FLUID_BUFSIZE - synth - > cur ;
2010-06-30 16:39:20 +00:00
fluid_rvoice_mixer_get_bufs ( synth - > eventhandler - > mixer , & left_in , & right_in ) ;
2017-07-13 10:02:58 +00:00
fluid_rvoice_mixer_get_fx_bufs ( synth - > eventhandler - > mixer , & fx_left_in , & fx_right_in ) ;
2003-03-11 16:56:45 +00:00
2005-06-08 03:51:13 +00:00
num = ( available > len ) ? len : available ;
2012-09-23 09:08:45 +00:00
# ifdef WITH_FLOAT
2005-06-08 03:51:13 +00:00
bytes = num * sizeof ( float ) ;
2012-09-23 09:08:45 +00:00
# endif
2003-03-11 16:56:45 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > audio_channels ; i + + ) {
2010-09-28 20:14:35 +00:00
# ifdef WITH_FLOAT
2005-06-08 03:51:13 +00:00
FLUID_MEMCPY ( left [ i ] , left_in [ i ] + synth - > cur , bytes ) ;
FLUID_MEMCPY ( right [ i ] , right_in [ i ] + synth - > cur , bytes ) ;
2010-09-28 20:14:35 +00:00
# else //WITH_FLOAT
2010-10-13 21:57:19 +00:00
int j ;
2010-09-28 20:14:35 +00:00
for ( j = 0 ; j < num ; j + + ) {
left [ i ] [ j ] = ( float ) left_in [ i ] [ j + synth - > cur ] ;
right [ i ] [ j ] = ( float ) right_in [ i ] [ j + synth - > cur ] ;
}
# endif //WITH_FLOAT
2005-06-08 03:51:13 +00:00
}
2017-07-13 10:02:58 +00:00
for ( i = 0 ; i < synth - > effects_channels ; i + + )
{
# ifdef WITH_FLOAT
if ( fx_left ! = NULL )
FLUID_MEMCPY ( fx_left [ i ] , fx_left_in [ i ] + synth - > cur , bytes ) ;
if ( fx_right ! = NULL )
FLUID_MEMCPY ( fx_right [ i ] , fx_right_in [ i ] + synth - > cur , bytes ) ;
# else //WITH_FLOAT
int j ;
2017-07-31 14:19:50 +00:00
if ( fx_left ! = NULL ) {
for ( j = 0 ; j < num ; j + + )
2017-07-13 10:02:58 +00:00
fx_left [ i ] [ j ] = ( float ) fx_left_in [ i ] [ j + synth - > cur ] ;
2017-07-31 14:19:50 +00:00
}
2017-07-13 10:02:58 +00:00
2017-07-31 14:19:50 +00:00
if ( fx_right ! = NULL ) {
for ( j = 0 ; j < num ; j + + )
2017-07-13 10:02:58 +00:00
fx_right [ i ] [ j ] = ( float ) fx_right_in [ i ] [ j + synth - > cur ] ;
2017-07-31 14:19:50 +00:00
}
2017-07-13 10:02:58 +00:00
# endif //WITH_FLOAT
}
2005-06-08 03:51:13 +00:00
count + = num ;
num + = synth - > cur ; /* if we're now done, num becomes the new synth->cur below */
2003-03-11 16:56:45 +00:00
}
/* Then, run one_block() and copy till we have 'len' samples */
while ( count < len ) {
2010-07-03 12:25:43 +00:00
fluid_rvoice_mixer_set_mix_fx ( synth - > eventhandler - > mixer , 0 ) ;
2010-09-30 06:04:25 +00:00
fluid_synth_render_blocks ( synth , 1 ) ; // TODO:
2010-06-30 16:39:20 +00:00
fluid_rvoice_mixer_get_bufs ( synth - > eventhandler - > mixer , & left_in , & right_in ) ;
2017-07-13 10:02:58 +00:00
fluid_rvoice_mixer_get_fx_bufs ( synth - > eventhandler - > mixer , & fx_left_in , & fx_right_in ) ;
2003-03-11 16:56:45 +00:00
2004-03-19 11:52:56 +00:00
num = ( FLUID_BUFSIZE > len - count ) ? len - count : FLUID_BUFSIZE ;
2012-09-23 09:08:45 +00:00
# ifdef WITH_FLOAT
2004-03-19 11:52:56 +00:00
bytes = num * sizeof ( float ) ;
2012-09-23 09:08:45 +00:00
# endif
2007-03-04 16:45:05 +00:00
2004-03-19 11:52:56 +00:00
for ( i = 0 ; i < synth - > audio_channels ; i + + ) {
2010-09-30 06:04:25 +00:00
# ifdef WITH_FLOAT
2004-03-19 11:52:56 +00:00
FLUID_MEMCPY ( left [ i ] + count , left_in [ i ] , bytes ) ;
FLUID_MEMCPY ( right [ i ] + count , right_in [ i ] , bytes ) ;
2010-09-30 06:04:25 +00:00
# else //WITH_FLOAT
2010-10-13 21:57:19 +00:00
int j ;
2010-09-30 06:04:25 +00:00
for ( j = 0 ; j < num ; j + + ) {
left [ i ] [ j + count ] = ( float ) left_in [ i ] [ j ] ;
right [ i ] [ j + count ] = ( float ) right_in [ i ] [ j ] ;
}
# endif //WITH_FLOAT
2004-03-19 11:52:56 +00:00
}
2007-03-04 16:45:05 +00:00
2017-07-13 10:02:58 +00:00
for ( i = 0 ; i < synth - > effects_channels ; i + + )
{
# ifdef WITH_FLOAT
if ( fx_left ! = NULL )
FLUID_MEMCPY ( fx_left [ i + count ] , fx_left_in [ i ] , bytes ) ;
if ( fx_right ! = NULL )
FLUID_MEMCPY ( fx_right [ i + count ] , fx_right_in [ i ] , bytes ) ;
# else //WITH_FLOAT
int j ;
2017-07-31 14:19:50 +00:00
if ( fx_left ! = NULL ) {
for ( j = 0 ; j < num ; j + + )
2017-07-13 10:02:58 +00:00
fx_left [ i ] [ j + count ] = ( float ) fx_left_in [ i ] [ j ] ;
2017-07-31 14:19:50 +00:00
}
2017-07-13 10:02:58 +00:00
2017-07-31 14:19:50 +00:00
if ( fx_right ! = NULL ) {
for ( j = 0 ; j < num ; j + + )
2017-07-13 10:02:58 +00:00
fx_right [ i ] [ j + count ] = ( float ) fx_right_in [ i ] [ j ] ;
2017-07-31 14:19:50 +00:00
}
2017-07-13 10:02:58 +00:00
# endif //WITH_FLOAT
}
2004-03-19 11:52:56 +00:00
count + = num ;
2003-03-11 16:56:45 +00:00
}
synth - > cur = num ;
time = fluid_utime ( ) - time ;
2009-09-25 00:56:48 +00:00
cpu_load = 0.5 * ( synth - > cpu_load + time * synth - > sample_rate / len / 10000.0 ) ;
fluid_atomic_float_set ( & synth - > cpu_load , cpu_load ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
if ( ! synth - > eventhandler - > is_threadsafe )
fluid_synth_api_exit ( synth ) ;
2009-09-22 07:04:07 +00:00
return FLUID_OK ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Synthesize floating point audio to audio buffers .
* @ param synth FluidSynth instance
* @ param len Count of audio frames to synthesize
* @ param nin Ignored
* @ param in Ignored
* @ param nout Count of arrays in ' out '
* @ param out Array of arrays to store audio to
* @ return FLUID_OK on success , FLUID_FAIL otherwise
*
* This function implements the default interface defined in fluidsynth / audio . h .
2017-07-12 19:44:20 +00:00
*
* @ note Should only be called from synthesis thread .
2009-09-22 07:04:07 +00:00
*/
/*
* FIXME : Currently if nout ! = 2 memory allocation will occur !
*/
int
fluid_synth_process ( fluid_synth_t * synth , int len , int nin , float * * in ,
int nout , float * * out )
2003-03-11 16:56:45 +00:00
{
2009-02-22 09:52:32 +00:00
if ( nout = = 2 ) {
return fluid_synth_write_float ( synth , len , out [ 0 ] , 0 , 1 , out [ 1 ] , 0 , 1 ) ;
}
else {
float * * left , * * right ;
int i ;
left = FLUID_ARRAY ( float * , nout / 2 ) ;
right = FLUID_ARRAY ( float * , nout / 2 ) ;
2017-06-25 08:13:45 +00:00
if ( ( left = = NULL ) | | ( right = = NULL ) ) {
FLUID_LOG ( FLUID_ERR , " Out of memory. " ) ;
FLUID_FREE ( left ) ;
FLUID_FREE ( right ) ;
return FLUID_FAILED ;
}
2009-02-22 09:52:32 +00:00
for ( i = 0 ; i < nout / 2 ; i + + ) {
left [ i ] = out [ 2 * i ] ;
right [ i ] = out [ 2 * i + 1 ] ;
}
fluid_synth_nwrite_float ( synth , len , left , right , NULL , NULL ) ;
FLUID_FREE ( left ) ;
FLUID_FREE ( right ) ;
2009-09-22 07:04:07 +00:00
return FLUID_OK ;
2009-02-22 09:52:32 +00:00
}
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Synthesize a block of floating point audio samples to audio buffers .
* @ param synth FluidSynth instance
* @ param len Count of audio frames to synthesize
* @ param lout Array of floats to store left channel of audio
* @ param loff Offset index in ' lout ' for first sample
* @ param lincr Increment between samples stored to ' lout '
* @ param rout Array of floats to store right channel of audio
* @ param roff Offset index in ' rout ' for first sample
* @ param rincr Increment between samples stored to ' rout '
* @ return FLUID_OK on success , FLUID_FAIL otherwise
*
* Useful for storing interleaved stereo ( lout = rout , loff = 0 , roff = 1 ,
* lincr = 2 , rincr = 2 ) .
*
2017-07-12 19:44:20 +00:00
* @ note Should only be called from synthesis thread .
* @ note Reverb and Chorus are mixed to \ c lout resp . \ c rout .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
fluid_synth_write_float ( fluid_synth_t * synth , int len ,
2009-09-22 07:04:07 +00:00
void * lout , int loff , int lincr ,
void * rout , int roff , int rincr )
2003-03-11 16:56:45 +00:00
{
int i , j , k , l ;
float * left_out = ( float * ) lout ;
float * right_out = ( float * ) rout ;
2010-06-30 16:39:20 +00:00
fluid_real_t * * left_in ;
fluid_real_t * * right_in ;
2003-03-11 16:56:45 +00:00
double time = fluid_utime ( ) ;
2009-09-25 00:56:48 +00:00
float cpu_load ;
2003-03-11 16:56:45 +00:00
2010-07-04 09:05:32 +00:00
fluid_profile_ref_var ( prof_ref ) ;
2010-07-01 11:14:55 +00:00
if ( ! synth - > eventhandler - > is_threadsafe )
fluid_synth_api_enter ( synth ) ;
2010-07-03 12:25:43 +00:00
fluid_rvoice_mixer_set_mix_fx ( synth - > eventhandler - > mixer , 1 ) ;
2003-03-11 16:56:45 +00:00
l = synth - > cur ;
2010-07-03 12:25:43 +00:00
fluid_rvoice_mixer_get_bufs ( synth - > eventhandler - > mixer , & left_in , & right_in ) ;
2003-03-11 16:56:45 +00:00
for ( i = 0 , j = loff , k = roff ; i < len ; i + + , l + + , j + = lincr , k + = rincr ) {
/* fill up the buffers as needed */
2010-07-03 12:25:43 +00:00
if ( l > = synth - > curmax ) {
int blocksleft = ( len - i + FLUID_BUFSIZE - 1 ) / FLUID_BUFSIZE ;
synth - > curmax = FLUID_BUFSIZE * fluid_synth_render_blocks ( synth , blocksleft ) ;
2010-06-30 16:39:20 +00:00
fluid_rvoice_mixer_get_bufs ( synth - > eventhandler - > mixer , & left_in , & right_in ) ;
2003-03-11 16:56:45 +00:00
l = 0 ;
}
2007-03-04 16:45:05 +00:00
2010-06-30 16:39:20 +00:00
left_out [ j ] = ( float ) left_in [ 0 ] [ l ] ;
right_out [ k ] = ( float ) right_in [ 0 ] [ l ] ;
2003-03-11 16:56:45 +00:00
}
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
synth - > cur = l ;
time = fluid_utime ( ) - time ;
2009-09-25 00:56:48 +00:00
cpu_load = 0.5 * ( synth - > cpu_load + time * synth - > sample_rate / len / 10000.0 ) ;
fluid_atomic_float_set ( & synth - > cpu_load , cpu_load ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
if ( ! synth - > eventhandler - > is_threadsafe )
fluid_synth_api_exit ( synth ) ;
2010-07-04 09:05:32 +00:00
fluid_profile ( FLUID_PROF_WRITE , prof_ref ) ;
2010-07-01 11:14:55 +00:00
2009-09-22 07:04:07 +00:00
return FLUID_OK ;
2003-03-11 16:56:45 +00:00
}
2006-11-21 20:04:31 +00:00
# define DITHER_SIZE 48000
# define DITHER_CHANNELS 2
static float rand_table [ DITHER_CHANNELS ] [ DITHER_SIZE ] ;
2009-09-22 07:04:07 +00:00
/* Init dither table */
2009-06-07 05:16:47 +00:00
static void
init_dither ( void )
2006-11-21 20:04:31 +00:00
{
float d , dp ;
int c , i ;
for ( c = 0 ; c < DITHER_CHANNELS ; c + + ) {
dp = 0 ;
for ( i = 0 ; i < DITHER_SIZE - 1 ; i + + ) {
d = rand ( ) / ( float ) RAND_MAX - 0.5f ;
rand_table [ c ] [ i ] = d - dp ;
dp = d ;
}
rand_table [ c ] [ DITHER_SIZE - 1 ] = 0 - dp ;
}
}
2007-01-14 17:48:51 +00:00
/* A portable replacement for roundf(), seems it may actually be faster too! */
static inline int
roundi ( float x )
{
if ( x > = 0.0f )
return ( int ) ( x + 0.5f ) ;
else
return ( int ) ( x - 0.5f ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Synthesize a block of 16 bit audio samples to audio buffers .
* @ param synth FluidSynth instance
* @ param len Count of audio frames to synthesize
* @ param lout Array of 16 bit words to store left channel of audio
* @ param loff Offset index in ' lout ' for first sample
* @ param lincr Increment between samples stored to ' lout '
* @ param rout Array of 16 bit words to store right channel of audio
* @ param roff Offset index in ' rout ' for first sample
* @ param rincr Increment between samples stored to ' rout '
* @ return FLUID_OK on success , FLUID_FAIL otherwise
*
* Useful for storing interleaved stereo ( lout = rout , loff = 0 , roff = 1 ,
* lincr = 2 , rincr = 2 ) .
*
2017-07-12 19:44:20 +00:00
* @ note Should only be called from synthesis thread .
* @ note Reverb and Chorus are mixed to \ c lout resp . \ c rout .
* @ note Dithering is performed when converting from internal floating point to
2009-09-22 07:04:07 +00:00
* 16 bit audio .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
fluid_synth_write_s16 ( fluid_synth_t * synth , int len ,
2009-09-22 07:04:07 +00:00
void * lout , int loff , int lincr ,
void * rout , int roff , int rincr )
2003-03-11 16:56:45 +00:00
{
int i , j , k , cur ;
signed short * left_out = ( signed short * ) lout ;
signed short * right_out = ( signed short * ) rout ;
2010-06-30 16:39:20 +00:00
fluid_real_t * * left_in ;
fluid_real_t * * right_in ;
2003-03-11 16:56:45 +00:00
fluid_real_t left_sample ;
fluid_real_t right_sample ;
double time = fluid_utime ( ) ;
2010-07-01 11:14:55 +00:00
int di ;
2010-07-04 09:05:32 +00:00
//double prof_ref_on_block;
2009-09-25 00:56:48 +00:00
float cpu_load ;
2009-10-07 05:20:55 +00:00
fluid_profile_ref_var ( prof_ref ) ;
2010-07-01 11:14:55 +00:00
if ( ! synth - > eventhandler - > is_threadsafe )
fluid_synth_api_enter ( synth ) ;
2010-07-03 12:25:43 +00:00
fluid_rvoice_mixer_set_mix_fx ( synth - > eventhandler - > mixer , 1 ) ;
fluid_rvoice_mixer_get_bufs ( synth - > eventhandler - > mixer , & left_in , & right_in ) ;
2003-03-11 16:56:45 +00:00
cur = synth - > cur ;
2010-07-01 11:14:55 +00:00
di = synth - > dither_index ;
2003-03-11 16:56:45 +00:00
for ( i = 0 , j = loff , k = roff ; i < len ; i + + , cur + + , j + = lincr , k + = rincr ) {
/* fill up the buffers as needed */
2010-07-03 12:25:43 +00:00
if ( cur > = synth - > curmax ) {
int blocksleft = ( len - i + FLUID_BUFSIZE - 1 ) / FLUID_BUFSIZE ;
2010-07-04 09:05:32 +00:00
//prof_ref_on_block = fluid_profile_ref();
2010-07-03 12:25:43 +00:00
synth - > curmax = FLUID_BUFSIZE * fluid_synth_render_blocks ( synth , blocksleft ) ;
2010-06-30 16:39:20 +00:00
fluid_rvoice_mixer_get_bufs ( synth - > eventhandler - > mixer , & left_in , & right_in ) ;
2003-03-11 16:56:45 +00:00
cur = 0 ;
2007-03-04 16:45:05 +00:00
2010-07-04 09:05:32 +00:00
//fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
2003-03-11 16:56:45 +00:00
}
2010-06-30 16:39:20 +00:00
left_sample = roundi ( left_in [ 0 ] [ cur ] * 32766.0f + rand_table [ 0 ] [ di ] ) ;
right_sample = roundi ( right_in [ 0 ] [ cur ] * 32766.0f + rand_table [ 1 ] [ di ] ) ;
2006-11-21 20:04:31 +00:00
di + + ;
if ( di > = DITHER_SIZE ) di = 0 ;
2003-03-11 16:56:45 +00:00
/* digital clipping */
2006-11-21 20:04:31 +00:00
if ( left_sample > 32767.0f ) left_sample = 32767.0f ;
if ( left_sample < - 32768.0f ) left_sample = - 32768.0f ;
if ( right_sample > 32767.0f ) right_sample = 32767.0f ;
if ( right_sample < - 32768.0f ) right_sample = - 32768.0f ;
2003-03-11 16:56:45 +00:00
left_out [ j ] = ( signed short ) left_sample ;
right_out [ k ] = ( signed short ) right_sample ;
}
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
synth - > cur = cur ;
2006-11-21 20:04:31 +00:00
synth - > dither_index = di ; /* keep dither buffer continous */
2003-03-11 16:56:45 +00:00
2010-07-04 09:05:32 +00:00
fluid_profile ( FLUID_PROF_WRITE , prof_ref ) ;
2003-03-11 16:56:45 +00:00
time = fluid_utime ( ) - time ;
2009-09-25 00:56:48 +00:00
cpu_load = 0.5 * ( synth - > cpu_load + time * synth - > sample_rate / len / 10000.0 ) ;
fluid_atomic_float_set ( & synth - > cpu_load , cpu_load ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
if ( ! synth - > eventhandler - > is_threadsafe )
fluid_synth_api_exit ( synth ) ;
2003-03-11 16:56:45 +00:00
return 0 ;
}
2009-09-22 07:04:07 +00:00
/**
* Converts stereo floating point sample data to signed 16 bit data with dithering .
* @ param dither_index Pointer to an integer which should be initialized to 0
* before the first call and passed unmodified to additional calls which are
* part of the same synthesis output .
* @ param len Length in frames to convert
* @ param lin Buffer of left audio samples to convert from
* @ param rin Buffer of right audio samples to convert from
* @ param lout Array of 16 bit words to store left channel of audio
* @ param loff Offset index in ' lout ' for first sample
* @ param lincr Increment between samples stored to ' lout '
* @ param rout Array of 16 bit words to store right channel of audio
* @ param roff Offset index in ' rout ' for first sample
* @ param rincr Increment between samples stored to ' rout '
*
2017-08-13 13:16:55 +00:00
* @ note Currently private to libfluidsynth .
2006-11-21 20:04:31 +00:00
*/
void
2007-09-20 07:47:38 +00:00
fluid_synth_dither_s16 ( int * dither_index , int len , float * lin , float * rin ,
2006-11-21 20:04:31 +00:00
void * lout , int loff , int lincr ,
void * rout , int roff , int rincr )
{
int i , j , k ;
signed short * left_out = ( signed short * ) lout ;
signed short * right_out = ( signed short * ) rout ;
fluid_real_t left_sample ;
fluid_real_t right_sample ;
2007-09-20 07:47:38 +00:00
int di = * dither_index ;
2009-10-07 05:20:55 +00:00
fluid_profile_ref_var ( prof_ref ) ;
2006-11-21 20:04:31 +00:00
for ( i = 0 , j = loff , k = roff ; i < len ; i + + , j + = lincr , k + = rincr ) {
2007-01-14 17:48:51 +00:00
left_sample = roundi ( lin [ i ] * 32766.0f + rand_table [ 0 ] [ di ] ) ;
right_sample = roundi ( rin [ i ] * 32766.0f + rand_table [ 1 ] [ di ] ) ;
2006-11-21 20:04:31 +00:00
di + + ;
if ( di > = DITHER_SIZE ) di = 0 ;
/* digital clipping */
if ( left_sample > 32767.0f ) left_sample = 32767.0f ;
if ( left_sample < - 32768.0f ) left_sample = - 32768.0f ;
if ( right_sample > 32767.0f ) right_sample = 32767.0f ;
if ( right_sample < - 32768.0f ) right_sample = - 32768.0f ;
left_out [ j ] = ( signed short ) left_sample ;
right_out [ k ] = ( signed short ) right_sample ;
}
2007-03-04 16:45:05 +00:00
2007-09-20 07:47:38 +00:00
* dither_index = di ; /* keep dither buffer continous */
2006-11-21 20:04:31 +00:00
2010-07-04 09:05:32 +00:00
fluid_profile ( FLUID_PROF_WRITE , prof_ref ) ;
2006-11-21 20:04:31 +00:00
}
2003-03-11 16:56:45 +00:00
2010-06-28 20:03:12 +00:00
static void
fluid_synth_check_finished_voices ( fluid_synth_t * synth )
{
int j ;
fluid_rvoice_t * fv ;
while ( NULL ! = ( fv = fluid_rvoice_eventhandler_get_finished_voice ( synth - > eventhandler ) ) ) {
2011-03-27 13:54:52 +00:00
for ( j = 0 ; j < synth - > polyphony ; j + + ) {
2010-06-28 20:03:12 +00:00
if ( synth - > voice [ j ] - > rvoice = = fv ) {
fluid_voice_unlock_rvoice ( synth - > voice [ j ] ) ;
2017-07-01 15:57:43 +00:00
fluid_voice_stop ( synth - > voice [ j ] ) ;
2011-03-27 13:54:52 +00:00
break ;
2010-06-28 20:03:12 +00:00
}
2011-03-27 13:54:52 +00:00
else if ( synth - > voice [ j ] - > overflow_rvoice = = fv ) {
fluid_voice_overflow_rvoice_finished ( synth - > voice [ j ] ) ;
break ;
}
}
2010-06-28 20:03:12 +00:00
}
}
2011-02-07 07:30:50 +00:00
/**
* Process all waiting events in the rvoice queue .
* Make sure no ( other ) rendering is running in parallel when
* you call this function !
*/
void fluid_synth_process_event_queue ( fluid_synth_t * synth )
{
fluid_rvoice_eventhandler_dispatch_all ( synth - > eventhandler ) ;
}
2010-07-03 12:25:43 +00:00
/**
* Process blocks ( FLUID_BUFSIZE ) of audio .
* Must be called from renderer thread only !
* @ return number of blocks rendered . Might ( often ) return less than requested
2003-03-11 16:56:45 +00:00
*/
2009-06-07 05:16:47 +00:00
static int
2010-07-03 12:25:43 +00:00
fluid_synth_render_blocks ( fluid_synth_t * synth , int blockcount )
2003-03-11 16:56:45 +00:00
{
2017-08-19 20:01:47 +00:00
int i , maxblocks ;
2009-10-07 05:20:55 +00:00
fluid_profile_ref_var ( prof_ref ) ;
2004-03-29 10:05:18 +00:00
2009-11-15 02:34:24 +00:00
/* Assign ID of synthesis thread */
2010-07-03 12:25:43 +00:00
// synth->synth_thread_id = fluid_thread_get_id ();
2007-03-04 16:45:05 +00:00
fluid_check_fpe ( " ??? Just starting up ??? " ) ;
2010-07-03 12:25:43 +00:00
fluid_rvoice_eventhandler_dispatch_all ( synth - > eventhandler ) ;
2017-08-19 20:01:47 +00:00
/* do not render more blocks than we can store internally */
maxblocks = fluid_rvoice_mixer_get_bufcount ( synth - > eventhandler - > mixer ) ;
if ( blockcount > maxblocks )
blockcount = maxblocks ;
2010-07-03 12:25:43 +00:00
for ( i = 0 ; i < blockcount ; i + + ) {
fluid_sample_timer_process ( synth ) ;
2010-07-31 20:50:47 +00:00
fluid_synth_add_ticks ( synth , FLUID_BUFSIZE ) ;
2017-08-18 15:53:12 +00:00
/* If events have been queued waiting for fluid_rvoice_eventhandler_dispatch_all()
2017-08-19 20:01:47 +00:00
* ( should only happen with parallel render ) stop processing and go for rendering
2017-08-18 15:53:12 +00:00
*/
2010-07-03 12:25:43 +00:00
if ( fluid_rvoice_eventhandler_dispatch_count ( synth - > eventhandler ) ) {
// Something has happened, we can't process more
blockcount = i + 1 ;
break ;
}
}
2009-06-07 08:10:09 +00:00
fluid_check_fpe ( " fluid_sample_timer_process " ) ;
2010-07-03 12:25:43 +00:00
blockcount = fluid_rvoice_mixer_render ( synth - > eventhandler - > mixer , blockcount ) ;
2003-03-11 16:56:45 +00:00
/* Testcase, that provokes a denormal floating point error */
#if 0
{ float num = 1 ; while ( num ! = 0 ) { num * = 0.5 ; } ; } ;
# endif
fluid_check_fpe ( " ??? Remainder of synth_one_block ??? " ) ;
2010-07-04 09:05:32 +00:00
fluid_profile ( FLUID_PROF_ONE_BLOCK , prof_ref ) ;
2010-07-03 12:25:43 +00:00
return blockcount ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
2010-07-31 20:50:47 +00:00
static int fluid_synth_update_overflow ( fluid_synth_t * synth , char * name ,
fluid_real_t value )
{
2010-08-08 06:45:10 +00:00
double d ;
2010-07-31 20:50:47 +00:00
fluid_synth_api_enter ( synth ) ;
2010-08-08 06:45:10 +00:00
fluid_settings_getnum ( synth - > settings , " synth.overflow.percussion " , & d ) ;
synth - > overflow . percussion = d ;
fluid_settings_getnum ( synth - > settings , " synth.overflow.released " , & d ) ;
synth - > overflow . released = d ;
fluid_settings_getnum ( synth - > settings , " synth.overflow.sustained " , & d ) ;
synth - > overflow . sustained = d ;
fluid_settings_getnum ( synth - > settings , " synth.overflow.volume " , & d ) ;
synth - > overflow . volume = d ;
fluid_settings_getnum ( synth - > settings , " synth.overflow.age " , & d ) ;
synth - > overflow . age = d ;
2010-07-31 20:50:47 +00:00
FLUID_API_RETURN ( 0 ) ;
}
2009-09-22 07:04:07 +00:00
/* Selects a voice for killing. */
2009-06-07 05:16:47 +00:00
static fluid_voice_t *
2009-09-22 07:04:07 +00:00
fluid_synth_free_voice_by_kill_LOCAL ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
int i ;
2011-03-27 13:54:52 +00:00
fluid_real_t best_prio = OVERFLOW_PRIO_CANNOT_KILL - 1 ;
2003-03-11 16:56:45 +00:00
fluid_real_t this_voice_prio ;
fluid_voice_t * voice ;
int best_voice_index = - 1 ;
2010-07-31 20:50:47 +00:00
unsigned int ticks = fluid_synth_get_ticks ( synth ) ;
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
/* safeguard against an available voice. */
2004-05-05 20:27:22 +00:00
if ( _AVAILABLE ( voice ) ) {
2003-03-11 16:56:45 +00:00
return voice ;
2004-05-05 20:27:22 +00:00
}
2010-07-31 20:50:47 +00:00
this_voice_prio = fluid_voice_get_overflow_prio ( voice , & synth - > overflow ,
ticks ) ;
2003-03-11 16:56:45 +00:00
/* check if this voice has less priority than the previous candidate. */
2010-07-31 20:50:47 +00:00
if ( this_voice_prio < best_prio ) {
best_voice_index = i ;
2003-03-11 16:56:45 +00:00
best_prio = this_voice_prio ;
2010-07-31 20:50:47 +00:00
}
2003-03-11 16:56:45 +00:00
}
2004-05-05 20:27:22 +00:00
if ( best_voice_index < 0 ) {
2003-03-11 16:56:45 +00:00
return NULL ;
2004-05-05 20:27:22 +00:00
}
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ best_voice_index ] ;
2010-07-31 20:50:47 +00:00
FLUID_LOG ( FLUID_DBG , " Killing voice %d, index %d, chan %d, key %d " ,
2017-09-02 22:22:07 +00:00
fluid_voice_get_id ( voice ) , best_voice_index , fluid_voice_get_channel ( voice ) , fluid_voice_get_key ( voice ) ) ;
2004-05-05 20:27:22 +00:00
fluid_voice_off ( voice ) ;
2003-03-11 16:56:45 +00:00
return voice ;
}
2010-06-28 20:03:12 +00:00
2009-09-22 07:04:07 +00:00
/**
* Allocate a synthesis voice .
* @ param synth FluidSynth instance
* @ param sample Sample to assign to the voice
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param key MIDI note number for the voice ( 0 - 127 )
* @ param vel MIDI velocity for the voice ( 0 - 127 )
* @ return Allocated synthesis voice or NULL on error
*
* This function is called by a SoundFont ' s preset in response to a noteon event .
* The returned voice comes with default modulators and generators .
* A single noteon event may create any number of voices , when the preset is layered .
*
2017-08-13 13:16:55 +00:00
* @ note Should only be called from within synthesis thread , which includes
2009-09-22 07:04:07 +00:00
* SoundFont loader preset noteon method .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
fluid_voice_t *
2003-03-11 16:56:45 +00:00
fluid_synth_alloc_voice ( fluid_synth_t * synth , fluid_sample_t * sample , int chan , int key , int vel )
{
int i , k ;
fluid_voice_t * voice = NULL ;
2004-05-05 20:27:22 +00:00
fluid_channel_t * channel = NULL ;
2017-09-07 08:45:46 +00:00
fluid_mod_t * default_mod ;
2010-07-31 20:50:47 +00:00
unsigned int ticks ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( sample ! = NULL , NULL ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( NULL ) ;
2010-06-28 20:03:12 +00:00
2003-03-11 16:56:45 +00:00
/* check if there's an available synthesis process */
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
if ( _AVAILABLE ( synth - > voice [ i ] ) ) {
voice = synth - > voice [ i ] ;
break ;
}
}
/* No success yet? Then stop a running voice. */
if ( voice = = NULL ) {
2010-06-28 20:03:12 +00:00
FLUID_LOG ( FLUID_DBG , " Polyphony exceeded, trying to kill a voice " ) ;
2009-09-22 07:04:07 +00:00
voice = fluid_synth_free_voice_by_kill_LOCAL ( synth ) ;
2003-03-11 16:56:45 +00:00
}
if ( voice = = NULL ) {
FLUID_LOG ( FLUID_WARN , " Failed to allocate a synthesis process. (chan=%d,key=%d) " , chan , key ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( NULL ) ;
2007-03-04 16:45:05 +00:00
}
2010-07-31 20:50:47 +00:00
ticks = fluid_synth_get_ticks ( synth ) ;
2003-03-11 16:56:45 +00:00
if ( synth - > verbose ) {
k = 0 ;
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
if ( ! _AVAILABLE ( synth - > voice [ i ] ) ) {
k + + ;
}
}
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_INFO , " noteon \t %d \t %d \t %d \t %05d \t %.3f \t %.3f \t %.3f \t %d " ,
chan , key , vel , synth - > storeid ,
2010-07-31 20:50:47 +00:00
( float ) ticks / 44100.0f ,
2003-03-11 16:56:45 +00:00
( fluid_curtime ( ) - synth - > start ) / 1000.0f ,
0.0f ,
k ) ;
}
2004-05-05 20:27:22 +00:00
if ( chan > = 0 ) {
channel = synth - > channel [ chan ] ;
}
2009-11-15 02:34:24 +00:00
if ( fluid_voice_init ( voice , sample , channel , key , vel ,
2010-10-17 10:20:57 +00:00
synth - > storeid , ticks , synth - > gain ) ! = FLUID_OK ) {
2003-03-11 16:56:45 +00:00
FLUID_LOG ( FLUID_WARN , " Failed to initialize voice " ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( NULL ) ;
2003-03-11 16:56:45 +00:00
}
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
/* add the default modulators to the synthesis process. */
2017-09-07 08:45:46 +00:00
default_mod = synth - > default_mod ;
while ( default_mod ! = NULL ) {
fluid_voice_add_mod ( voice , default_mod , FLUID_VOICE_DEFAULT ) ;
default_mod = default_mod - > next ;
}
2007-03-04 16:45:05 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( voice ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/* Kill all voices on a given channel, which have the same exclusive class
* generator as new_voice .
2003-03-11 16:56:45 +00:00
*/
2009-06-07 05:16:47 +00:00
static void
2009-09-22 07:04:07 +00:00
fluid_synth_kill_by_exclusive_class_LOCAL ( fluid_synth_t * synth ,
fluid_voice_t * new_voice )
{
2003-03-11 16:56:45 +00:00
int excl_class = _GEN ( new_voice , GEN_EXCLUSIVECLASS ) ;
2009-09-22 07:04:07 +00:00
fluid_voice_t * existing_voice ;
int i ;
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
/* Excl. class 0: No exclusive class */
2009-09-22 07:04:07 +00:00
if ( excl_class = = 0 ) return ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
/* Kill all notes on the same channel with the same exclusive class */
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2009-09-22 07:04:07 +00:00
existing_voice = synth - > voice [ i ] ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
/* If voice is playing, on the same channel, has same exclusive
* class and is not part of the same noteon event ( voice group ) , then kill it */
2007-03-04 16:45:05 +00:00
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_playing ( existing_voice )
2017-09-02 22:22:07 +00:00
& & fluid_voice_get_channel ( existing_voice ) = = fluid_voice_get_channel ( new_voice )
2009-09-22 07:04:07 +00:00
& & ( int ) _GEN ( existing_voice , GEN_EXCLUSIVECLASS ) = = excl_class
& & fluid_voice_get_id ( existing_voice ) ! = fluid_voice_get_id ( new_voice ) )
fluid_voice_kill_excl ( existing_voice ) ;
}
}
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/**
* Activate a voice previously allocated with fluid_synth_alloc_voice ( ) .
* @ param synth FluidSynth instance
* @ param voice Voice to activate
*
* This function is called by a SoundFont ' s preset in response to a noteon
* event . Exclusive classes are processed here .
*
2017-08-13 13:16:55 +00:00
* @ note Should only be called from within synthesis thread , which includes
2009-09-22 07:04:07 +00:00
* SoundFont loader preset noteon method .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
void
fluid_synth_start_voice ( fluid_synth_t * synth , fluid_voice_t * voice )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_if_fail ( synth ! = NULL ) ;
fluid_return_if_fail ( voice ! = NULL ) ;
2010-07-01 11:14:55 +00:00
// fluid_return_if_fail (fluid_synth_is_synth_thread (synth));
fluid_synth_api_enter ( synth ) ;
2003-05-29 15:43:52 +00:00
2003-03-11 16:56:45 +00:00
/* Find the exclusive class of this voice. If set, kill all voices
* that match the exclusive class and are younger than the first
* voice process created by this noteon event . */
2009-09-22 07:04:07 +00:00
fluid_synth_kill_by_exclusive_class_LOCAL ( synth , voice ) ;
2003-05-29 15:43:52 +00:00
2009-09-22 07:04:07 +00:00
fluid_voice_start ( voice ) ; /* Start the new voice */
2010-06-28 20:03:12 +00:00
if ( synth - > eventhandler - > is_threadsafe )
fluid_voice_lock_rvoice ( voice ) ;
fluid_rvoice_eventhandler_add_rvoice ( synth - > eventhandler , voice - > rvoice ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Add a SoundFont loader interface .
* @ param synth FluidSynth instance
* @ param loader Loader API structure , used directly and should remain allocated
* as long as the synth instance is used .
*
* SoundFont loaders are used to add custom instrument loading to FluidSynth .
* The caller supplied functions for loading files , allocating presets ,
* retrieving information on them and synthesizing note - on events . Using this
* method even non SoundFont instruments can be synthesized , although limited
* to the SoundFont synthesis model .
*
2017-08-13 13:16:55 +00:00
* @ note Should only be called before any SoundFont files are loaded .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
void
fluid_synth_add_sfloader ( fluid_synth_t * synth , fluid_sfloader_t * loader )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
gboolean sfont_already_loaded ;
fluid_return_if_fail ( synth ! = NULL ) ;
fluid_return_if_fail ( loader ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
sfont_already_loaded = synth - > sfont_info ! = NULL ;
2010-07-01 11:14:55 +00:00
if ( ! sfont_already_loaded )
synth - > loaders = fluid_list_prepend ( synth - > loaders , loader ) ;
fluid_synth_api_exit ( synth ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Load a SoundFont file ( filename is interpreted by SoundFont loaders ) .
* The newly loaded SoundFont will be put on top of the SoundFont
* stack . Presets are searched starting from the SoundFont on the
* top of the stack , working the way down the stack until a preset is found .
*
* @ param synth SoundFont instance
* @ param filename File to load
* @ param reset_presets TRUE to re - assign presets for all MIDI channels
* @ return SoundFont ID on success , FLUID_FAILED on error
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_sfload ( fluid_synth_t * synth , const char * filename , int reset_presets )
{
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
fluid_sfont_t * sfont ;
fluid_list_t * list ;
fluid_sfloader_t * loader ;
unsigned int sfont_id ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( filename ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
/* MT NOTE: Loaders list should not change. */
2003-03-11 16:56:45 +00:00
for ( list = synth - > loaders ; list ; list = fluid_list_next ( list ) ) {
loader = ( fluid_sfloader_t * ) fluid_list_get ( list ) ;
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
sfont = fluid_sfloader_load ( loader , filename ) ;
if ( sfont ! = NULL ) {
2009-09-22 07:04:07 +00:00
sfont_info = new_fluid_sfont_info ( synth , sfont ) ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
if ( ! sfont_info )
{
2013-08-09 14:43:30 +00:00
delete_fluid_sfont ( sfont ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
}
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
sfont - > id = sfont_id = + + synth - > sfont_id ;
synth - > sfont_info = fluid_list_prepend ( synth - > sfont_info , sfont_info ) ; /* prepend to list */
fluid_hashtable_insert ( synth - > sfont_hash , sfont , sfont_info ) ; /* Hash sfont->sfont_info */
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/* reset the presets for all channels if requested */
if ( reset_presets ) fluid_synth_program_reset ( synth ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( ( int ) sfont_id ) ;
2003-03-11 16:56:45 +00:00
}
}
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR , " Failed to load SoundFont \" %s \" " , filename ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/* Create a new SoundFont info structure, free with FLUID_FREE */
static fluid_sfont_info_t *
new_fluid_sfont_info ( fluid_synth_t * synth , fluid_sfont_t * sfont )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
sfont_info = FLUID_NEW ( fluid_sfont_info_t ) ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
if ( ! sfont_info )
{
FLUID_LOG ( FLUID_ERR , " Out of memory " ) ;
return NULL ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
sfont_info - > sfont = sfont ;
sfont_info - > synth = synth ;
sfont_info - > refcount = 1 ; /* Start with refcount of 1 for owning synth */
sfont_info - > bankofs = 0 ;
return ( sfont_info ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Unload a SoundFont .
* @ param synth SoundFont instance
* @ param id ID of SoundFont to unload
* @ param reset_presets TRUE to re - assign presets for all MIDI channels
* @ return FLUID_OK on success , FLUID_FAILED on error
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_sfunload ( fluid_synth_t * synth , unsigned int id , int reset_presets )
{
2009-10-12 19:18:06 +00:00
fluid_sfont_info_t * sfont_info = NULL ;
2009-09-22 07:04:07 +00:00
fluid_list_t * list ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
/* remove the SoundFont from the list */
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
if ( fluid_sfont_get_id ( sfont_info - > sfont ) = = id )
{
synth - > sfont_info = fluid_list_remove ( synth - > sfont_info , sfont_info ) ;
break ;
}
}
if ( ! list ) {
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR , " No SoundFont with id = %d " , id ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/* reset the presets for all channels (SoundFont will be freed when there are no more references) */
if ( reset_presets ) fluid_synth_program_reset ( synth ) ;
else fluid_synth_update_presets ( synth ) ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/* -- Remove synth->sfont_info list's reference to SoundFont */
fluid_synth_sfont_unref ( synth , sfont_info - > sfont ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2009-09-22 07:04:07 +00:00
}
/* Unref a SoundFont and destroy if no more references */
2010-07-14 08:44:51 +00:00
void
2009-09-22 07:04:07 +00:00
fluid_synth_sfont_unref ( fluid_synth_t * synth , fluid_sfont_t * sfont )
{
fluid_sfont_info_t * sfont_info ;
int refcount = 0 ;
sfont_info = fluid_hashtable_lookup ( synth - > sfont_hash , sfont ) ;
if ( sfont_info )
{
sfont_info - > refcount - - ; /* -- Remove the sfont_info list's reference */
refcount = sfont_info - > refcount ;
if ( refcount = = 0 ) /* Remove SoundFont from hash if no more references */
fluid_hashtable_remove ( synth - > sfont_hash , sfont_info - > sfont ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
fluid_return_if_fail ( sfont_info ! = NULL ) ; /* Shouldn't happen, programming error if so */
if ( refcount = = 0 ) /* No more references? - Attempt delete */
{
if ( delete_fluid_sfont ( sfont_info - > sfont ) = = 0 ) /* SoundFont loader can block SoundFont unload */
{
FLUID_FREE ( sfont_info ) ;
FLUID_LOG ( FLUID_DBG , " Unloaded SoundFont " ) ;
} /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */
else new_fluid_timer ( 100 , fluid_synth_sfunload_callback , sfont_info , TRUE , TRUE , FALSE ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
}
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
/* Callback to continually attempt to unload a SoundFont,
* only if a SoundFont loader blocked the unload operation */
static int
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 )
{
FLUID_FREE ( sfont_info ) ;
FLUID_LOG ( FLUID_DBG , " Unloaded SoundFont " ) ;
return FALSE ;
}
else return TRUE ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Reload a SoundFont . The SoundFont retains its ID and index on the SoundFont stack .
* @ param synth SoundFont instance
* @ param id ID of SoundFont to reload
* @ return SoundFont ID on success , FLUID_FAILED on error
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_sfreload ( fluid_synth_t * synth , unsigned int id )
2003-03-11 16:56:45 +00:00
{
char filename [ 1024 ] ;
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info , * old_sfont_info ;
2003-03-11 16:56:45 +00:00
fluid_sfont_t * sfont ;
fluid_sfloader_t * loader ;
2009-09-22 07:04:07 +00:00
fluid_list_t * list ;
int index ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
/* Search for SoundFont and get its index */
for ( list = synth - > sfont_info , index = 0 ; list ; list = fluid_list_next ( list ) , index + + ) {
old_sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
if ( fluid_sfont_get_id ( old_sfont_info - > sfont ) = = id ) break ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
if ( ! list ) {
FLUID_LOG ( FLUID_ERR , " No SoundFont with id = %d " , id ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
}
/* keep a copy of the SoundFont's filename */
2009-09-22 07:04:07 +00:00
FLUID_STRCPY ( filename , fluid_sfont_get_name ( old_sfont_info - > sfont ) ) ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
if ( fluid_synth_sfunload ( synth , id , FALSE ) ! = FLUID_OK )
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
/* MT Note: SoundFont loader list will not change */
2003-03-11 16:56:45 +00:00
for ( list = synth - > loaders ; list ; list = fluid_list_next ( list ) ) {
loader = ( fluid_sfloader_t * ) fluid_list_get ( list ) ;
2007-03-04 16:45:05 +00:00
2003-03-11 16:56:45 +00:00
sfont = fluid_sfloader_load ( loader , filename ) ;
if ( sfont ! = NULL ) {
sfont - > id = id ;
2009-09-22 07:04:07 +00:00
sfont_info = new_fluid_sfont_info ( synth , sfont ) ;
if ( ! sfont_info )
{
2013-08-09 14:43:30 +00:00
delete_fluid_sfont ( sfont ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
}
synth - > sfont_info = fluid_list_insert_at ( synth - > sfont_info , index , sfont_info ) ; /* insert the sfont at the same index */
fluid_hashtable_insert ( synth - > sfont_hash , sfont , sfont_info ) ; /* Hash sfont->sfont_info */
2003-03-11 16:56:45 +00:00
/* reset the presets for all channels */
fluid_synth_update_presets ( synth ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( sfont - > id ) ;
2003-03-11 16:56:45 +00:00
}
}
2007-03-04 16:45:05 +00:00
FLUID_LOG ( FLUID_ERR , " Failed to load SoundFont \" %s \" " , filename ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Add a SoundFont . The SoundFont will be added to the top of the SoundFont stack .
* @ param synth FluidSynth instance
* @ param sfont SoundFont to add
* @ return New assigned SoundFont ID or FLUID_FAILED on error
2004-05-07 09:53:39 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_add_sfont ( fluid_synth_t * synth , fluid_sfont_t * sfont )
2004-05-07 09:53:39 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
unsigned int sfont_id ;
2004-05-07 09:53:39 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( sfont ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
sfont_info = new_fluid_sfont_info ( synth , sfont ) ;
2010-07-01 11:14:55 +00:00
if ( ! sfont_info )
FLUID_API_RETURN ( FLUID_FAILED ) ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
sfont - > id = sfont_id = + + synth - > sfont_id ;
synth - > sfont_info = fluid_list_prepend ( synth - > sfont_info , sfont_info ) ; /* prepend to list */
fluid_hashtable_insert ( synth - > sfont_hash , sfont , sfont_info ) ; /* Hash sfont->sfont_info */
2004-05-07 09:53:39 +00:00
2009-09-22 07:04:07 +00:00
/* reset the presets for all channels */
fluid_synth_program_reset ( synth ) ;
2004-05-07 09:53:39 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( sfont_id ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Remove a SoundFont from the SoundFont stack without deleting it .
* @ param synth FluidSynth instance
* @ param sfont SoundFont to remove
*
* SoundFont is not freed and is left as the responsibility of the caller .
*
2017-08-13 13:16:55 +00:00
* @ note The SoundFont should only be freed after there are no presets
2009-09-22 07:04:07 +00:00
* referencing it . This can only be ensured by the SoundFont loader and
* therefore this function should not normally be used .
2004-05-07 09:53:39 +00:00
*/
2009-09-22 07:04:07 +00:00
void
fluid_synth_remove_sfont ( fluid_synth_t * synth , fluid_sfont_t * sfont )
2004-05-07 09:53:39 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
fluid_list_t * list ;
fluid_return_if_fail ( synth ! = NULL ) ;
fluid_return_if_fail ( sfont ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
/* remove the SoundFont from the list */
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
if ( sfont_info - > sfont = = sfont )
{
synth - > sfont_info = fluid_list_remove ( synth - > sfont_info , sfont_info ) ;
/* Remove from SoundFont hash regardless of refcount (SoundFont delete is up to caller) */
fluid_hashtable_remove ( synth - > sfont_hash , sfont_info - > sfont ) ;
break ;
}
}
2004-05-07 09:53:39 +00:00
2009-09-22 07:04:07 +00:00
/* reset the presets for all channels */
fluid_synth_program_reset ( synth ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2009-09-22 07:04:07 +00:00
}
2009-10-28 19:38:10 +00:00
/**
2009-09-22 07:04:07 +00:00
* Count number of loaded SoundFont files .
* @ param synth FluidSynth instance
* @ return Count of loaded SoundFont files .
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_sfcount ( fluid_synth_t * synth )
{
2009-09-22 07:04:07 +00:00
int count ;
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
count = fluid_list_size ( synth - > sfont_info ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( count ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get SoundFont by index .
* @ param synth FluidSynth instance
* @ param num SoundFont index on the stack ( starting from 0 for top of stack ) .
* @ return SoundFont instance or NULL if invalid index
2003-03-11 16:56:45 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Caller should be certain that SoundFont is not deleted ( unloaded ) for
2009-09-22 07:04:07 +00:00
* the duration of use of the returned pointer .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
fluid_sfont_t *
2003-03-11 16:56:45 +00:00
fluid_synth_get_sfont ( fluid_synth_t * synth , unsigned int num )
{
2009-09-22 07:04:07 +00:00
fluid_sfont_t * sfont = NULL ;
fluid_list_t * list ;
fluid_return_val_if_fail ( synth ! = NULL , NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
list = fluid_list_nth ( synth - > sfont_info , num ) ;
if ( list ) sfont = ( ( fluid_sfont_info_t * ) fluid_list_get ( list ) ) - > sfont ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( sfont ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get SoundFont by ID .
* @ param synth FluidSynth instance
* @ param id SoundFont ID
* @ return SoundFont instance or NULL if invalid ID
2003-03-11 16:56:45 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Caller should be certain that SoundFont is not deleted ( unloaded ) for
2009-09-22 07:04:07 +00:00
* the duration of use of the returned pointer .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
fluid_sfont_t *
fluid_synth_get_sfont_by_id ( fluid_synth_t * synth , unsigned int id )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_sfont_t * sfont = NULL ;
fluid_list_t * list ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont = ( ( fluid_sfont_info_t * ) fluid_list_get ( list ) ) - > sfont ;
if ( fluid_sfont_get_id ( sfont ) = = id )
break ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( list ? sfont : NULL ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get SoundFont by name .
* @ param synth FluidSynth instance
* @ param name Name of SoundFont
* @ return SoundFont instance or NULL if invalid name
2009-10-23 02:18:26 +00:00
* @ since 1.1 .0
2004-02-28 13:20:07 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Caller should be certain that SoundFont is not deleted ( unloaded ) for
2009-09-22 07:04:07 +00:00
* the duration of use of the returned pointer .
2004-02-28 13:20:07 +00:00
*/
2009-09-22 07:04:07 +00:00
fluid_sfont_t *
2009-10-28 19:38:10 +00:00
fluid_synth_get_sfont_by_name ( fluid_synth_t * synth , const char * name )
2004-02-28 13:20:07 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_sfont_t * sfont = NULL ;
fluid_list_t * list ;
2004-02-28 13:20:07 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , NULL ) ;
fluid_return_val_if_fail ( name ! = NULL , NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont = ( ( fluid_sfont_info_t * ) fluid_list_get ( list ) ) - > sfont ;
if ( FLUID_STRCMP ( fluid_sfont_get_name ( sfont ) , name ) = = 0 )
break ;
2004-02-28 13:20:07 +00:00
}
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( list ? sfont : NULL ) ;
2004-02-28 13:20:07 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get active preset on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ return Preset or NULL if no preset active on channel
2009-11-27 22:28:23 +00:00
* @ deprecated fluid_synth_get_channel_info ( ) should replace most use cases .
2009-09-22 07:04:07 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Should only be called from within synthesis thread , which includes
2009-11-16 07:43:43 +00:00
* SoundFont loader preset noteon methods . Not thread safe otherwise .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
fluid_preset_t *
2003-03-11 16:56:45 +00:00
fluid_synth_get_channel_preset ( fluid_synth_t * synth , int chan )
{
2010-07-01 11:14:55 +00:00
fluid_preset_t * result ;
2009-11-16 07:43:43 +00:00
fluid_channel_t * channel ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( NULL ) ;
2007-03-04 16:45:05 +00:00
2009-11-16 07:43:43 +00:00
channel = synth - > channel [ chan ] ;
2010-10-17 10:20:57 +00:00
result = channel - > preset ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
return result ;
2009-11-16 07:43:43 +00:00
}
/**
2009-11-27 22:28:23 +00:00
* Get information on the currently selected preset on a MIDI channel .
2009-11-16 07:43:43 +00:00
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param info Caller supplied structure to fill with preset information
* @ return # FLUID_OK on success , # FLUID_FAILED otherwise
* @ since 1.1 .1
*/
int
2009-11-27 22:28:23 +00:00
fluid_synth_get_channel_info ( fluid_synth_t * synth , int chan ,
fluid_synth_channel_info_t * info )
2009-11-16 07:43:43 +00:00
{
fluid_channel_t * channel ;
fluid_preset_t * preset ;
char * name ;
if ( info )
{
info - > assigned = FALSE ;
info - > name [ 0 ] = ' \0 ' ;
}
fluid_return_val_if_fail ( info ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-11-16 07:43:43 +00:00
channel = synth - > channel [ chan ] ;
2010-10-17 10:20:57 +00:00
preset = channel - > preset ;
2009-11-16 07:43:43 +00:00
if ( preset )
{
info - > assigned = TRUE ;
name = fluid_preset_get_name ( preset ) ;
if ( name )
{
2009-11-27 22:28:23 +00:00
strncpy ( info - > name , name , FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE ) ;
info - > name [ FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE - 1 ] = ' \0 ' ;
2009-11-16 07:43:43 +00:00
}
else info - > name [ 0 ] = ' \0 ' ;
info - > sfont_id = preset - > sfont - > id ;
info - > bank = fluid_preset_get_banknum ( preset ) ;
info - > program = fluid_preset_get_num ( preset ) ;
}
else
{
info - > assigned = FALSE ;
fluid_channel_get_sfont_bank_prog ( channel , & info - > sfont_id , & info - > bank , & info - > program ) ;
info - > name [ 0 ] = ' \0 ' ;
}
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2009-11-16 07:43:43 +00:00
return FLUID_OK ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
2017-08-13 13:08:22 +00:00
* Get list of currently playing voices .
2009-09-22 07:04:07 +00:00
* @ param synth FluidSynth instance
* @ param buf Array to store voices to ( NULL terminated if not filled completely )
* @ param bufsize Count of indexes in buf
* @ param id Voice ID to search for or < 0 to return list of all playing voices
*
2017-08-13 13:16:55 +00:00
* @ note Should only be called from within synthesis thread , which includes
2009-09-22 07:04:07 +00:00
* SoundFont loader preset noteon methods . Voices are only guaranteed to remain
* unchanged until next synthesis process iteration .
2003-03-11 16:56:45 +00:00
*/
void
2009-09-22 07:04:07 +00:00
fluid_synth_get_voicelist ( fluid_synth_t * synth , fluid_voice_t * buf [ ] , int bufsize ,
int id )
2003-03-11 16:56:45 +00:00
{
int count = 0 ;
2009-09-22 07:04:07 +00:00
int i ;
fluid_return_if_fail ( synth ! = NULL ) ;
fluid_return_if_fail ( buf ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
for ( i = 0 ; i < synth - > polyphony & & count < bufsize ; i + + ) {
2003-03-11 16:56:45 +00:00
fluid_voice_t * voice = synth - > voice [ i ] ;
2007-03-04 16:45:05 +00:00
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_playing ( voice ) & & ( id < 0 | | ( int ) voice - > id = = id ) )
2003-03-11 16:56:45 +00:00
buf [ count + + ] = voice ;
2009-09-22 07:04:07 +00:00
}
if ( count < bufsize ) buf [ count ] = NULL ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Enable or disable reverb effect .
* @ param synth FluidSynth instance
* @ param on TRUE to enable reverb , FALSE to disable
*/
void
fluid_synth_set_reverb_on ( fluid_synth_t * synth , int on )
{
fluid_return_if_fail ( synth ! = NULL ) ;
fluid_atomic_int_set ( & synth - > with_reverb , on ! = 0 ) ;
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_set_reverb_enabled ,
on ! = 0 , 0.0f ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Activate a reverb preset .
* @ param synth FluidSynth instance
* @ param num Reverb preset number
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*
2017-08-13 13:16:55 +00:00
* @ note Currently private to libfluidsynth .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_set_reverb_preset ( fluid_synth_t * synth , int num )
{
int i = 0 ;
while ( revmodel_preset [ i ] . name ! = NULL ) {
if ( i = = num ) {
fluid_synth_set_reverb ( synth , revmodel_preset [ i ] . roomsize ,
revmodel_preset [ i ] . damp , revmodel_preset [ i ] . width ,
revmodel_preset [ i ] . level ) ;
return FLUID_OK ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
i + + ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
return FLUID_FAILED ;
}
/**
* Set reverb parameters .
* @ param synth FluidSynth instance
* @ param roomsize Reverb room size value ( 0.0 - 1.2 )
* @ param damping Reverb damping value ( 0.0 - 1.0 )
* @ param width Reverb width value ( 0.0 - 100.0 )
* @ param level Reverb level value ( 0.0 - 1.0 )
2009-12-16 02:48:07 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Not realtime safe and therefore should not be called from synthesis
2009-12-16 02:48:07 +00:00
* context at the risk of stalling audio output .
2009-09-22 07:04:07 +00:00
*/
void
fluid_synth_set_reverb ( fluid_synth_t * synth , double roomsize , double damping ,
double width , double level )
{
fluid_synth_set_reverb_full ( synth , FLUID_REVMODEL_SET_ALL ,
roomsize , damping , width , level ) ;
}
/**
* Set one or more reverb parameters .
* @ param synth FluidSynth instance
* @ param set Flags indicating which parameters should be set ( # fluid_revmodel_set_t )
* @ param roomsize Reverb room size value ( 0.0 - 1.2 )
* @ param damping Reverb damping value ( 0.0 - 1.0 )
* @ param width Reverb width value ( 0.0 - 100.0 )
* @ param level Reverb level value ( 0.0 - 1.0 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-12-16 02:48:07 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Not realtime safe and therefore should not be called from synthesis
2009-12-16 02:48:07 +00:00
* context at the risk of stalling audio output .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_set_reverb_full ( fluid_synth_t * synth , int set , double roomsize ,
double damping , double width , double level )
{
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
if ( ! ( set & FLUID_REVMODEL_SET_ALL ) )
2009-11-05 04:37:51 +00:00
set = FLUID_REVMODEL_SET_ALL ;
2009-12-16 02:48:07 +00:00
/* Synth shadow values are set here so that they will be returned if querried */
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-11-05 04:37:51 +00:00
if ( set & FLUID_REVMODEL_SET_ROOMSIZE )
fluid_atomic_float_set ( & synth - > reverb_roomsize , roomsize ) ;
if ( set & FLUID_REVMODEL_SET_DAMPING )
fluid_atomic_float_set ( & synth - > reverb_damping , damping ) ;
if ( set & FLUID_REVMODEL_SET_WIDTH )
fluid_atomic_float_set ( & synth - > reverb_width , width ) ;
if ( set & FLUID_REVMODEL_SET_LEVEL )
fluid_atomic_float_set ( & synth - > reverb_level , level ) ;
2009-09-22 07:04:07 +00:00
2010-06-30 16:39:20 +00:00
fluid_rvoice_eventhandler_push5 ( synth - > eventhandler ,
fluid_rvoice_mixer_set_reverb_params ,
synth - > eventhandler - > mixer , set ,
roomsize , damping , width , level , 0.0f ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get reverb room size .
* @ param synth FluidSynth instance
* @ return Reverb room size ( 0.0 - 1.2 )
*/
double
fluid_synth_get_reverb_roomsize ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
result = fluid_atomic_float_get ( & synth - > reverb_roomsize ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get reverb damping .
* @ param synth FluidSynth instance
* @ return Reverb damping value ( 0.0 - 1.0 )
*/
double
fluid_synth_get_reverb_damp ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_float_get ( & synth - > reverb_damping ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get reverb level .
* @ param synth FluidSynth instance
* @ return Reverb level value ( 0.0 - 1.0 )
*/
double
fluid_synth_get_reverb_level ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_float_get ( & synth - > reverb_level ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get reverb width .
* @ param synth FluidSynth instance
* @ return Reverb width value ( 0.0 - 100.0 )
*/
double
fluid_synth_get_reverb_width ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_float_get ( & synth - > reverb_width ) ;
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Enable or disable chorus effect .
* @ param synth FluidSynth instance
* @ param on TRUE to enable chorus , FALSE to disable
*/
void
fluid_synth_set_chorus_on ( fluid_synth_t * synth , int on )
{
fluid_return_if_fail ( synth ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
fluid_atomic_int_set ( & synth - > with_chorus , on ! = 0 ) ;
2010-07-14 08:45:38 +00:00
fluid_synth_update_mixer ( synth , fluid_rvoice_mixer_set_chorus_enabled ,
on ! = 0 , 0.0f ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Set chorus parameters .
* @ param synth FluidSynth instance
* @ param nr Chorus voice count ( 0 - 99 , CPU time consumption proportional to
* this value )
2012-12-27 10:07:42 +00:00
* @ param level Chorus level ( 0.0 - 10.0 )
2009-09-22 07:04:07 +00:00
* @ param speed Chorus speed in Hz ( 0.29 - 5.0 )
* @ param depth_ms Chorus depth ( max value depends on synth sample rate ,
* 0.0 - 21.0 is safe for sample rate values up to 96 KHz )
* @ param type Chorus waveform type ( # fluid_chorus_mod )
*/
void
fluid_synth_set_chorus ( fluid_synth_t * synth , int nr , double level ,
double speed , double depth_ms , int type )
{
fluid_synth_set_chorus_full ( synth , FLUID_CHORUS_SET_ALL , nr , level , speed ,
depth_ms , type ) ;
}
/**
* Set one or more chorus parameters .
* @ param synth FluidSynth instance
* @ param set Flags indicating which chorus parameters to set ( # fluid_chorus_set_t )
* @ param nr Chorus voice count ( 0 - 99 , CPU time consumption proportional to
* this value )
2012-12-27 10:07:42 +00:00
* @ param level Chorus level ( 0.0 - 10.0 )
2009-09-22 07:04:07 +00:00
* @ param speed Chorus speed in Hz ( 0.29 - 5.0 )
* @ param depth_ms Chorus depth ( max value depends on synth sample rate ,
* 0.0 - 21.0 is safe for sample rate values up to 96 KHz )
* @ param type Chorus waveform type ( # fluid_chorus_mod )
*/
int
fluid_synth_set_chorus_full ( fluid_synth_t * synth , int set , int nr , double level ,
double speed , double depth_ms , int type )
{
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
if ( ! ( set & FLUID_CHORUS_SET_ALL ) )
set = FLUID_CHORUS_SET_ALL ;
2012-12-27 09:55:09 +00:00
/* Synth shadow values are set here so that they will be returned if queried */
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-11-05 04:37:51 +00:00
if ( set & FLUID_CHORUS_SET_NR )
fluid_atomic_int_set ( & synth - > chorus_nr , nr ) ;
if ( set & FLUID_CHORUS_SET_LEVEL )
fluid_atomic_float_set ( & synth - > chorus_level , level ) ;
if ( set & FLUID_CHORUS_SET_SPEED )
fluid_atomic_float_set ( & synth - > chorus_speed , speed ) ;
if ( set & FLUID_CHORUS_SET_DEPTH )
fluid_atomic_float_set ( & synth - > chorus_depth , depth_ms ) ;
if ( set & FLUID_CHORUS_SET_TYPE )
fluid_atomic_int_set ( & synth - > chorus_type , type ) ;
2010-06-30 16:39:20 +00:00
fluid_rvoice_eventhandler_push5 ( synth - > eventhandler ,
2012-12-27 09:55:09 +00:00
fluid_rvoice_mixer_set_chorus_params ,
synth - > eventhandler - > mixer , set ,
2010-06-30 16:39:20 +00:00
nr , level , speed , depth_ms , type ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get chorus voice number ( delay line count ) value .
* @ param synth FluidSynth instance
* @ return Chorus voice count ( 0 - 99 )
*/
int
fluid_synth_get_chorus_nr ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_int_get ( & synth - > chorus_nr ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get chorus level .
* @ param synth FluidSynth instance
* @ return Chorus level value ( 0.0 - 10.0 )
*/
double
fluid_synth_get_chorus_level ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_float_get ( & synth - > chorus_level ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get chorus speed in Hz .
* @ param synth FluidSynth instance
* @ return Chorus speed in Hz ( 0.29 - 5.0 )
*/
double
fluid_synth_get_chorus_speed_Hz ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_float_get ( & synth - > chorus_speed ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get chorus depth .
* @ param synth FluidSynth instance
* @ return Chorus depth
*/
double
fluid_synth_get_chorus_depth_ms ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_float_get ( & synth - > chorus_depth ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get chorus waveform type .
* @ param synth FluidSynth instance
* @ return Chorus waveform type ( # fluid_chorus_mod )
*/
int
fluid_synth_get_chorus_type ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
double result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0.0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_atomic_int_get ( & synth - > chorus_type ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/*
2003-03-11 16:56:45 +00:00
* If the same note is hit twice on the same channel , then the older
* voice process is advanced to the release stage . Using a mechanical
* MIDI controller , the only way this can happen is when the sustain
* pedal is held . In this case the behaviour implemented here is
* natural for many instruments . Note : One noteon event can trigger
* several voice processes , for example a stereo sample . Don ' t
* release those . . .
*/
2009-06-07 05:16:47 +00:00
static void
2009-09-22 07:04:07 +00:00
fluid_synth_release_voice_on_same_note_LOCAL ( fluid_synth_t * synth , int chan ,
int key )
2009-06-07 05:16:47 +00:00
{
2003-03-11 16:56:45 +00:00
int i ;
fluid_voice_t * voice ;
2004-03-29 10:05:18 +00:00
2015-04-07 11:48:04 +00:00
synth - > storeid = synth - > noteid + + ;
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2003-03-11 16:56:45 +00:00
voice = synth - > voice [ i ] ;
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_playing ( voice )
2017-09-02 22:22:07 +00:00
& & ( fluid_voice_get_channel ( voice ) = = chan )
& & ( fluid_voice_get_key ( voice ) = = key )
2003-03-11 16:56:45 +00:00
& & ( fluid_voice_get_id ( voice ) ! = synth - > noteid ) ) {
2015-04-07 11:48:04 +00:00
/* Id of voices that was sustained by sostenuto */
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_sostenuto ( voice ) )
2017-09-02 22:22:07 +00:00
synth - > storeid = fluid_voice_get_id ( voice ) ;
2015-04-07 11:48:04 +00:00
/* Force the voice into release stage (pedaling is ignored) */
fluid_voice_release ( voice ) ;
2003-03-11 16:56:45 +00:00
}
}
}
2009-09-22 07:04:07 +00:00
/**
* Set synthesis interpolation method on one or all MIDI channels .
* @ param synth FluidSynth instance
* @ param chan MIDI channel to set interpolation method on or - 1 for all channels
* @ param interp_method Interpolation method ( # fluid_interp )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_set_interp_method ( fluid_synth_t * synth , int chan , int interp_method )
{
2003-03-11 16:56:45 +00:00
int i ;
2010-07-14 08:54:40 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
if ( chan < - 1 | | chan > = synth - > midi_channels )
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
if ( synth - > channel [ 0 ] = = NULL ) {
FLUID_LOG ( FLUID_ERR , " Channels don't exist (yet)! " ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
}
2003-03-11 16:56:45 +00:00
for ( i = 0 ; i < synth - > midi_channels ; i + + ) {
2009-09-22 07:04:07 +00:00
if ( chan < 0 | | fluid_channel_get_num ( synth - > channel [ i ] ) = = chan )
2003-03-11 16:56:45 +00:00
fluid_channel_set_interp_method ( synth - > channel [ i ] , interp_method ) ;
2009-09-22 07:04:07 +00:00
}
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
} ;
2009-09-22 07:04:07 +00:00
/**
* Get the total count of MIDI channels .
* @ param synth FluidSynth instance
* @ return Count of MIDI channels
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_count_midi_channels ( fluid_synth_t * synth )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = synth - > midi_channels ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the total count of audio channels .
* @ param synth FluidSynth instance
2009-10-22 07:06:26 +00:00
* @ return Count of audio channel stereo pairs ( 1 = 2 channels , 2 = 4 , etc )
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_count_audio_channels ( fluid_synth_t * synth )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = synth - > audio_channels ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the total number of allocated audio channels . Usually identical to the
2009-10-22 07:06:26 +00:00
* number of audio channels . Can be employed by LADSPA effects subsystem .
2009-09-22 07:04:07 +00:00
*
* @ param synth FluidSynth instance
2009-10-22 07:06:26 +00:00
* @ return Count of audio group stereo pairs ( 1 = 2 channels , 2 = 4 , etc )
2003-03-11 16:56:45 +00:00
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_count_audio_groups ( fluid_synth_t * synth )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = synth - > audio_groups ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the total number of allocated effects channels .
* @ param synth FluidSynth instance
* @ return Count of allocated effects channels
2003-03-11 16:56:45 +00:00
*/
int
fluid_synth_count_effects_channels ( fluid_synth_t * synth )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
result = synth - > effects_channels ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the synth CPU load value .
* @ param synth FluidSynth instance
* @ return Estimated CPU load value in percent ( 0 - 100 )
*/
double
fluid_synth_get_cpu_load ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2009-09-25 00:56:48 +00:00
return fluid_atomic_float_get ( & synth - > cpu_load ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/* Get tuning for a given bank:program */
static fluid_tuning_t *
2003-03-11 16:56:45 +00:00
fluid_synth_get_tuning ( fluid_synth_t * synth , int bank , int prog )
{
2010-07-01 11:14:55 +00:00
2003-03-11 16:56:45 +00:00
if ( ( synth - > tuning = = NULL ) | |
( synth - > tuning [ bank ] = = NULL ) | |
2009-09-25 00:56:48 +00:00
( synth - > tuning [ bank ] [ prog ] = = NULL ) )
2007-03-04 16:45:05 +00:00
return NULL ;
2009-09-22 07:04:07 +00:00
2003-03-11 16:56:45 +00:00
return synth - > tuning [ bank ] [ prog ] ;
}
2009-09-25 00:56:48 +00:00
/* Replace tuning on a given bank:program (need not already exist).
* Synth mutex should already be locked by caller . */
static int
fluid_synth_replace_tuning_LOCK ( fluid_synth_t * synth , fluid_tuning_t * tuning ,
int bank , int prog , int apply )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
fluid_tuning_t * old_tuning ;
2009-09-22 07:04:07 +00:00
2003-03-11 16:56:45 +00:00
if ( synth - > tuning = = NULL ) {
synth - > tuning = FLUID_ARRAY ( fluid_tuning_t * * , 128 ) ;
if ( synth - > tuning = = NULL ) {
FLUID_LOG ( FLUID_PANIC , " Out of memory " ) ;
2009-09-25 00:56:48 +00:00
return FLUID_FAILED ;
2003-03-11 16:56:45 +00:00
}
FLUID_MEMSET ( synth - > tuning , 0 , 128 * sizeof ( fluid_tuning_t * * ) ) ;
}
if ( synth - > tuning [ bank ] = = NULL ) {
synth - > tuning [ bank ] = FLUID_ARRAY ( fluid_tuning_t * , 128 ) ;
if ( synth - > tuning [ bank ] = = NULL ) {
FLUID_LOG ( FLUID_PANIC , " Out of memory " ) ;
2009-09-25 00:56:48 +00:00
return FLUID_FAILED ;
2003-03-11 16:56:45 +00:00
}
FLUID_MEMSET ( synth - > tuning [ bank ] , 0 , 128 * sizeof ( fluid_tuning_t * ) ) ;
}
2009-09-25 00:56:48 +00:00
old_tuning = synth - > tuning [ bank ] [ prog ] ;
synth - > tuning [ bank ] [ prog ] = tuning ;
if ( old_tuning ) {
if ( ! fluid_tuning_unref ( old_tuning , 1 ) ) /* -- unref old tuning */
{ /* Replace old tuning if present */
2010-10-17 10:20:57 +00:00
fluid_synth_replace_tuning_LOCAL ( synth , old_tuning , tuning , apply , FALSE ) ;
2009-09-25 00:56:48 +00:00
}
}
return FLUID_OK ;
}
/* Replace a tuning with a new one in all MIDI channels. new_tuning can be
* NULL , in which case channels are reset to default equal tempered scale . */
static void
fluid_synth_replace_tuning_LOCAL ( fluid_synth_t * synth , fluid_tuning_t * old_tuning ,
fluid_tuning_t * new_tuning , int apply , int unref_new )
{
fluid_channel_t * channel ;
int old_tuning_unref = 0 ;
int i ;
for ( i = 0 ; i < synth - > midi_channels ; i + + )
{
channel = synth - > channel [ i ] ;
if ( fluid_channel_get_tuning ( channel ) = = old_tuning )
{
old_tuning_unref + + ;
if ( new_tuning ) fluid_tuning_ref ( new_tuning ) ; /* ++ ref new tuning for channel */
fluid_channel_set_tuning ( channel , new_tuning ) ;
if ( apply ) fluid_synth_update_voice_tuning_LOCAL ( synth , channel ) ;
2003-03-11 16:56:45 +00:00
}
}
2009-09-25 00:56:48 +00:00
/* Send unref old tuning event if any unrefs */
2010-09-12 19:18:39 +00:00
if ( old_tuning & & old_tuning_unref )
fluid_tuning_unref ( old_tuning , old_tuning_unref ) ;
2009-09-25 00:56:48 +00:00
if ( ! unref_new | | ! new_tuning ) return ;
2010-07-14 08:44:51 +00:00
fluid_tuning_unref ( new_tuning , 1 ) ;
2009-09-25 00:56:48 +00:00
}
/* Update voice tunings in realtime */
static void
fluid_synth_update_voice_tuning_LOCAL ( fluid_synth_t * synth , fluid_channel_t * channel )
{
fluid_voice_t * voice ;
int i ;
for ( i = 0 ; i < synth - > polyphony ; i + + )
{
voice = synth - > voice [ i ] ;
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_on ( voice ) & & ( voice - > channel = = channel ) )
2009-09-25 00:56:48 +00:00
{
fluid_voice_calculate_gen_pitch ( voice ) ;
fluid_voice_update_param ( voice , GEN_PITCH ) ;
}
}
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Set the tuning of the entire MIDI note scale .
* @ param synth FluidSynth instance
2009-09-25 00:56:48 +00:00
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
2009-09-22 07:04:07 +00:00
* @ param name Label name for this tuning
* @ param pitch Array of pitch values ( length of 128 , each value is number of
* cents , for example normally note 0 is 0.0 , 1 is 100.0 , 60 is 6000.0 , etc ) .
* Pass NULL to create a well - tempered ( normal ) scale .
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-09-26 20:10:14 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Tuning is not applied in realtime to existing notes of the replaced
2009-09-26 20:10:14 +00:00
* tuning ( if any ) , use fluid_synth_activate_key_tuning ( ) instead to specify
* this behavior .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_create_key_tuning ( fluid_synth_t * synth , int bank , int prog ,
2009-10-28 19:38:10 +00:00
const char * name , const double * pitch )
2009-09-26 20:10:14 +00:00
{
return fluid_synth_activate_key_tuning ( synth , bank , prog , name , pitch , FALSE ) ;
}
/**
* Set the tuning of the entire MIDI note scale .
* @ param synth FluidSynth instance
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
* @ param name Label name for this tuning
* @ param pitch Array of pitch values ( length of 128 , each value is number of
* cents , for example normally note 0 is 0.0 , 1 is 100.0 , 60 is 6000.0 , etc ) .
* Pass NULL to create a well - tempered ( normal ) scale .
* @ param apply TRUE to apply new tuning in realtime to existing notes which
* are using the replaced tuning ( if any ) , FALSE otherwise
* @ return FLUID_OK on success , FLUID_FAILED otherwise
* @ since 1.1 .0
*/
int
fluid_synth_activate_key_tuning ( fluid_synth_t * synth , int bank , int prog ,
2009-10-28 19:38:10 +00:00
const char * name , const double * pitch , int apply )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
fluid_tuning_t * tuning ;
int retval = FLUID_OK ;
2009-09-22 07:04:07 +00:00
2009-09-25 00:56:48 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( bank > = 0 & & bank < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( prog > = 0 & & prog < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-25 00:56:48 +00:00
tuning = new_fluid_tuning ( name , bank , prog ) ;
if ( tuning )
{
if ( pitch ) fluid_tuning_set_all ( tuning , pitch ) ;
2009-09-26 20:10:14 +00:00
retval = fluid_synth_replace_tuning_LOCK ( synth , tuning , bank , prog , apply ) ;
2009-09-25 00:56:48 +00:00
if ( retval = = FLUID_FAILED ) fluid_tuning_unref ( tuning , 1 ) ;
}
else retval = FLUID_FAILED ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( retval ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Apply an octave tuning to every octave in the MIDI note scale .
* @ param synth FluidSynth instance
2009-09-25 00:56:48 +00:00
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
2009-09-22 07:04:07 +00:00
* @ param name Label name for this tuning
* @ param pitch Array of pitch values ( length of 12 for each note of an octave
* starting at note C , values are number of offset cents to add to the normal
* tuning amount )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-09-26 20:10:14 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Tuning is not applied in realtime to existing notes of the replaced
2009-09-26 20:10:14 +00:00
* tuning ( if any ) , use fluid_synth_activate_octave_tuning ( ) instead to specify
* this behavior .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_create_octave_tuning ( fluid_synth_t * synth , int bank , int prog ,
2009-10-28 19:38:10 +00:00
const char * name , const double * pitch )
2009-09-26 20:10:14 +00:00
{
return fluid_synth_activate_octave_tuning ( synth , bank , prog , name , pitch , FALSE ) ;
}
/**
* Activate an octave tuning on every octave in the MIDI note scale .
* @ param synth FluidSynth instance
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
* @ param name Label name for this tuning
* @ param pitch Array of pitch values ( length of 12 for each note of an octave
* starting at note C , values are number of offset cents to add to the normal
* tuning amount )
* @ param apply TRUE to apply new tuning in realtime to existing notes which
* are using the replaced tuning ( if any ) , FALSE otherwise
* @ return FLUID_OK on success , FLUID_FAILED otherwise
* @ since 1.1 .0
*/
int
fluid_synth_activate_octave_tuning ( fluid_synth_t * synth , int bank , int prog ,
2009-10-28 19:38:10 +00:00
const char * name , const double * pitch , int apply )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
fluid_tuning_t * tuning ;
int retval = FLUID_OK ;
2009-09-22 07:04:07 +00:00
2009-09-25 00:56:48 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( bank > = 0 & & bank < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( prog > = 0 & & prog < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( pitch ! = NULL , FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-25 00:56:48 +00:00
tuning = new_fluid_tuning ( name , bank , prog ) ;
if ( tuning )
{
fluid_tuning_set_octave ( tuning , pitch ) ;
2009-09-26 20:10:14 +00:00
retval = fluid_synth_replace_tuning_LOCK ( synth , tuning , bank , prog , apply ) ;
2009-09-25 00:56:48 +00:00
if ( retval = = FLUID_FAILED ) fluid_tuning_unref ( tuning , 1 ) ;
}
else retval = FLUID_FAILED ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( retval ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Set tuning values for one or more MIDI notes for an existing tuning .
* @ param synth FluidSynth instance
2009-09-25 00:56:48 +00:00
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
2009-09-22 07:04:07 +00:00
* @ param len Number of MIDI notes to assign
* @ param key Array of MIDI key numbers ( length of ' len ' , values 0 - 127 )
* @ param pitch Array of pitch values ( length of ' len ' , values are number of
* cents from MIDI note 0 )
2009-09-26 20:10:14 +00:00
* @ param apply TRUE to apply tuning change in realtime to existing notes using
* the specified tuning , FALSE otherwise
2009-09-22 07:04:07 +00:00
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-09-25 00:56:48 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note Prior to version 1.1 .0 it was an error to specify a tuning that didn ' t
2009-09-25 00:56:48 +00:00
* already exist . Starting with 1.1 .0 , the default equal tempered scale will be
* used as a basis , if no tuning exists for the given bank and prog .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_tune_notes ( fluid_synth_t * synth , int bank , int prog ,
2009-10-28 19:38:10 +00:00
int len , const int * key , const double * pitch , int apply )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
fluid_tuning_t * old_tuning , * new_tuning ;
int retval = FLUID_OK ;
2003-03-11 16:56:45 +00:00
int i ;
2009-09-25 00:56:48 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( bank > = 0 & & bank < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( prog > = 0 & & prog < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( len > 0 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( key ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( pitch ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2003-03-11 16:56:45 +00:00
2009-09-25 00:56:48 +00:00
old_tuning = fluid_synth_get_tuning ( synth , bank , prog ) ;
2003-03-11 16:56:45 +00:00
2009-09-25 00:56:48 +00:00
if ( old_tuning )
new_tuning = fluid_tuning_duplicate ( old_tuning ) ;
else new_tuning = new_fluid_tuning ( " Unnamed " , bank , prog ) ;
if ( new_tuning )
{
for ( i = 0 ; i < len ; i + + )
fluid_tuning_set_pitch ( new_tuning , key [ i ] , pitch [ i ] ) ;
retval = fluid_synth_replace_tuning_LOCK ( synth , new_tuning , bank , prog , apply ) ;
if ( retval = = FLUID_FAILED ) fluid_tuning_unref ( new_tuning , 1 ) ;
}
else retval = FLUID_FAILED ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( retval ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
2009-09-26 20:10:14 +00:00
* Select a tuning scale on a MIDI channel .
2009-09-22 07:04:07 +00:00
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
2009-09-25 00:56:48 +00:00
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
2009-09-22 07:04:07 +00:00
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-09-25 00:56:48 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note This function does NOT activate tuning in realtime , use
2009-09-26 20:10:14 +00:00
* fluid_synth_activate_tuning ( ) instead to specify whether tuning change
* should cause existing notes to update .
*
2017-08-13 13:16:55 +00:00
* @ note Prior to version 1.1 .0 it was an error to select a tuning that didn ' t
2009-09-26 20:10:14 +00:00
* already exist . Starting with 1.1 .0 , a default equal tempered scale will be
* created , if no tuning exists for the given bank and prog .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_select_tuning ( fluid_synth_t * synth , int chan , int bank , int prog )
2009-09-26 20:10:14 +00:00
{
return fluid_synth_activate_tuning ( synth , chan , bank , prog , FALSE ) ;
}
/**
* Activate a tuning scale on a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param bank Tuning bank number ( 0 - 127 ) , not related to MIDI instrument bank
* @ param prog Tuning preset number ( 0 - 127 ) , not related to MIDI instrument program
* @ param apply TRUE to apply tuning change to active notes , FALSE otherwise
* @ return FLUID_OK on success , FLUID_FAILED otherwise
* @ since 1.1 .0
*
2017-08-13 13:16:55 +00:00
* @ note A default equal tempered scale will be created , if no tuning exists
2009-09-26 20:10:14 +00:00
* on the given bank and prog .
*/
int
fluid_synth_activate_tuning ( fluid_synth_t * synth , int chan , int bank , int prog ,
int apply )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
fluid_tuning_t * tuning ;
int retval = FLUID_OK ;
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
//fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
//fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
2009-09-25 00:56:48 +00:00
fluid_return_val_if_fail ( bank > = 0 & & bank < 128 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( prog > = 0 & & prog < 128 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2009-09-25 00:56:48 +00:00
tuning = fluid_synth_get_tuning ( synth , bank , prog ) ;
/* If no tuning exists, create a new default tuning. We do this, so that
* it can be replaced later , if any changes are made . */
if ( ! tuning )
{
tuning = new_fluid_tuning ( " Unnamed " , bank , prog ) ;
if ( tuning ) fluid_synth_replace_tuning_LOCK ( synth , tuning , bank , prog , FALSE ) ;
}
if ( tuning ) fluid_tuning_ref ( tuning ) ; /* ++ ref for outside of lock */
2010-07-01 11:14:55 +00:00
if ( ! tuning )
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-25 00:56:48 +00:00
2010-10-17 10:20:57 +00:00
fluid_tuning_ref ( tuning ) ; /* ++ ref new tuning for following function */
retval = fluid_synth_set_tuning_LOCAL ( synth , chan , tuning , apply ) ;
2009-09-25 00:56:48 +00:00
fluid_tuning_unref ( tuning , 1 ) ; /* -- unref for outside of lock */
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( retval ) ;
2009-09-25 00:56:48 +00:00
}
/* Local synthesis thread set tuning function (takes over tuning reference) */
static int
fluid_synth_set_tuning_LOCAL ( fluid_synth_t * synth , int chan ,
fluid_tuning_t * tuning , int apply )
{
fluid_tuning_t * old_tuning ;
fluid_channel_t * channel ;
channel = synth - > channel [ chan ] ;
old_tuning = fluid_channel_get_tuning ( channel ) ;
fluid_channel_set_tuning ( channel , tuning ) ; /* !! Takes over callers reference */
if ( apply ) fluid_synth_update_voice_tuning_LOCAL ( synth , channel ) ;
/* Send unref old tuning event */
if ( old_tuning )
{
2010-09-12 19:18:39 +00:00
fluid_tuning_unref ( old_tuning , 1 ) ;
}
2010-07-14 08:44:51 +00:00
2003-03-11 16:56:45 +00:00
return FLUID_OK ;
}
2009-09-22 07:04:07 +00:00
/**
* Clear tuning scale on a MIDI channel ( set it to the default well - tempered scale ) .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-09-26 20:10:14 +00:00
*
2017-08-13 13:16:55 +00:00
* @ note This function does NOT activate tuning change in realtime , use
2009-09-26 20:10:14 +00:00
* fluid_synth_deactivate_tuning ( ) instead to specify whether tuning change
* should cause existing notes to update .
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_reset_tuning ( fluid_synth_t * synth , int chan )
2009-09-26 20:10:14 +00:00
{
return fluid_synth_deactivate_tuning ( synth , chan , FALSE ) ;
}
/**
* Clear tuning scale on a MIDI channel ( use default equal tempered scale ) .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param apply TRUE to apply tuning change to active notes , FALSE otherwise
* @ return FLUID_OK on success , FLUID_FAILED otherwise
* @ since 1.1 .0
*/
int
fluid_synth_deactivate_tuning ( fluid_synth_t * synth , int chan , int apply )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
int retval = FLUID_OK ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
2010-10-17 10:20:57 +00:00
retval = fluid_synth_set_tuning_LOCAL ( synth , chan , NULL , apply ) ;
2009-09-25 00:56:48 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( retval ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Start tuning iteration .
* @ param synth FluidSynth instance
*/
void
fluid_synth_tuning_iteration_start ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_if_fail ( synth ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2013-08-19 23:10:43 +00:00
fluid_private_set ( synth - > tuning_iter , FLUID_INT_TO_POINTER ( 0 ) ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Advance to next tuning .
* @ param synth FluidSynth instance
* @ param bank Location to store MIDI bank number of next tuning scale
* @ param prog Location to store MIDI program number of next tuning scale
* @ return 1 if tuning iteration advanced , 0 if no more tunings
*/
int
fluid_synth_tuning_iteration_next ( fluid_synth_t * synth , int * bank , int * prog )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
void * pval ;
2003-03-11 16:56:45 +00:00
int b = 0 , p = 0 ;
2007-03-04 16:45:05 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
fluid_return_val_if_fail ( bank ! = NULL , 0 ) ;
fluid_return_val_if_fail ( prog ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
2009-09-25 00:56:48 +00:00
/* Current tuning iteration stored as: bank << 8 | program */
pval = fluid_private_get ( synth - > tuning_iter ) ;
p = FLUID_POINTER_TO_INT ( pval ) ;
b = ( p > > 8 ) & 0xFF ;
p & = 0xFF ;
2003-03-11 16:56:45 +00:00
2009-09-25 00:56:48 +00:00
if ( ! synth - > tuning )
{
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( 0 ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-25 00:56:48 +00:00
for ( ; b < 128 ; b + + , p = 0 )
{
if ( synth - > tuning [ b ] = = NULL ) continue ;
for ( ; p < 128 ; p + + )
{
if ( synth - > tuning [ b ] [ p ] = = NULL ) continue ;
* bank = b ;
* prog = p ;
if ( p < 127 ) fluid_private_set ( synth - > tuning_iter ,
2013-08-19 23:10:43 +00:00
FLUID_INT_TO_POINTER ( b < < 8 | ( p + 1 ) ) ) ;
2009-09-25 00:56:48 +00:00
else fluid_private_set ( synth - > tuning_iter ,
2013-08-19 23:10:43 +00:00
FLUID_INT_TO_POINTER ( ( b + 1 ) < < 8 ) ) ;
2009-09-25 00:56:48 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( 1 ) ;
2003-03-11 16:56:45 +00:00
}
}
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( 0 ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get the entire note tuning for a given MIDI bank and program .
* @ param synth FluidSynth instance
* @ param bank MIDI bank number of tuning
* @ param prog MIDI program number of tuning
* @ param name Location to store tuning name or NULL to ignore
* @ param len Maximum number of chars to store to ' name ' ( including NULL byte )
* @ param pitch Array to store tuning scale to or NULL to ignore ( len of 128 )
2009-09-25 00:56:48 +00:00
* @ return FLUID_OK if matching tuning was found , FLUID_FAILED otherwise
2009-09-22 07:04:07 +00:00
*/
int
fluid_synth_tuning_dump ( fluid_synth_t * synth , int bank , int prog ,
char * name , int len , double * pitch )
2003-03-11 16:56:45 +00:00
{
2009-09-25 00:56:48 +00:00
fluid_tuning_t * tuning ;
2010-07-01 11:14:55 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_synth_api_enter ( synth ) ;
2009-09-25 00:56:48 +00:00
tuning = fluid_synth_get_tuning ( synth , bank , prog ) ;
2003-03-11 16:56:45 +00:00
2009-09-25 00:56:48 +00:00
if ( tuning )
{
if ( name )
{
snprintf ( name , len - 1 , " %s " , fluid_tuning_get_name ( tuning ) ) ;
name [ len - 1 ] = 0 ; /* make sure the string is null terminated */
}
if ( pitch )
FLUID_MEMCPY ( pitch , fluid_tuning_get_all ( tuning ) , 128 * sizeof ( double ) ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( tuning ? FLUID_OK : FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get settings assigned to a synth .
* @ param synth FluidSynth instance
* @ return FluidSynth settings which are assigned to the synth
*/
fluid_settings_t *
fluid_synth_get_settings ( fluid_synth_t * synth )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , NULL ) ;
2003-03-11 16:56:45 +00:00
return synth - > settings ;
}
2009-09-22 07:04:07 +00:00
/**
* Convenience function to set a string setting of a synth .
* @ param synth FluidSynth instance
* @ param name Name of setting parameter
* @ param str Value to assign to the setting
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_setstr ( fluid_synth_t * synth , const char * name , const char * str )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
return fluid_settings_setstr ( synth - > settings , name , str ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Convenience function to duplicate a string setting of a synth .
* @ param synth FluidSynth instance
* @ param name Name of setting parameter
* @ param str Location to store a pointer to the newly allocated string value
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*
* The returned string is owned by the caller and should be freed with free ( )
* when finished with it .
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_dupstr ( fluid_synth_t * synth , const char * name , char * * str )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( str ! = NULL , FLUID_FAILED ) ;
return fluid_settings_dupstr ( synth - > settings , name , str ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Convenience function to set a floating point setting of a synth .
* @ param synth FluidSynth instance
* @ param name Name of setting parameter
* @ param val Value to assign to the setting
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_setnum ( fluid_synth_t * synth , const char * name , double val )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
return fluid_settings_setnum ( synth - > settings , name , val ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Convenience function to get a floating point setting of a synth .
* @ param synth FluidSynth instance
* @ param name Name of setting parameter
* @ param val Location to store the current value of the setting
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_getnum ( fluid_synth_t * synth , const char * name , double * val )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
return fluid_settings_getnum ( synth - > settings , name , val ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Convenience function to set an integer setting of a synth .
* @ param synth FluidSynth instance
* @ param name Name of setting parameter
* @ param val Value to assign to the setting
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_setint ( fluid_synth_t * synth , const char * name , int val )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
return fluid_settings_setint ( synth - > settings , name , val ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Convenience function to get an integer setting of a synth .
* @ param synth FluidSynth instance
* @ param name Name of setting parameter
* @ param val Location to store the current value of the setting
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*/
int
2009-10-28 19:38:10 +00:00
fluid_synth_getint ( fluid_synth_t * synth , const char * name , int * val )
2003-03-11 16:56:45 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( name ! = NULL , FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
return fluid_settings_getint ( synth - > settings , name , val ) ;
}
2009-09-22 07:04:07 +00:00
/**
* Set a SoundFont generator ( effect ) value on a MIDI channel in real - time .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param param SoundFont generator ID ( # fluid_gen_type )
* @ param value Offset generator value to assign to the MIDI channel
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*
* Parameter numbers and ranges are described in the SoundFont 2.01
* specification PDF , paragraph 8.1 .3 , page 48. See # fluid_gen_type .
*/
2007-03-04 16:45:05 +00:00
int
2003-03-11 16:56:45 +00:00
fluid_synth_set_gen ( fluid_synth_t * synth , int chan , int param , float value )
{
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( param > = 0 & & param < GEN_LAST , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
2010-10-17 10:20:57 +00:00
fluid_synth_set_gen_LOCAL ( synth , chan , param , value , FALSE ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2009-09-22 07:04:07 +00:00
}
/* Synthesis thread local set gen function */
static void
fluid_synth_set_gen_LOCAL ( fluid_synth_t * synth , int chan , int param , float value ,
int absolute )
{
fluid_voice_t * voice ;
int i ;
2003-03-11 16:56:45 +00:00
2009-09-22 07:04:07 +00:00
fluid_channel_set_gen ( synth - > channel [ chan ] , param , value , absolute ) ;
2004-03-03 11:14:25 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2004-03-03 11:14:25 +00:00
voice = synth - > voice [ i ] ;
2017-09-02 22:22:07 +00:00
if ( fluid_voice_get_channel ( voice ) = = chan )
2009-09-22 07:04:07 +00:00
fluid_voice_set_param ( voice , param , value , absolute ) ;
}
2004-03-03 11:14:25 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Set a SoundFont generator ( effect ) value on a MIDI channel in real - time .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param param SoundFont generator ID ( # fluid_gen_type )
* @ param value Offset or absolute generator value to assign to the MIDI channel
* @ param absolute 0 to assign a relative value , non - zero to assign an absolute value
2009-10-23 02:18:26 +00:00
* @ param normalized 0 if value is specified in the native units of the generator ,
2009-09-22 07:04:07 +00:00
* non - zero to take the value as a 0.0 - 1.0 range and apply it to the valid
* generator effect range ( scaled and shifted as necessary ) .
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2009-10-23 02:18:26 +00:00
* @ since 1.1 .0
2009-09-22 07:04:07 +00:00
*
* This function allows for setting all effect parameters in real time on a
* MIDI channel . Setting absolute to non - zero will cause the value to override
* any generator values set in the instruments played on the MIDI channel .
* See SoundFont 2.01 spec , paragraph 8.1 .3 , page 48 for details on SoundFont
* generator parameters and valid ranges .
2004-03-03 11:14:25 +00:00
*/
2007-03-04 16:45:05 +00:00
int
fluid_synth_set_gen2 ( fluid_synth_t * synth , int chan , int param ,
2004-03-03 11:14:25 +00:00
float value , int absolute , int normalized )
{
float v ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( param > = 0 & & param < GEN_LAST , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2004-03-03 11:14:25 +00:00
2009-09-22 07:04:07 +00:00
v = normalized ? fluid_gen_scale ( param , value ) : value ;
2003-03-11 16:56:45 +00:00
2010-10-17 10:20:57 +00:00
fluid_synth_set_gen_LOCAL ( synth , chan , param , v , absolute ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get generator value assigned to a MIDI channel .
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param param SoundFont generator ID ( # fluid_gen_type )
* @ return Current generator value assigned to MIDI channel
*/
float
fluid_synth_get_gen ( fluid_synth_t * synth , int chan , int param )
2003-03-11 16:56:45 +00:00
{
2010-07-01 11:14:55 +00:00
float result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( param > = 0 & & param < GEN_LAST , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2003-03-11 16:56:45 +00:00
2010-07-01 11:14:55 +00:00
result = fluid_channel_get_gen ( synth - > channel [ chan ] , param ) ;
FLUID_API_RETURN ( result ) ;
2003-03-11 16:56:45 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Assign a MIDI router to a synth .
* @ param synth FluidSynth instance
* @ param router MIDI router to assign to the synth
*
2017-08-13 13:16:55 +00:00
* @ note This should only be done once and prior to using the synth .
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
void
fluid_synth_set_midi_router ( fluid_synth_t * synth , fluid_midi_router_t * router )
{
fluid_return_if_fail ( synth ! = NULL ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
synth - > midi_router = router ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_exit ( synth ) ;
2003-03-11 16:56:45 +00:00
} ;
2009-09-22 07:04:07 +00:00
/**
* Handle MIDI event from MIDI router , used as a callback function .
* @ param data FluidSynth instance
* @ param event MIDI event to handle
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2003-03-11 16:56:45 +00:00
*/
2009-09-22 07:04:07 +00:00
int
fluid_synth_handle_midi_event ( void * data , fluid_midi_event_t * event )
2003-03-11 16:56:45 +00:00
{
fluid_synth_t * synth = ( fluid_synth_t * ) data ;
int type = fluid_midi_event_get_type ( event ) ;
int chan = fluid_midi_event_get_channel ( event ) ;
switch ( type ) {
case NOTE_ON :
2007-03-04 16:45:05 +00:00
return fluid_synth_noteon ( synth , chan ,
2009-09-26 20:10:14 +00:00
fluid_midi_event_get_key ( event ) ,
fluid_midi_event_get_velocity ( event ) ) ;
2003-03-11 16:56:45 +00:00
case NOTE_OFF :
return fluid_synth_noteoff ( synth , chan , fluid_midi_event_get_key ( event ) ) ;
case CONTROL_CHANGE :
2007-03-04 16:45:05 +00:00
return fluid_synth_cc ( synth , chan ,
2009-09-26 20:10:14 +00:00
fluid_midi_event_get_control ( event ) ,
fluid_midi_event_get_value ( event ) ) ;
2003-03-11 16:56:45 +00:00
case PROGRAM_CHANGE :
return fluid_synth_program_change ( synth , chan , fluid_midi_event_get_program ( event ) ) ;
2009-01-22 16:47:21 +00:00
case CHANNEL_PRESSURE :
2009-11-05 04:37:51 +00:00
return fluid_synth_channel_pressure ( synth , chan , fluid_midi_event_get_program ( event ) ) ;
2009-01-22 16:47:21 +00:00
2003-03-11 16:56:45 +00:00
case PITCH_BEND :
return fluid_synth_pitch_bend ( synth , chan , fluid_midi_event_get_pitch ( event ) ) ;
case MIDI_SYSTEM_RESET :
return fluid_synth_system_reset ( synth ) ;
2009-09-26 20:10:14 +00:00
case MIDI_SYSEX :
return fluid_synth_sysex ( synth , event - > paramptr , event - > param1 , NULL , NULL , NULL , FALSE ) ;
2003-03-11 16:56:45 +00:00
}
return FLUID_FAILED ;
}
2009-09-22 07:04:07 +00:00
/**
* Create and start voices using a preset and a MIDI note on event .
* @ param synth FluidSynth instance
* @ param id Voice group ID to use ( can be used with fluid_synth_stop ( ) ) .
* @ param preset Preset to synthesize
* @ param audio_chan Unused currently , set to 0
2010-07-01 11:14:55 +00:00
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
2009-09-22 07:04:07 +00:00
* @ param key MIDI note number ( 0 - 127 )
* @ param vel MIDI velocity number ( 1 - 127 )
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*
2017-08-13 13:16:55 +00:00
* @ note Should only be called from within synthesis thread , which includes
2009-09-22 07:04:07 +00:00
* SoundFont loader preset noteon method .
*/
int
fluid_synth_start ( fluid_synth_t * synth , unsigned int id , fluid_preset_t * preset ,
2010-07-01 11:14:55 +00:00
int audio_chan , int chan , int key , int vel )
2004-05-05 20:27:22 +00:00
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( preset ! = NULL , FLUID_FAILED ) ;
fluid_return_val_if_fail ( key > = 0 & & key < = 127 , FLUID_FAILED ) ;
fluid_return_val_if_fail ( vel > = 1 & & vel < = 127 , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
2004-05-05 20:27:22 +00:00
synth - > storeid = id ;
2010-07-01 11:14:55 +00:00
result = fluid_preset_noteon ( preset , synth , chan , key , vel ) ;
FLUID_API_RETURN ( result ) ;
2009-09-22 07:04:07 +00:00
}
/**
* Stop notes for a given note event voice ID .
* @ param synth FluidSynth instance
* @ param id Voice note event ID
* @ return FLUID_OK on success , FLUID_FAILED otherwise
*
2017-08-13 13:16:55 +00:00
* @ note In FluidSynth versions prior to 1.1 .0 # FLUID_FAILED would be returned
2009-09-22 07:04:07 +00:00
* if no matching voice note event ID was found . Versions after 1.1 .0 only
* return # FLUID_FAILED if an error occurs .
*/
int
fluid_synth_stop ( fluid_synth_t * synth , unsigned int id )
{
2010-07-01 11:14:55 +00:00
int result ;
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2010-10-17 10:20:57 +00:00
fluid_synth_stop_LOCAL ( synth , id ) ;
result = FLUID_OK ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( result ) ;
2004-05-05 20:27:22 +00:00
}
2009-09-22 07:04:07 +00:00
/* Local synthesis thread variant of fluid_synth_stop */
static void
fluid_synth_stop_LOCAL ( fluid_synth_t * synth , unsigned int id )
2004-05-05 20:27:22 +00:00
{
fluid_voice_t * voice ;
2009-09-22 07:04:07 +00:00
int i ;
2007-03-04 16:45:05 +00:00
2005-06-08 03:51:13 +00:00
for ( i = 0 ; i < synth - > polyphony ; i + + ) {
2004-05-05 20:27:22 +00:00
voice = synth - > voice [ i ] ;
2017-08-27 14:17:15 +00:00
if ( fluid_voice_is_on ( voice ) & & ( fluid_voice_get_id ( voice ) = = id ) )
2009-10-14 07:27:30 +00:00
fluid_voice_noteoff ( voice ) ;
2004-05-05 20:27:22 +00:00
}
}
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
/**
* Offset the bank numbers of a loaded SoundFont .
* @ param synth FluidSynth instance
* @ param sfont_id ID of a loaded SoundFont
* @ param offset Bank offset value to apply to all instruments
*/
int
fluid_synth_set_bank_offset ( fluid_synth_t * synth , int sfont_id , int offset )
2004-08-18 15:11:47 +00:00
{
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
fluid_list_t * list ;
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , FLUID_FAILED ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2009-09-22 07:04:07 +00:00
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
if ( fluid_sfont_get_id ( sfont_info - > sfont ) = = ( unsigned int ) sfont_id )
{
sfont_info - > bankofs = offset ;
break ;
}
}
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
if ( ! list )
{
FLUID_LOG ( FLUID_ERR , " No SoundFont with id = %d " , sfont_id ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_FAILED ) ;
2009-09-22 07:04:07 +00:00
}
2004-08-18 15:11:47 +00:00
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( FLUID_OK ) ;
2004-08-18 15:11:47 +00:00
}
2009-09-22 07:04:07 +00:00
/**
* Get bank offset of a loaded SoundFont .
* @ param synth FluidSynth instance
* @ param sfont_id ID of a loaded SoundFont
* @ return SoundFont bank offset value
*/
2007-03-04 16:45:05 +00:00
int
2004-08-18 15:11:47 +00:00
fluid_synth_get_bank_offset ( fluid_synth_t * synth , int sfont_id )
{
2009-09-22 07:04:07 +00:00
fluid_sfont_info_t * sfont_info ;
fluid_list_t * list ;
2009-10-12 19:18:06 +00:00
int offset = 0 ;
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
fluid_return_val_if_fail ( synth ! = NULL , 0 ) ;
2010-07-01 11:14:55 +00:00
fluid_synth_api_enter ( synth ) ;
2004-08-18 15:11:47 +00:00
2009-09-22 07:04:07 +00:00
for ( list = synth - > sfont_info ; list ; list = fluid_list_next ( list ) ) {
sfont_info = ( fluid_sfont_info_t * ) fluid_list_get ( list ) ;
if ( fluid_sfont_get_id ( sfont_info - > sfont ) = = ( unsigned int ) sfont_id )
{
offset = sfont_info - > bankofs ;
break ;
}
}
if ( ! list )
{
FLUID_LOG ( FLUID_ERR , " No SoundFont with id = %d " , sfont_id ) ;
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( 0 ) ;
2009-09-22 07:04:07 +00:00
}
2010-07-01 11:14:55 +00:00
FLUID_API_RETURN ( offset ) ;
}
void
fluid_synth_api_enter ( fluid_synth_t * synth )
{
if ( synth - > use_mutex ) {
fluid_rec_mutex_lock ( synth - > mutex ) ;
}
if ( ! synth - > public_api_count ) {
fluid_synth_check_finished_voices ( synth ) ;
}
synth - > public_api_count + + ;
}
void fluid_synth_api_exit ( fluid_synth_t * synth )
{
synth - > public_api_count - - ;
if ( ! synth - > public_api_count ) {
fluid_rvoice_eventhandler_flush ( synth - > eventhandler ) ;
}
if ( synth - > use_mutex ) {
fluid_rec_mutex_unlock ( synth - > mutex ) ;
}
2004-08-18 15:11:47 +00:00
}
2011-02-04 19:19:30 +00:00
/**
* Set midi channel type
* @ param synth FluidSynth instance
* @ param chan MIDI channel number ( 0 to MIDI channel count - 1 )
* @ param type CHANNEL_TYPE_MELODIC , or CHANNEL_TYPE_DRUM
* @ return FLUID_OK on success , FLUID_FAILED otherwise
2011-02-04 19:26:33 +00:00
* @ since 1.1 .4
2011-02-04 19:19:30 +00:00
*/
int fluid_synth_set_channel_type ( fluid_synth_t * synth , int chan , int type )
{
fluid_return_val_if_fail ( ( type > = CHANNEL_TYPE_MELODIC ) & & ( type < = CHANNEL_TYPE_DRUM ) , FLUID_FAILED ) ;
FLUID_API_ENTRY_CHAN ( FLUID_FAILED ) ;
synth - > channel [ chan ] - > channel_type = type ;
FLUID_API_RETURN ( FLUID_OK ) ;
}