mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-31 13:40:35 +00:00
Noteoff optimization fixed, mutex in iiwu_synth, ...
This commit is contained in:
parent
82b1c742c9
commit
75a32f5c75
8 changed files with 254 additions and 187 deletions
|
@ -1,3 +1,21 @@
|
||||||
|
2003-05-29 root <mn@bongo>
|
||||||
|
|
||||||
|
* src/fluid_synth.c (fluid_synth_one_block): Added a mutex that provides a small degree of
|
||||||
|
protection against noteons / noteoffs, when the audio thread is working.
|
||||||
|
|
||||||
|
* src/fluid_synth.h (struct _fluid_synth_t):
|
||||||
|
|
||||||
|
* src/fluid_voice.c (fluid_voice_optimize_sample):
|
||||||
|
|
||||||
|
2003-05-29 Markus Nentwig <nentwig@users.sourceforge.net>
|
||||||
|
|
||||||
|
* include/fluidsynth/voice.h: added fluid_voice_gen_incr to api
|
||||||
|
* src/fluidsynth.c: Added error message for command line parameter handling
|
||||||
|
* src/fluid_voice.c (fluid_voice_optimize_sample): Removed loop peak detection
|
||||||
|
at run time, because it caused dropouts. Now the sound font loader or application
|
||||||
|
is responsible to call fluid_voice_optimize_sample (if it doesn't, the turnoff optimization is
|
||||||
|
simply disabled).
|
||||||
|
|
||||||
2003-04-029 Antoine Schmitt <as@gratin.org>
|
2003-04-029 Antoine Schmitt <as@gratin.org>
|
||||||
|
|
||||||
* src/fluid_defsfont.c: inst_zone lokey is now properly inialized to 0
|
* src/fluid_defsfont.c: inst_zone lokey is now properly inialized to 0
|
||||||
|
|
|
@ -54,6 +54,8 @@ FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t* voice, int gen, float val
|
||||||
/** Get the value of a generator */
|
/** Get the value of a generator */
|
||||||
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
|
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
|
||||||
|
|
||||||
|
/** Modify the value of a generator by val */
|
||||||
|
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
|
||||||
|
|
||||||
|
|
||||||
/** Return the unique ID of the noteon-event. A sound font loader
|
/** Return the unique ID of the noteon-event. A sound font loader
|
||||||
|
@ -72,6 +74,20 @@ FLUIDSYNTH_API unsigned int fluid_voice_get_id(fluid_voice_t* voice);
|
||||||
|
|
||||||
FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
|
FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
|
||||||
|
|
||||||
|
/** If the peak volume during the loop is known, then the voice can
|
||||||
|
* be released earlier during the release phase. Otherwise, the
|
||||||
|
* voice will operate (inaudibly), until the envelope is at the
|
||||||
|
* nominal turnoff point. In many cases the loop volume is many dB
|
||||||
|
* below the maximum volume. For example, the loop volume for a
|
||||||
|
* typical acoustic piano is 20 dB below max. Taking that into
|
||||||
|
* account in the turn-off algorithm we can save 20 dB / 100 dB =>
|
||||||
|
* 1/5 of the total release time.
|
||||||
|
* So it's a good idea to call fluid_voice_optimize_sample
|
||||||
|
* on each sample once.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t* s);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
|
|
||||||
|
|
||||||
#include "fluid_defsfont.h"
|
#include "fluid_defsfont.h"
|
||||||
|
/* Todo: Get rid of that 'include' */
|
||||||
#include "fluid_sys.h"
|
#include "fluid_sys.h"
|
||||||
#include "fluid_voice.h"
|
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
*
|
*
|
||||||
* SFONT LOADER
|
* SFONT LOADER
|
||||||
|
@ -1381,9 +1381,10 @@ fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defs
|
||||||
if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) {
|
if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) {
|
||||||
zone->sample = fluid_defsfont_get_sample(sfont, ((SFSample *) sfzone->instsamp->data)->name);
|
zone->sample = fluid_defsfont_get_sample(sfont, ((SFSample *) sfzone->instsamp->data)->name);
|
||||||
if (zone->sample == NULL) {
|
if (zone->sample == NULL) {
|
||||||
FLUID_LOG(FLUID_ERR, "Couldnt fins sample name");
|
FLUID_LOG(FLUID_ERR, "Couldn't find sample name");
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
fluid_voice_optimize_sample(zone->sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Import the modulators (only SF2.1 and higher) */
|
/* Import the modulators (only SF2.1 and higher) */
|
||||||
|
|
|
@ -328,6 +328,8 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
|
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
|
||||||
|
|
||||||
|
fluid_mutex_init(synth->busy);
|
||||||
|
|
||||||
synth->settings = settings;
|
synth->settings = settings;
|
||||||
|
|
||||||
|
@ -670,6 +672,7 @@ delete_fluid_synth(fluid_synth_t* synth)
|
||||||
FLUID_FREE(synth->LADSPA_FxUnit);
|
FLUID_FREE(synth->LADSPA_FxUnit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
fluid_mutex_destroy(synth->busy);
|
||||||
FLUID_FREE(synth);
|
FLUID_FREE(synth);
|
||||||
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
|
@ -695,6 +698,8 @@ fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
|
||||||
{
|
{
|
||||||
fluid_channel_t* channel;
|
fluid_channel_t* channel;
|
||||||
int r;
|
int r;
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
|
@ -747,6 +752,8 @@ fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
int status = FLUID_FAILED;
|
int status = FLUID_FAILED;
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
@ -782,6 +789,8 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
if ((voice->chan == chan) && _SUSTAINED(voice)) {
|
if ((voice->chan == chan) && _SUSTAINED(voice)) {
|
||||||
|
@ -799,6 +808,8 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
|
||||||
int
|
int
|
||||||
fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
|
fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
|
||||||
{
|
{
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
||||||
|
@ -924,6 +935,8 @@ fluid_synth_modulate_voices(fluid_synth_t* synth, int chan, int is_cc, int ctrl)
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
if (voice->chan == chan) {
|
if (voice->chan == chan) {
|
||||||
|
@ -945,6 +958,8 @@ fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
@ -962,6 +977,8 @@ int
|
||||||
fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
|
fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
||||||
|
@ -1100,6 +1117,8 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
|
||||||
unsigned int banknum;
|
unsigned int banknum;
|
||||||
unsigned int sfont_id;
|
unsigned int sfont_id;
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
if ((prognum >= 0) && (prognum < FLUID_NUM_PROGRAMS) &&
|
if ((prognum >= 0) && (prognum < FLUID_NUM_PROGRAMS) &&
|
||||||
(chan >= 0) && (chan < synth->midi_channels)) {
|
(chan >= 0) && (chan < synth->midi_channels)) {
|
||||||
|
|
||||||
|
@ -1323,6 +1342,8 @@ int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num)
|
||||||
void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
|
void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
|
||||||
double width, double level)
|
double width, double level)
|
||||||
{
|
{
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
fluid_revmodel_setroomsize(synth->reverb, roomsize);
|
fluid_revmodel_setroomsize(synth->reverb, roomsize);
|
||||||
fluid_revmodel_setdamp(synth->reverb, damping);
|
fluid_revmodel_setdamp(synth->reverb, damping);
|
||||||
fluid_revmodel_setwidth(synth->reverb, width);
|
fluid_revmodel_setwidth(synth->reverb, width);
|
||||||
|
@ -1335,6 +1356,8 @@ void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double dampin
|
||||||
void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
||||||
double speed, double depth_ms, int type)
|
double speed, double depth_ms, int type)
|
||||||
{
|
{
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
fluid_chorus_set_nr(synth->chorus, nr);
|
fluid_chorus_set_nr(synth->chorus, nr);
|
||||||
fluid_chorus_set_level(synth->chorus, (fluid_real_t)level);
|
fluid_chorus_set_level(synth->chorus, (fluid_real_t)level);
|
||||||
fluid_chorus_set_speed_Hz(synth->chorus, (fluid_real_t)speed);
|
fluid_chorus_set_speed_Hz(synth->chorus, (fluid_real_t)speed);
|
||||||
|
@ -1598,6 +1621,7 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||||
fluid_real_t* chorus_buf;
|
fluid_real_t* chorus_buf;
|
||||||
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
|
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
|
||||||
double prof_ref = fluid_profile_ref();
|
double prof_ref = fluid_profile_ref();
|
||||||
|
fluid_mutex_lock(synth->busy); /* Here comes the audio thread. Lock the synth. */
|
||||||
|
|
||||||
fluid_check_fpe("??? Just starting up ???");
|
fluid_check_fpe("??? Just starting up ???");
|
||||||
|
|
||||||
|
@ -1717,6 +1741,7 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||||
{float num=1;while (num != 0){num*=0.5;};};
|
{float num=1;while (num != 0){num*=0.5;};};
|
||||||
#endif
|
#endif
|
||||||
fluid_check_fpe("??? Remainder of synth_one_block ???");
|
fluid_check_fpe("??? Remainder of synth_one_block ???");
|
||||||
|
fluid_mutex_unlock(synth->busy); /* Allow other threads to touch the synth */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1737,6 +1762,9 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
int best_voice_index=-1;
|
int best_voice_index=-1;
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
|
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
@ -1809,6 +1837,9 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
|
||||||
int i, k;
|
int i, k;
|
||||||
fluid_voice_t* voice = NULL;
|
fluid_voice_t* voice = NULL;
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
/* If there is another voice process on the same channel and key,
|
/* If there is another voice process on the same channel and key,
|
||||||
advance it to the release phase. */
|
advance it to the release phase. */
|
||||||
fluid_synth_release_voice_on_same_note(synth, chan, key);
|
fluid_synth_release_voice_on_same_note(synth, chan, key);
|
||||||
|
@ -1935,12 +1966,16 @@ void fluid_synth_kill_by_exclusive_class(fluid_synth_t* synth, fluid_voice_t* ne
|
||||||
*/
|
*/
|
||||||
void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
|
void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
|
||||||
{
|
{
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
/* Find the exclusive class of this voice. If set, kill all voices
|
/* Find the exclusive class of this voice. If set, kill all voices
|
||||||
* that match the exclusive class and are younger than the first
|
* that match the exclusive class and are younger than the first
|
||||||
* voice process created by this noteon event. */
|
* voice process created by this noteon event. */
|
||||||
fluid_synth_kill_by_exclusive_class(synth, voice);
|
fluid_synth_kill_by_exclusive_class(synth, voice);
|
||||||
|
|
||||||
/* Start the new voice */
|
/* Start the new voice */
|
||||||
|
|
||||||
fluid_voice_start(voice);
|
fluid_voice_start(voice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2280,6 +2315,9 @@ double fluid_synth_get_reverb_width(fluid_synth_t* synth)
|
||||||
void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int key){
|
void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int key){
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
|
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
if (_PLAYING(voice)
|
if (_PLAYING(voice)
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "fluid_chorus.h"
|
#include "fluid_chorus.h"
|
||||||
#include "fluid_ladspa.h"
|
#include "fluid_ladspa.h"
|
||||||
#include "fluid_midi_router.h"
|
#include "fluid_midi_router.h"
|
||||||
|
#include "fluid_sys.h"
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
*
|
*
|
||||||
|
@ -131,6 +132,10 @@ struct _fluid_synth_t
|
||||||
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
||||||
|
|
||||||
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
||||||
|
fluid_mutex_t busy; /* Indicates, whether the audio thread is currently running.
|
||||||
|
* Note: This simple scheme does -not- provide 100 % protection against
|
||||||
|
* thread problems, for example from MIDI thread and shell thread
|
||||||
|
*/
|
||||||
#ifdef LADSPA
|
#ifdef LADSPA
|
||||||
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /** Effects unit for LADSPA support */
|
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /** Effects unit for LADSPA support */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
* 02111-1307, USA
|
* 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
int print_pan = 1;
|
|
||||||
|
|
||||||
#include "fluidsynth_priv.h"
|
#include "fluidsynth_priv.h"
|
||||||
#include "fluid_voice.h"
|
#include "fluid_voice.h"
|
||||||
#include "fluid_mod.h"
|
#include "fluid_mod.h"
|
||||||
|
@ -42,13 +39,16 @@ float interp_coeff_sse_mem[FLUID_INTERP_MAX*4+4];
|
||||||
sse_t* interp_coeff_sse;
|
sse_t* interp_coeff_sse;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* 16 bits => 96+4=100 dB dynamic range => 0.00001 */
|
|
||||||
#define FLUID_NOISE_FLOOR 0.00003
|
|
||||||
|
|
||||||
/* used for filter turn off optimization - if filter cutoff is above the
|
/* used for filter turn off optimization - if filter cutoff is above the
|
||||||
specified value and filter q is below the other value, turn filter off */
|
specified value and filter q is below the other value, turn filter off */
|
||||||
#define FLUID_MAX_AUDIBLE_FILTER_FC 16000.0f
|
#define FLUID_MAX_AUDIBLE_FILTER_FC 16000.0f
|
||||||
#define FLUID_MIN_AUDIBLE_FILTER_Q 1.2f
|
#define FLUID_MIN_AUDIBLE_FILTER_Q 1.2f
|
||||||
|
|
||||||
|
/* Smallest amplitude that can be perceived (full scale is +/- 0.5)
|
||||||
|
* 16 bits => 96+4=100 dB dynamic range => 0.00001
|
||||||
|
* 0.00001 * 2 is approximately 0.00003 :)
|
||||||
|
*/
|
||||||
|
#define FLUID_NOISE_FLOOR 0.00003
|
||||||
|
|
||||||
/* these should be the absolute minimum that FluidSynth can deal with */
|
/* these should be the absolute minimum that FluidSynth can deal with */
|
||||||
#define FLUID_MIN_LOOP_SIZE 2
|
#define FLUID_MIN_LOOP_SIZE 2
|
||||||
|
@ -262,8 +262,11 @@ fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||||
|
|
||||||
/* For a looped sample, this value will be overwritten as soon as the
|
/* For a looped sample, this value will be overwritten as soon as the
|
||||||
* loop parameters are initialized (they may depend on modulators).
|
* loop parameters are initialized (they may depend on modulators).
|
||||||
* For a non-looped sample this is kept.*/
|
* This value can be kept, it is a worst-case estimate.
|
||||||
voice->amplitude_that_reaches_noise_floor = FLUID_NOISE_FLOOR / voice->synth_gain;
|
*/
|
||||||
|
|
||||||
|
voice->amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / voice->synth_gain;
|
||||||
|
voice->amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / voice->synth_gain;
|
||||||
|
|
||||||
/* Increment the reference count of the sample to prevent the
|
/* Increment the reference count of the sample to prevent the
|
||||||
unloading of the soundfont while this voice is playing. */
|
unloading of the soundfont while this voice is playing. */
|
||||||
|
@ -498,14 +501,25 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
|
|
||||||
/* A voice can be turned off, when an estimate for the volume
|
/* A voice can be turned off, when an estimate for the volume
|
||||||
* (upper bound) falls below that volume, that will drop the
|
* (upper bound) falls below that volume, that will drop the
|
||||||
* sample below the noise floor. Start out with assuming a 0 dB
|
* sample below the noise floor.
|
||||||
* sample... */
|
*/
|
||||||
amplitude_that_reaches_noise_floor = FLUID_NOISE_FLOOR;
|
|
||||||
if (voice->has_looped) {
|
/* If the loop amplitude is known, we can use it if the voice loop is within
|
||||||
/* For the loop we may have a better estimate for the volume of
|
* the sample loop
|
||||||
* the actual sample (from peak detector): */
|
*/
|
||||||
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor;
|
#if 0
|
||||||
}
|
printf("%i %i %i %i %i %i\n", voice->has_looped, voice->sample->amplitude_that_reaches_noise_floor_is_valid, voice->loop_start, voice->loop_end, voice->sample->loopstart, voice->sample->loopend );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Is the playing pointer already in the loop? */
|
||||||
|
if (voice->has_looped){
|
||||||
|
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor_loop;
|
||||||
|
} else {
|
||||||
|
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor_nonloop;
|
||||||
|
};
|
||||||
|
#if 0
|
||||||
|
printf("Retrieving %f\n", amplitude_that_reaches_noise_floor);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* voice->attenuation_min is a lower boundary for the attenuation
|
/* voice->attenuation_min is a lower boundary for the attenuation
|
||||||
* now and in the future (possibly 0 in the worst case). Now the
|
* now and in the future (possibly 0 in the worst case). Now the
|
||||||
|
@ -524,7 +538,9 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
* can safely turn off the voice. Duh. */
|
* can safely turn off the voice. Duh. */
|
||||||
if (amp_max < amplitude_that_reaches_noise_floor){
|
if (amp_max < amplitude_that_reaches_noise_floor){
|
||||||
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
|
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
|
||||||
/* printf("Voice turned off! Amp is %f\n", amp_max); */
|
#if 0
|
||||||
|
printf("Voice turned off! Amp is %f\n", amp_max);
|
||||||
|
#endif
|
||||||
fluid_voice_off(voice);
|
fluid_voice_off(voice);
|
||||||
goto post_process;
|
goto post_process;
|
||||||
}
|
}
|
||||||
|
@ -705,7 +721,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* At which index does the loop point occur in the output buffer?
|
/* At which index does the loop point occur in the output buffer?
|
||||||
* This calculates the first index in the buffer, which uses
|
* This calculates the first index in the buffer, which uses
|
||||||
* sample data taken after the looparound. */
|
* sample data taken after the looparound. */
|
||||||
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loop_end_offset, incr);
|
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loop_end, incr);
|
||||||
|
|
||||||
if (end_in_buffer >= FLUID_BUFSIZE) {
|
if (end_in_buffer >= FLUID_BUFSIZE) {
|
||||||
/* The loop occurs after the end of the buffer.
|
/* The loop occurs after the end of the buffer.
|
||||||
|
@ -731,11 +747,11 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
#include "fluid_dsp_core.c"
|
#include "fluid_dsp_core.c"
|
||||||
|
|
||||||
/* loop */
|
/* loop */
|
||||||
fluid_phase_sub_int(dsp_phase, voice->loop_end_offset - voice->loop_start_offset);
|
fluid_phase_sub_int(dsp_phase, voice->loop_end - voice->loop_start);
|
||||||
voice->has_looped=1;
|
|
||||||
start = end_in_buffer;
|
start = end_in_buffer;
|
||||||
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loop_end_offset, incr);
|
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loop_end, incr);
|
||||||
}
|
}
|
||||||
|
voice->has_looped=1;
|
||||||
dsp_start = start;
|
dsp_start = start;
|
||||||
dsp_end = FLUID_BUFSIZE;
|
dsp_end = FLUID_BUFSIZE;
|
||||||
#include "fluid_dsp_core.c"
|
#include "fluid_dsp_core.c"
|
||||||
|
@ -745,7 +761,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* Not looping right now. */
|
/* Not looping right now. */
|
||||||
|
|
||||||
dsp_start = 0;
|
dsp_start = 0;
|
||||||
end_in_buffer = fluid_phase_steps(dsp_phase, voice->end_offset, incr);
|
end_in_buffer = fluid_phase_steps(dsp_phase, voice->sample_end, incr);
|
||||||
|
|
||||||
if (end_in_buffer >= FLUID_BUFSIZE) {
|
if (end_in_buffer >= FLUID_BUFSIZE) {
|
||||||
/* Run the whole buffer at once */
|
/* Run the whole buffer at once */
|
||||||
|
@ -813,7 +829,6 @@ void fluid_voice_start(fluid_voice_t* voice)
|
||||||
|
|
||||||
voice->ref = fluid_profile_ref();
|
voice->ref = fluid_profile_ref();
|
||||||
|
|
||||||
fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(voice);
|
|
||||||
voice->status = FLUID_VOICE_ON;
|
voice->status = FLUID_VOICE_ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1271,7 +1286,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */
|
case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */
|
||||||
case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
|
case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->start_offset = (voice->sample->start
|
voice->sample_start = (voice->sample->start
|
||||||
+ (int) _GEN(voice, GEN_STARTADDROFS)
|
+ (int) _GEN(voice, GEN_STARTADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_STARTADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_STARTADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1280,7 +1295,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */
|
case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */
|
||||||
case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
|
case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->end_offset = (voice->sample->end
|
voice->sample_end = (voice->sample->end
|
||||||
+ (int) _GEN(voice, GEN_ENDADDROFS)
|
+ (int) _GEN(voice, GEN_ENDADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_ENDADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_ENDADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1289,7 +1304,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */
|
case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */
|
||||||
case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
|
case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->loop_start_offset = (voice->sample->loopstart
|
voice->loop_start = (voice->sample->loopstart
|
||||||
+ (int) _GEN(voice, GEN_STARTLOOPADDROFS)
|
+ (int) _GEN(voice, GEN_STARTLOOPADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_STARTLOOPADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_STARTLOOPADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1299,7 +1314,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */
|
case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */
|
||||||
case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
|
case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->loop_end_offset = (voice->sample->loopend
|
voice->loop_end = (voice->sample->loopend
|
||||||
+ (int) _GEN(voice, GEN_ENDLOOPADDROFS)
|
+ (int) _GEN(voice, GEN_ENDLOOPADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_ENDLOOPADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_ENDLOOPADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1781,91 +1796,6 @@ fluid_real_t fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice
|
||||||
return lower_bound;
|
return lower_bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample
|
|
||||||
*
|
|
||||||
* Purpose:
|
|
||||||
*
|
|
||||||
* Determines the factor, that will drop the amplitude of the sample's
|
|
||||||
* loop to the noise floor. Typically, the algorithm is run only once
|
|
||||||
* for each sample, then the result is cached in the sample structure.
|
|
||||||
*/
|
|
||||||
fluid_real_t
|
|
||||||
fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(fluid_voice_t* voice)
|
|
||||||
{
|
|
||||||
fluid_sample_t* s = voice->sample;
|
|
||||||
int voiceloop_differs_from_sampleloop = 0;
|
|
||||||
fluid_real_t result;
|
|
||||||
|
|
||||||
fluid_check_fpe("voice_determine_amplitude_that_reaches_noise_floor start");
|
|
||||||
if (s == NULL || !s->valid){
|
|
||||||
/* The voice has no sample. Therefore an arbitrarily high
|
|
||||||
* amplitude will make the resulting signal drop below the noise
|
|
||||||
* floor => return a high number */
|
|
||||||
return 999.;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modulators can modify the loop parameters of a sample at playing
|
|
||||||
* time. In this case, the maximum amplitude of the loop will
|
|
||||||
* probably vary. Usually a voice uses the loop settings from the
|
|
||||||
* instrument without altering them. Caching works only in this
|
|
||||||
* case. */
|
|
||||||
if (((int)s->loopstart != voice->loop_start_offset)
|
|
||||||
|| ((int) s->loopend != voice->loop_end_offset)) {
|
|
||||||
voiceloop_differs_from_sampleloop=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s->amplitude_that_reaches_noise_floor_is_valid || voiceloop_differs_from_sampleloop) {
|
|
||||||
signed short peak_max = 0;
|
|
||||||
signed short peak_min = 0;
|
|
||||||
signed short peak;
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
/* SF specs: The first and last sample is identical. Therefore process start .. end-1. */
|
|
||||||
for (offset = voice->loop_start_offset; offset < voice->loop_end_offset; offset++){
|
|
||||||
signed short val = s->data[offset];
|
|
||||||
if (val > peak_max) {
|
|
||||||
peak_max = val;
|
|
||||||
} else if (val < peak_min) {
|
|
||||||
peak_min = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (peak_max >- peak_min){
|
|
||||||
peak = peak_max;
|
|
||||||
} else {
|
|
||||||
peak =- peak_min;
|
|
||||||
}
|
|
||||||
if (peak == 0){
|
|
||||||
/* The sample is empty. Turn off directly when reaching the loop
|
|
||||||
* by setting a threshold, that is higher than the highest
|
|
||||||
* possible total gain of 1. Note: not terminating an empty
|
|
||||||
* sample will crash the DSP loop! */
|
|
||||||
result = 999.;
|
|
||||||
} else {
|
|
||||||
/* For example: Take a peak of 3277 (10 % of 32768). The
|
|
||||||
* normalized amplitude is 0.1 (10 % of 32768). An amplitude
|
|
||||||
* factor of 0.0001 (as opposed to the default 0.00001) will
|
|
||||||
* drop this sample to the noise floor.
|
|
||||||
*/
|
|
||||||
fluid_real_t normalized_amplitude_during_loop=((fluid_real_t)peak)/32768.;
|
|
||||||
result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop;
|
|
||||||
if (!voiceloop_differs_from_sampleloop){
|
|
||||||
/* Cache value in sample */
|
|
||||||
s->amplitude_that_reaches_noise_floor = (double)result;
|
|
||||||
s->amplitude_that_reaches_noise_floor_is_valid = 1;
|
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop peak detection: smallest reasonable gain is %f, cached", result); */
|
|
||||||
} else {
|
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop peak detection: smallest reasonable gain is %f, not cached", result); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Recall cached value from sample*/
|
|
||||||
result = (fluid_real_t) s->amplitude_that_reaches_noise_floor;
|
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop peak detection: smallest reasonable gain is %f, recalled from cache", result); */
|
|
||||||
}
|
|
||||||
fluid_check_fpe("voice_determine_amplitude_that_reaches_noise_floor");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Purpose:
|
/* Purpose:
|
||||||
*
|
*
|
||||||
|
@ -1889,34 +1819,34 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
#if 0
|
#if 0
|
||||||
printf("Sample from %i to %i\n",voice->sample->start, voice->sample->end);
|
printf("Sample from %i to %i\n",voice->sample->start, voice->sample->end);
|
||||||
printf("Sample loop from %i %i\n",voice->sample->loopstart, voice->sample->loopend);
|
printf("Sample loop from %i %i\n",voice->sample->loopstart, voice->sample->loopend);
|
||||||
printf("Playback from %i to %i\n", voice->start_offset, voice->end_offset);
|
printf("Playback from %i to %i\n", voice->sample_start, voice->sample_end);
|
||||||
printf("Playback loop from %i to %i\n",voice->loop_start_offset, voice->loop_end_offset);
|
printf("Playback loop from %i to %i\n",voice->loop_start, voice->loop_end);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Keep the start point within the sample data */
|
/* Keep the start point within the sample data */
|
||||||
if (voice->start_offset < min_index_nonloop){
|
if (voice->sample_start < min_index_nonloop){
|
||||||
voice->start_offset = min_index_nonloop;
|
voice->sample_start = min_index_nonloop;
|
||||||
} else if (voice->start_offset > max_index_nonloop){
|
} else if (voice->sample_start > max_index_nonloop){
|
||||||
voice->start_offset = max_index_nonloop;
|
voice->sample_start = max_index_nonloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the end point within the sample data */
|
/* Keep the end point within the sample data */
|
||||||
if (voice->end_offset < min_index_nonloop){
|
if (voice->sample_end < min_index_nonloop){
|
||||||
voice->end_offset = min_index_nonloop;
|
voice->sample_end = min_index_nonloop;
|
||||||
} else if (voice->end_offset > max_index_nonloop){
|
} else if (voice->sample_end > max_index_nonloop){
|
||||||
voice->end_offset = max_index_nonloop;
|
voice->sample_end = max_index_nonloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep start and end point in the right order */
|
/* Keep start and end point in the right order */
|
||||||
if (voice->start_offset > voice->end_offset){
|
if (voice->sample_start > voice->sample_end){
|
||||||
int temp = voice->start_offset;
|
int temp = voice->sample_start;
|
||||||
voice->start_offset = voice->end_offset;
|
voice->sample_start = voice->sample_end;
|
||||||
voice->end_offset = temp;
|
voice->sample_end = temp;
|
||||||
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
|
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zero length? */
|
/* Zero length? */
|
||||||
if (voice->start_offset == voice->end_offset){
|
if (voice->sample_start == voice->sample_end){
|
||||||
fluid_voice_off(voice);
|
fluid_voice_off(voice);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1924,31 +1854,45 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
if ((_SAMPLEMODE(voice) == FLUID_LOOP)
|
if ((_SAMPLEMODE(voice) == FLUID_LOOP)
|
||||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
||||||
/* Keep the loop start point within the sample data */
|
/* Keep the loop start point within the sample data */
|
||||||
if (voice->loop_start_offset < min_index_loop){
|
if (voice->loop_start < min_index_loop){
|
||||||
voice->loop_start_offset = min_index_loop;
|
voice->loop_start = min_index_loop;
|
||||||
} else if (voice->loop_start_offset > max_index_loop){
|
} else if (voice->loop_start > max_index_loop){
|
||||||
voice->loop_start_offset = max_index_loop;
|
voice->loop_start = max_index_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the loop end point within the sample data */
|
/* Keep the loop end point within the sample data */
|
||||||
if (voice->loop_end_offset < min_index_loop){
|
if (voice->loop_end < min_index_loop){
|
||||||
voice->loop_end_offset = min_index_loop;
|
voice->loop_end = min_index_loop;
|
||||||
} else if (voice->loop_end_offset > max_index_loop){
|
} else if (voice->loop_end > max_index_loop){
|
||||||
voice->loop_end_offset = max_index_loop;
|
voice->loop_end = max_index_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep loop start and end point in the right order */
|
/* Keep loop start and end point in the right order */
|
||||||
if (voice->loop_start_offset > voice->loop_end_offset){
|
if (voice->loop_start > voice->loop_end){
|
||||||
int temp=voice->loop_start_offset;
|
int temp=voice->loop_start;
|
||||||
voice->loop_start_offset=voice->loop_end_offset;
|
voice->loop_start=voice->loop_end;
|
||||||
voice->loop_end_offset=temp;
|
voice->loop_end=temp;
|
||||||
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
|
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop too short? Then don't loop. */
|
/* Loop too short? Then don't loop. */
|
||||||
if (voice->loop_end_offset < voice->loop_start_offset + FLUID_MIN_LOOP_SIZE){
|
if (voice->loop_end < voice->loop_start + FLUID_MIN_LOOP_SIZE){
|
||||||
voice->gen[GEN_SAMPLEMODE].val=FLUID_UNLOOPED;
|
voice->gen[GEN_SAMPLEMODE].val=FLUID_UNLOOPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The loop points may have changed. Obtain a new estimate for the loop volume. */
|
||||||
|
/* Is the voice loop within the sample loop? */
|
||||||
|
if ((int)voice->loop_start >= (int)voice->sample->loopstart
|
||||||
|
&& (int)voice->loop_end <= (int)voice->sample->loopend){
|
||||||
|
/* Is there a valid peak amplitude available for the loop? */
|
||||||
|
if (voice->sample->amplitude_that_reaches_noise_floor_is_valid){
|
||||||
|
voice->amplitude_that_reaches_noise_floor_loop=voice->sample->amplitude_that_reaches_noise_floor / voice->synth_gain;
|
||||||
|
} else {
|
||||||
|
/* Worst case */
|
||||||
|
voice->amplitude_that_reaches_noise_floor_loop=voice->amplitude_that_reaches_noise_floor_nonloop;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
} /* if sample mode is looped */
|
} /* if sample mode is looped */
|
||||||
|
|
||||||
/* Run startup specific code (only once, when the voice is started) */
|
/* Run startup specific code (only once, when the voice is started) */
|
||||||
|
@ -1962,7 +1906,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
|
|
||||||
/* Set the initial phase of the voice (using the result from the
|
/* Set the initial phase of the voice (using the result from the
|
||||||
start offset modulators). */
|
start offset modulators). */
|
||||||
fluid_phase_set_int(voice->phase, voice->start_offset);
|
fluid_phase_set_int(voice->phase, voice->sample_start);
|
||||||
} /* if startup */
|
} /* if startup */
|
||||||
|
|
||||||
/* Is this voice run in loop mode, or does it run straight to the
|
/* Is this voice run in loop mode, or does it run straight to the
|
||||||
|
@ -1982,40 +1926,18 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
* actions required.
|
* actions required.
|
||||||
*/
|
*/
|
||||||
int index_in_sample = fluid_phase_index(voice->phase);
|
int index_in_sample = fluid_phase_index(voice->phase);
|
||||||
if (index_in_sample >= voice->loop_end_offset){
|
if (index_in_sample >= voice->loop_end){
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
|
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
|
||||||
fluid_phase_set_int(voice->phase,voice->loop_start_offset);
|
fluid_phase_set_int(voice->phase,voice->loop_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->start_offset, voice->end_offset, voice->loop_start_offset, voice->loop_end_offset); */
|
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->sample_start, voice->sample_end, voice->loop_start, voice->loop_end); */
|
||||||
|
|
||||||
/* If the peak volume during the loop is known, then the voice can
|
|
||||||
* be released earlier during the release phase. Otherwise, the
|
|
||||||
* voice will operate (inaudibly), until the envelope is at the
|
|
||||||
* nominal turnoff point. In many cases the loop volume is many dB
|
|
||||||
* below the maximum volume. For example, the loop volume for a
|
|
||||||
* typical acoustic piano is 20 dB below max. Taking that into
|
|
||||||
* account in the turn-off algorithm we can save 20 dB / 100 dB =>
|
|
||||||
* 1/5 of the total release time. */
|
|
||||||
#if 1
|
|
||||||
{
|
|
||||||
fluid_real_t a = fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(voice);
|
|
||||||
/* if for example the synth has a gain of 0.1, the noise floor
|
|
||||||
comes up by a factor of 10. */
|
|
||||||
voice->amplitude_that_reaches_noise_floor = a / voice->synth_gain;
|
|
||||||
/* printf("Voice: smallest reasonable voice amplitude is %f\n", voice->amplitude_that_reaches_noise_floor); */
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Sample-dependent voice-turnoff disabled. Do nothing here. The
|
|
||||||
* default value for 'voice->amplitude_that_reaches_noise_floor'
|
|
||||||
* works fine. It's just inefficient.*/
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Sample sanity has been assured. Don't check again, until some
|
/* Sample sanity has been assured. Don't check again, until some
|
||||||
sample parameter is changed by modulation. */
|
sample parameter is changed by modulation. */
|
||||||
voice->check_sample_sanity_flag=0;
|
voice->check_sample_sanity_flag=0;
|
||||||
#if 0
|
#if 0
|
||||||
printf("Sane? playback loop from %i to %i\n",voice->loop_start_offset, voice->loop_end_offset);
|
printf("Sane? playback loop from %i to %i\n",voice->loop_start, voice->loop_end);
|
||||||
#endif
|
#endif
|
||||||
fluid_check_fpe("voice_check_sample_sanity");
|
fluid_check_fpe("voice_check_sample_sanity");
|
||||||
}
|
}
|
||||||
|
@ -2043,3 +1965,61 @@ int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain)
|
||||||
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* - Scan the loop
|
||||||
|
* - determine the peak level
|
||||||
|
* - Calculate, what factor will make the loop inaudible
|
||||||
|
* - Store in sample
|
||||||
|
*/
|
||||||
|
int fluid_voice_optimize_sample(fluid_sample_t* s)
|
||||||
|
{
|
||||||
|
signed short peak_max = 0;
|
||||||
|
signed short peak_min = 0;
|
||||||
|
signed short peak;
|
||||||
|
double result;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!s->amplitude_that_reaches_noise_floor_is_valid){ /* Only once */
|
||||||
|
/* Scan the loop */
|
||||||
|
for (i = (int)s->loopstart; i < (int) s->loopend; i ++){
|
||||||
|
signed short val = s->data[i];
|
||||||
|
if (val > peak_max) {
|
||||||
|
peak_max = val;
|
||||||
|
} else if (val < peak_min) {
|
||||||
|
peak_min = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the peak level */
|
||||||
|
if (peak_max >- peak_min){
|
||||||
|
peak = peak_max;
|
||||||
|
} else {
|
||||||
|
peak =- peak_min;
|
||||||
|
};
|
||||||
|
if (peak == 0){
|
||||||
|
/* Avoid division by zero */
|
||||||
|
peak = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Calculate what factor will make the loop inaudible
|
||||||
|
* For example: Take a peak of 3277 (10 % of 32768). The
|
||||||
|
* normalized amplitude is 0.1 (10 % of 32768). An amplitude
|
||||||
|
* factor of 0.0001 (as opposed to the default 0.00001) will
|
||||||
|
* drop this sample to the noise floor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 16 bits => 96+4=100 dB dynamic range => 0.00001 */
|
||||||
|
fluid_real_t normalized_amplitude_during_loop=((fluid_real_t)peak)/32768.;
|
||||||
|
result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop;
|
||||||
|
|
||||||
|
/* Store in sample */
|
||||||
|
s->amplitude_that_reaches_noise_floor = (double)result;
|
||||||
|
s->amplitude_that_reaches_noise_floor_is_valid = 1;
|
||||||
|
#if 0
|
||||||
|
printf("Sample peak detection: factor %f\n", (double)result);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
return FLUID_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -106,10 +106,10 @@ struct _fluid_voice_t
|
||||||
fluid_real_t root_pitch;
|
fluid_real_t root_pitch;
|
||||||
|
|
||||||
/* sample and loop start and end points (offset in sample memory) */
|
/* sample and loop start and end points (offset in sample memory) */
|
||||||
int start_offset;
|
int sample_start;
|
||||||
int end_offset;
|
int sample_end;
|
||||||
int loop_start_offset;
|
int loop_start;
|
||||||
int loop_end_offset;
|
int loop_end;
|
||||||
|
|
||||||
/* master gain */
|
/* master gain */
|
||||||
fluid_real_t synth_gain;
|
fluid_real_t synth_gain;
|
||||||
|
@ -119,7 +119,8 @@ struct _fluid_voice_t
|
||||||
unsigned int volenv_count;
|
unsigned int volenv_count;
|
||||||
int volenv_section;
|
int volenv_section;
|
||||||
fluid_real_t volenv_val;
|
fluid_real_t volenv_val;
|
||||||
fluid_real_t amplitude_that_reaches_noise_floor;
|
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
|
||||||
|
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
||||||
|
|
||||||
/* mod env */
|
/* mod env */
|
||||||
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
|
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
|
||||||
|
@ -230,7 +231,6 @@ int fluid_voice_kill_excl(fluid_voice_t* voice);
|
||||||
fluid_real_t fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
|
fluid_real_t fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
|
||||||
fluid_real_t fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(fluid_voice_t* voice);
|
fluid_real_t fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(fluid_voice_t* voice);
|
||||||
void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
|
void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
|
||||||
void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
|
|
||||||
|
|
||||||
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
|
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
|
||||||
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
||||||
|
|
|
@ -119,18 +119,27 @@ void process_o_cmd_line_option(fluid_settings_t* settings, char* optarg){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't know the type of the setting in question. So try
|
/* At this point:
|
||||||
* all types. The wrong types will fail.
|
* optarg => "synth.polyphony"
|
||||||
|
* val => "16"
|
||||||
*/
|
*/
|
||||||
if (fluid_settings_setnum(settings, optarg, atof(val))){
|
switch(fluid_settings_get_type(settings, optarg)){
|
||||||
printf("set %s to %s (float type)\n", optarg, val);
|
case FLUID_NUM_TYPE:
|
||||||
} else if (fluid_settings_setint(settings, optarg, atoi(val))){
|
if (fluid_settings_setnum(settings, optarg, atof(val))){
|
||||||
printf("set %s to %s (int type)\n", optarg, val);
|
break;
|
||||||
} else if (fluid_settings_setstr(settings, optarg, val)){
|
};
|
||||||
printf("set %s to %s (string type)\n", optarg, val);
|
case FLUID_INT_TYPE:
|
||||||
} else {
|
if (fluid_settings_setint(settings, optarg, atoi(val))){
|
||||||
printf("Failed to set %s to %s\n", optarg, val);
|
break;
|
||||||
};
|
};
|
||||||
|
case FLUID_STR_TYPE:
|
||||||
|
if (fluid_settings_setstr(settings, optarg, val)){
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
fprintf (stderr, "Settings argument on command line: Failed to set \"%s\" to \"%s\".\n"
|
||||||
|
"Most likely the parameter \"%s\" does not exist.\n", optarg, val, optarg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue