Changed volume attenuation calculation to match popular EMU devices, run

time polyphony modification, MOD LFO to volume was inverted, some bug
fixes.
This commit is contained in:
Element Green 2005-06-08 03:51:13 +00:00
parent 1f987a539e
commit 37d805cb0f
10 changed files with 147 additions and 67 deletions

View file

@ -1,3 +1,34 @@
2005-06-07 <jgreen@users.sourceforge.net>
* Applied Sean Bolton's DSSI patch (SB patch) which adds the ability to
change polyphony at runtime and fixes a bug (see below).
* README-OSX: Update from Ebrahim Mayat for OSX Panther.
* include/fluidsynth/synth.h: Sean Bolton's DSSI patch adds two new
functions fluid_synth_set_polyphony and fluid_synth_get_polyphony.
* src/fluid_conv.c: Centibel to amplitude conversion now follows
EMU 8k/10k which is contrary to SoundFont specification (TiMidity++
used as an example).
* src/fluid_conv.h: FLUID_CB_POWER_FACTOR defined for the centibel->amp
conversion table equation.
* src/fluid_defsfont.c (load_pgen): Fixed 'use of cast expressions as
lvalues is deprecated' warning by casting the value being assigned
instead of the variable assigned to and removed code warrior
specific code to work around this.
(load_igen): Same as for load_pgen.
* src/fluid_synth.c: SB patch - uses synth->polyphony instead of
synth->nvoice when iterating over the synth's voices.
(fluid_synth_update_polyphony): SB patch (new) - runtime update
(fluid_synth_set_polyphony): SB patch (new)
(fluid_synth_get_polyphony): SB patch (new)
(fluid_synth_nwrite_float): SB patch - fixes bug where the use of
arbitrary values of the 'len' parameter was broken.
* src/fluid_voice.c (fluid_voice_write): modlfo_to_vol (modulation LFO
to volume) was being calculated inverted (should be negative
attenuation, gain, for a positive rise in LFO).
(fluid_voice_noteoff): Updated centibel to amplitude conversion
used when voice off during attack to use the new
FLUID_CB_POWER_FACTOR.
2004-11-11 <jgreen@users.sourceforge.net>
* README-OSX: Update from Ebrahim Mayat.
@ -1223,4 +1254,3 @@
select between alsa, oss, midishare, directx, ...
* configure.in: preparing for the first pre-release, version 0.0.1

View file

@ -1,11 +1,11 @@
Compiling fluidsynth-1.0.5 on Mac OS X.3.5
Compiling fluidsynth-1.0.5 on Mac OS X.4 (Tiger)
--------------------------------------------
1. Install Apple's Developer Tools.
2. Install the Fink Project's Package manager, fink, obtainable at http://fink.sourceforge.net
3. Compile and install gnugetopt, readline, ladspa and ladspa-cmt from fink: e.g.
fink install gnugetopt
3. Compile and install libgnugetopt-1.2, readline-4.3, ladspa-1.12 and ladspa-cmt-1.15 from fink: e.g.
fink install libgnugetopt
4. Install MidiShare-1.87 for Mac OS X available from
http://www.grame.fr/MidiShare/
@ -16,8 +16,7 @@ Compiling fluidsynth-1.0.5 on Mac OS X.3.5
6. Edit the "/usr/local/lib/pkgconfig/jack.pc" file using your favorite Unix editor:
In the "Libs" line, replace "ljack" with "-framework Jack"
7. cd to the fluidsynth directory and in the configure script, substitute "-lmidishare" with
"-framework MidiShare".
7. cd to the fluidsynth directory and in the configure script, substitute "-lmidishare" with "-framework MidiShare".
8. Run configure with the following options (all on one line in a text editor, then copy and paste into Terminal):
./configure --enable-midishare --enable-ladspa --enable-functioncheck --enable-debug --enable-profiling --enable-jack-support "CPPFLAGS=-I/usr/local/include -I/sw/include -I/sw/include/liboss -I/System/Library/Frameworks/MidiShare.framework/Versions/A/Headers -I/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers -I/Library/Frameworks/Jack.framework/Headers" "LDFLAGS=-L/usr/local/lib -L/sw/lib -framework MidiShare -framework CoreAudio -framework Jack"
@ -43,6 +42,6 @@ Pentium 3+ SSE: no
8. make install as root.
Ebrahim Mayat <ebmayat@mac.com>
4th November 2004
Ebrahim Mayat <emayat@users.sourceforge.net>
19th May 2005

View file

@ -368,6 +368,12 @@ FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
/** Get the master gain */
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
/** Set the polyphony limit */
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
/** Get the polyphony limit */
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
/** Get the internal buffer size. The internal buffer size if not the
same thing as the buffer size specified in the
settings. Internally, the synth *always* uses a specific buffer

View file

@ -48,10 +48,14 @@ fluid_conversion_config(void)
* Note: SF2.01 section 8.1.3: Initial attenuation range is
* between 0 and 144 dB. Therefore a negative attenuation is
* not allowed.
*
* WARNING!! EMU8k and EMU10k devices don't conform to the SoundFont
* specification in regards to the attenuation. The below calculation
* is an approx. equation for generating a table equivelant to the
* cb_to_amp_table[] in tables.c of the TiMidity++ source.
*/
for (i = 0; i < FLUID_CB_AMP_SIZE; i++) {
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_CB_POWER_FACTOR);
}
/* initialize the conversion tables (see fluid_mod.c

View file

@ -28,6 +28,11 @@
#define FLUID_CB_AMP_SIZE 961
#define FLUID_PAN_SIZE 1002
/* EMU 8k/10k don't follow spec in regards to volume attenuation in centibels.
* This factor is used in the equation pow (10.0, cb / FLUID_CB_AMP_POWER_FACTOR).
* By the standard this should be -200.0. */
#define FLUID_CB_POWER_FACTOR (-531.509)
void fluid_conversion_config(void);
fluid_real_t fluid_ct2hz(fluid_real_t cents);

View file

@ -2347,13 +2347,7 @@ load_pgen (int size, SFData * sf, FILE * fd)
{ /* inst is last gen */
level = 3;
READW (genval.uword, fd);
#ifndef MACINTOSH
GPOINTER_TO_INT (((SFZone *) (p2->data))->instsamp) = genval.uword + 1;
#else
/* the codewarrior compiler doesn't seem to accepts the construct
above (not an lvalue), so i do it the other way around */
((SFZone *) (p2->data))->instsamp = (fluid_list_t *) (genval.uword + 1);
#endif
((SFZone *) (p2->data))->instsamp = GINT_TO_POINTER (genval.uword + 1);
break; /* break out of generator loop */
}
else
@ -2703,13 +2697,7 @@ load_igen (int size, SFData * sf, FILE * fd)
{ /* sample is last gen */
level = 3;
READW (genval.uword, fd);
#ifndef MACINTOSH
GPOINTER_TO_INT (((SFZone *) (p2->data))->instsamp) = genval.uword + 1;
#else
/* the codewarrior compiler doesn't seem to accepts the construct
above (not an lvalue), so i do it the other way around */
((SFZone *) (p2->data))->instsamp = (fluid_list_t *) (genval.uword + 1);
#endif
((SFZone *) (p2->data))->instsamp = GINT_TO_POINTER (genval.uword + 1);
break; /* break out of generator loop */
}
else
@ -3201,5 +3189,3 @@ safe_malloc (size_t size)
FLUID_LOG (FLUID_ERR, _("Attempted to allocate %d bytes"), (int) size);
return (ptr);
}

View file

@ -341,6 +341,7 @@ SFData *sfload_file (const char * fname);
#endif
#define GPOINTER_TO_INT(p) ((int) (p))
#define GINT_TO_POINTER(i) ((void *) (i))
char* g_strdup (const char *str);

View file

@ -371,6 +371,10 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_register_num(settings, "synth.gain",
0.2f, 0.0f, 10.0f, 0,
(fluid_num_update_t) fluid_synth_update_gain, synth);
fluid_settings_register_int(settings, "synth.polyphony",
synth->polyphony, 16, 4096, 0,
(fluid_int_update_t) fluid_synth_update_polyphony,
synth);
/* do some basic sanity checking on the settings */
@ -776,13 +780,13 @@ fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
/* 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->polyphony; i++) {
voice = synth->voice[i];
if (_ON(voice) && (voice->chan == chan) && (voice->key == key)) {
if (synth->verbose) {
int used_voices = 0;
int k;
for (k = 0; k < synth->nvoice; k++) {
for (k = 0; k < synth->polyphony; k++) {
if (!_AVAILABLE(synth->voice[k])) {
used_voices++;
}
@ -813,7 +817,7 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
/* 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->polyphony; i++) {
voice = synth->voice[i];
if ((voice->chan == chan) && _SUSTAINED(voice)) {
/* printf("turned off sustained note: chan=%d, key=%d, vel=%d\n", voice->chan, voice->key, voice->vel); */
@ -888,7 +892,7 @@ fluid_synth_all_notes_off(fluid_synth_t* synth, int chan)
int i;
fluid_voice_t* voice;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (_PLAYING(voice) && (voice->chan == chan)) {
fluid_voice_noteoff(voice);
@ -900,7 +904,7 @@ fluid_synth_all_notes_off(fluid_synth_t* synth, int chan)
/*
* fluid_synth_all_sounds_off
*
* put all notes on this channel into released state.
* immediately stop all notes on this channel.
*/
int
fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan)
@ -908,7 +912,7 @@ fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan)
int i;
fluid_voice_t* voice;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (_PLAYING(voice) && (voice->chan == chan)) {
fluid_voice_off(voice);
@ -929,7 +933,7 @@ fluid_synth_system_reset(fluid_synth_t* synth)
int i;
fluid_voice_t* voice;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (_PLAYING(voice)) {
fluid_voice_off(voice);
@ -961,7 +965,7 @@ fluid_synth_modulate_voices(fluid_synth_t* synth, int chan, int is_cc, int ctrl)
/* 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->polyphony; i++) {
voice = synth->voice[i];
if (voice->chan == chan) {
fluid_voice_modulate(voice, is_cc, ctrl);
@ -986,7 +990,7 @@ fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan)
/* 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->polyphony; i++) {
voice = synth->voice[i];
if (voice->chan == chan) {
fluid_voice_modulate_all(voice);
@ -1374,7 +1378,7 @@ void fluid_synth_set_gain(fluid_synth_t* synth, float gain)
fluid_clip(gain, 0.0f, 10.0f);
synth->gain = gain;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
fluid_voice_t* voice = synth->voice[i];
if (_PLAYING(voice)) {
fluid_voice_set_gain(voice, gain);
@ -1390,6 +1394,47 @@ float fluid_synth_get_gain(fluid_synth_t* synth)
return synth->gain;
}
/*
* fluid_synth_update_polyphony
*/
int fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value)
{
fluid_synth_set_polyphony(synth, value);
return 0;
}
/*
* fluid_synth_set_polyphony
*/
int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony)
{
int i;
if (polyphony < 1 || polyphony > synth->nvoice) {
return FLUID_FAILED;
}
/* turn off any voices above the new limit */
for (i = polyphony; i < synth->nvoice; i++) {
fluid_voice_t* voice = synth->voice[i];
if (_PLAYING(voice)) {
fluid_voice_off(voice);
}
}
synth->polyphony = polyphony;
return FLUID_OK;
}
/*
* fluid_synth_get_polyphony
*/
int fluid_synth_get_polyphony(fluid_synth_t* synth)
{
return synth->polyphony;
}
/*
* fluid_synth_get_internal_buffer_size
*/
@ -1537,20 +1582,24 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
/* First, take what's still available in the buffer */
count = 0;
available = FLUID_BUFSIZE - synth->cur;
num = synth->cur;
if (synth->cur < FLUID_BUFSIZE) {
available = FLUID_BUFSIZE - synth->cur;
num = (available > len)? len : available;
bytes = num * sizeof(float);
num = (available > len)? len : available;
bytes = num * sizeof(float);
for (i = 0; i < synth->audio_channels; i++) {
FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes);
FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes);
for (i = 0; i < synth->audio_channels; i++) {
FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes);
FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes);
}
for (i = 0; i < synth->effects_channels; i++) {
FLUID_MEMCPY(fx_left[i], fx_left_in[i] + synth->cur, bytes);
FLUID_MEMCPY(fx_right[i], fx_right_in[i] + synth->cur, bytes);
}
count += num;
num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
}
for (i = 0; i < synth->effects_channels; i++) {
FLUID_MEMCPY(fx_left[i], fx_left_in[i] + synth->cur, bytes);
FLUID_MEMCPY(fx_right[i], fx_right_in[i] + synth->cur, bytes);
}
count += num;
/* Then, run one_block() and copy till we have 'len' samples */
while (count < len) {
@ -1756,7 +1805,7 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref);
/* call all playing synthesis processes */
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (_PLAYING(voice)) {
@ -1869,7 +1918,7 @@ fluid_synth_free_voice_by_kill(fluid_synth_t* synth)
/* 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->polyphony; i++) {
voice = synth->voice[i];
@ -1951,7 +2000,7 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
/* fluid_mutex_unlock(synth->busy); */
/* check if there's an available synthesis process */
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
if (_AVAILABLE(synth->voice[i])) {
voice = synth->voice[i];
break;
@ -1970,7 +2019,7 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
if (synth->verbose) {
k = 0;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
if (!_AVAILABLE(synth->voice[i])) {
k++;
}
@ -2039,7 +2088,7 @@ void fluid_synth_kill_by_exclusive_class(fluid_synth_t* synth, fluid_voice_t* ne
/* Kill all notes on the same channel with the same exclusive class */
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
fluid_voice_t* existing_voice = synth->voice[i];
/* Existing voice does not play? Leave it alone. */
@ -2385,7 +2434,7 @@ fluid_synth_get_voicelist(fluid_synth_t* synth, fluid_voice_t* buf[], int bufsiz
{
int i;
int count = 0;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
fluid_voice_t* voice = synth->voice[i];
if (count >= bufsize) {
return;
@ -2481,7 +2530,7 @@ void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int
/* 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->polyphony; i++) {
voice = synth->voice[i];
if (_PLAYING(voice)
&& (voice->chan == chan)
@ -2804,7 +2853,7 @@ fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value)
fluid_channel_set_gen(synth->channel[chan], param, value, 0);
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (voice->chan == chan) {
fluid_voice_set_param(voice, param, value, 0);
@ -2859,7 +2908,7 @@ fluid_synth_set_gen2(fluid_synth_t* synth, int chan, int param,
fluid_channel_set_gen(synth->channel[chan], param, v, absolute);
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (voice->chan == chan) {
fluid_voice_set_param(voice, param, v, absolute);
@ -2966,7 +3015,7 @@ int fluid_synth_stop(fluid_synth_t* synth, unsigned int id)
int status = FLUID_FAILED;
int count = 0;
for (i = 0; i < synth->nvoice; i++) {
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];

View file

@ -205,6 +205,7 @@ void fluid_synth_update_presets(fluid_synth_t* synth);
int fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value);
int fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value);
fluid_bank_offset_t* fluid_synth_get_bank_offset0(fluid_synth_t* synth, int sfont_id);
void fluid_synth_remove_bank_offset(fluid_synth_t* synth, int sfont_id);

View file

@ -492,15 +492,17 @@ fluid_voice_write(fluid_voice_t* voice,
/* The volume amplitude is in hold phase. No sound is produced. */
goto post_process;
} else if (voice->volenv_section == FLUID_VOICE_ENVATTACK) {
/* the envelope is in the attack section: ramp linearly to max value. */
dsp_amp = (fluid_cb2amp(voice->attenuation + voice->modlfo_val * voice->modlfo_to_vol)
/* the envelope is in the attack section: ramp linearly to max value.
* A positive modlfo_to_vol should increase volume (negative attenuation).
*/
dsp_amp = (fluid_cb2amp(voice->attenuation + voice->modlfo_val * -voice->modlfo_to_vol)
* voice->volenv_val);
} else {
fluid_real_t amplitude_that_reaches_noise_floor;
fluid_real_t amp_max;
dsp_amp = fluid_cb2amp(voice->attenuation
+ 960.0f * (1.0f - voice->volenv_val)
+ voice->modlfo_val * voice->modlfo_to_vol);
+ voice->modlfo_val * -voice->modlfo_to_vol);
/* Here we are trying to turn off a voice, if the volume has dropped
* low enough.
@ -1629,11 +1631,10 @@ fluid_voice_noteoff(fluid_voice_t* voice)
* convert from linear amplitude to cb.
*/
if (voice->volenv_val > 0){
fluid_real_t attn_and_lfo = voice->attenuation + voice->modlfo_val * voice->modlfo_to_vol;
fluid_real_t amp = voice->volenv_val * pow (10.0, attn_and_lfo / -200.0);
fluid_real_t env_value = - ((-200. * log (amp) / log (10.) - attn_and_lfo) / 960.0 - 1);
env_value = (env_value < 0.0 ? 0.0 : env_value);
env_value = (env_value > 1.0 ? 1.0 : env_value);
fluid_real_t attn_and_lfo = voice->attenuation + voice->modlfo_val * -voice->modlfo_to_vol;
fluid_real_t amp = voice->volenv_val * pow (10.0, attn_and_lfo / FLUID_CB_POWER_FACTOR);
fluid_real_t env_value = - ((FLUID_CB_POWER_FACTOR * log (amp) / log (10.) - attn_and_lfo) / 960.0 - 1);
fluid_clip (env_value, 0.0, 1.0);
voice->volenv_val = env_value;
}
}
@ -2080,5 +2081,3 @@ int fluid_voice_optimize_sample(fluid_sample_t* s)
};
return FLUID_OK;
}