diff --git a/fluidsynth/ChangeLog b/fluidsynth/ChangeLog index 97c81db4..ac3e1150 100644 --- a/fluidsynth/ChangeLog +++ b/fluidsynth/ChangeLog @@ -1,3 +1,34 @@ +2005-06-07 + + * 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 * 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 - diff --git a/fluidsynth/README-OSX b/fluidsynth/README-OSX index 565946c0..8ae71562 100644 --- a/fluidsynth/README-OSX +++ b/fluidsynth/README-OSX @@ -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 -4th November 2004 +Ebrahim Mayat +19th May 2005 diff --git a/fluidsynth/include/fluidsynth/synth.h b/fluidsynth/include/fluidsynth/synth.h index 1eddc93b..f6ee18ee 100644 --- a/fluidsynth/include/fluidsynth/synth.h +++ b/fluidsynth/include/fluidsynth/synth.h @@ -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 diff --git a/fluidsynth/src/fluid_conv.c b/fluidsynth/src/fluid_conv.c index 10d936bd..dae85a0c 100644 --- a/fluidsynth/src/fluid_conv.c +++ b/fluidsynth/src/fluid_conv.c @@ -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 diff --git a/fluidsynth/src/fluid_conv.h b/fluidsynth/src/fluid_conv.h index e96b78ea..e2158011 100644 --- a/fluidsynth/src/fluid_conv.h +++ b/fluidsynth/src/fluid_conv.h @@ -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); diff --git a/fluidsynth/src/fluid_defsfont.c b/fluidsynth/src/fluid_defsfont.c index 680ea7bb..2e33a06c 100644 --- a/fluidsynth/src/fluid_defsfont.c +++ b/fluidsynth/src/fluid_defsfont.c @@ -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); } - - diff --git a/fluidsynth/src/fluid_defsfont.h b/fluidsynth/src/fluid_defsfont.h index 2de813ab..844347fc 100644 --- a/fluidsynth/src/fluid_defsfont.h +++ b/fluidsynth/src/fluid_defsfont.h @@ -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); diff --git a/fluidsynth/src/fluid_synth.c b/fluidsynth/src/fluid_synth.c index 6f9cdfe6..e76cdccb 100644 --- a/fluidsynth/src/fluid_synth.c +++ b/fluidsynth/src/fluid_synth.c @@ -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]; diff --git a/fluidsynth/src/fluid_synth.h b/fluidsynth/src/fluid_synth.h index 48c8950c..6be17dbc 100644 --- a/fluidsynth/src/fluid_synth.h +++ b/fluidsynth/src/fluid_synth.h @@ -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); diff --git a/fluidsynth/src/fluid_voice.c b/fluidsynth/src/fluid_voice.c index 353f6108..fbc6ad0f 100644 --- a/fluidsynth/src/fluid_voice.c +++ b/fluidsynth/src/fluid_voice.c @@ -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; } - -