See ChangeLog

This commit is contained in:
Peter Hanappe 2003-04-03 21:32:56 +00:00
parent 52be3cec9a
commit a8f4470fcd
14 changed files with 259 additions and 238 deletions

View file

@ -1,3 +1,20 @@
2003-04-03 Peter Hanappe <peter@hanappe.com>
* src/fluid_rev.c: reverb parameters are clipped to their valid
range.
* src/fluid_alsa.c: using fluid_alsa_audio_run_s16 as default
function. This reduces the high CPU usage.
* src/fluid_voice.c (fluid_voice_write): filter interpolation done
over only 1 buffer to avoid filter instability
* src/fluid_chan.c (fluid_channel_init): bank number set to 128
for the drum channel
* src/fluid_midi.c (fluid_midi_file_read_event): Correctly reading
pitchbend value
2003-02-27 Josh Green <jgreen@users.sourceforge.net>
Updated automake files (automake 1.6).

View file

@ -6,7 +6,7 @@ AC_INIT(src/fluidsynth.c)
FLUIDSYNTH_VERSION_MAJOR=1
FLUIDSYNTH_VERSION_MINOR=0
FLUIDSYNTH_VERSION_MICRO=0
FLUIDSYNTH_VERSION_MICRO=1
FLUIDSYNTH_VERSION=$FLUIDSYNTH_VERSION_MAJOR.$FLUIDSYNTH_VERSION_MINOR.$FLUIDSYNTH_VERSION_MICRO
AC_SUBST(FLUIDSYNTH_VERSION_MAJOR)

View file

@ -1,4 +1,4 @@
# install the man pages and include in distribution
man_MANS = fluidsynth.1
EXTRA_DIST = $(man_MANS) xtrafluid.txt
EXTRA_DIST = $(man_MANS)

View file

@ -89,14 +89,14 @@ struct fluid_alsa_formats_t {
};
struct fluid_alsa_formats_t fluid_alsa_formats[] = {
{ "float, rw, non interleaved",
SND_PCM_FORMAT_FLOAT,
SND_PCM_ACCESS_RW_NONINTERLEAVED,
fluid_alsa_audio_run_float },
{ "s16, rw, interleaved",
SND_PCM_FORMAT_S16,
SND_PCM_ACCESS_RW_INTERLEAVED,
fluid_alsa_audio_run_s16 },
{ "float, rw, non interleaved",
SND_PCM_FORMAT_FLOAT,
SND_PCM_ACCESS_RW_NONINTERLEAVED,
fluid_alsa_audio_run_float },
{ NULL, 0, 0, NULL }
};

View file

@ -52,7 +52,7 @@ void
fluid_channel_init(fluid_channel_t* chan)
{
chan->prognum = (chan->channum == 9)? 0 : chan->channum;
chan->banknum = (chan->channum == 9)? chan->channum : 0;
chan->banknum = (chan->channum == 9)? 128 : 0;
chan->sfontnum = 0;
chan->preset = fluid_synth_find_preset(chan->synth, chan->banknum, chan->prognum);
chan->interp_method = FLUID_INTERP_DEFAULT;

View file

@ -84,10 +84,11 @@
*/
# if defined(WITH_FLOAT)
# define zap_almost_zero(sample) (((*(unsigned int*)&(sample))&0x7f800000) < 0x08000000)?0.0f:(sample)
# define zap_almost_zero(_sample) \
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
# else
/* 1e-20 was chosen as an arbitrary (small) threshold. */
#define zap_almost_zero(sample) abs(sample)<1e-20?0:sample;
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
#endif
/* Interpolation (find a value between two samples of the original waveform) */
@ -333,7 +334,7 @@ if ((fluid_phase_fract(dsp_phase) == 0)
case FLUID_INTERP_7THORDER:
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
int fract=fluid_phase_fract_to_tablerow(dsp_phase);
int fract = fluid_phase_fract_to_tablerow(dsp_phase);
dsp_phase_index = fluid_phase_index(dsp_phase);
dsp_buf[dsp_i] = (dsp_amp *
(sinc_table7[0][fract] * (fluid_real_t) dsp_data[dsp_phase_index]
@ -353,7 +354,6 @@ if ((fluid_phase_fract(dsp_phase) == 0)
} /* switch interpolation method */
} /* If interpolation is needed */
/* filter (implement the voice filter according to Soundfont standard) */
if (dsp_use_filter_flag) {
@ -370,11 +370,7 @@ if (dsp_use_filter_flag) {
if (dsp_filter_coeff_incr_count > 0) {
/* The increment is added to each filter coefficient
filter_coeff_incr_count times. */
dsp_a1_incr = voice->a1_incr;
dsp_a2_incr = voice->a2_incr;
dsp_b02_incr = voice->b02_incr;
dsp_b1_incr = voice->b1_incr;
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
@ -389,11 +385,6 @@ if (dsp_use_filter_flag) {
dsp_b1 += dsp_b1_incr;
}
} /* for dsp_i */
voice->a1 = dsp_a1;
voice->a2 = dsp_a2;
voice->b02 = dsp_b02;
voice->b1 = dsp_b1;
voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
} else {
@ -510,7 +501,7 @@ if ((FLUID_BUFSIZE % 4 == 0)
*/
if ((voice->pan < 0.5) && (voice->pan > -0.5)) {
if ((-0.5 < voice->pan) && (voice->pan < 0.5)) {
/* The voice is centered. Use voice->amp_left twice. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
@ -554,6 +545,7 @@ if ((FLUID_BUFSIZE % 4 == 0)
#endif
#if 0
/* Nonoptimized DSP loop */
#error "This code is meant for experiments only. Probably unmaintained.";
@ -582,56 +574,9 @@ for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_right_buf[dsp_i] += voice->amp_right * dsp_sample;
if (dsp_reverb_buf){
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_sample;
};
}
if (dsp_chorus_buf){
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_sample;
};
};
#endif
/* Some older stuff, obsolete, 'archived' */
#if 0
#define fix1616tof(_v) ((float)((_v >> 16) + (_v & 0xffff) * .0000152587890625f))
/*
* fluid_voice_run_dsp
*/
#define fluid_voice_run_dsp(_start,_len) \
{ \
/* wave table interpolation */ \
for (i = _start; i < _len; i++) { \
coeff = &interp_coeff[fluid_phase_fract_to_tablerow(phase)]; \
index = fluid_phase_index(phase); \
z = (int) (coeff->c0 * data[index] + coeff->c1 * data[index+1] + coeff->c2 * data[index+2] + coeff->c3 * data[index+3]); \
z = ((z >> 16) * a) + ((z * a) >> 16); \
buf[i] = fix1616tof(z) / 32768.0f; \
fluid_phase_incr(phase, phase_incr); \
amp += amp_incr; \
} \
\
/* filter */ \
if (b1 || b2) { \
for (i = _start; i < _len; i++) { \
w = gain * buf[i] - b1 * w1 - b2 * w2; \
buf[i] = w + w1 + w1 + w2; \
w2 = w1; \
w1 = w; \
} \
} \
\
/* pan */ \
for (i = _start; i < _len; i++) { \
left[i] += amp_left * buf[i]; \
right[i] += amp_right * buf[i]; \
} \
\
/* reverb */ \
if (reverb_send) { \
for (i = _start; i < _len; i++) { \
reverb_buf[i] += reverb_send * buf[i]; \
} \
} \
}
}
#endif

View file

@ -620,7 +620,8 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track)
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
param1 = ((param1 & 0x7f) << 7) | (param2 & 0x7f);
param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
param2 = 0;
break;

View file

@ -801,12 +801,14 @@ int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
fflush(stdout);
break;
case NOTE_OFF:
fprintf(stdout, "event_pre_noteoff %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_pre_noteoff %i %i %i\n",
event->channel, event->param1, event->param2);
fflush(stdout);
break;
break;
case CONTROL_CHANGE:
fprintf(stdout, "event_pre_cc %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_pre_cc %i %i %i\n",
event->channel, event->param1, event->param2);
fflush(stdout);
break;
case PROGRAM_CHANGE:
@ -822,7 +824,8 @@ int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
fflush(stdout);
break;
case KEY_PRESSURE:
fprintf(stdout, "event_pre_kpress %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_pre_kpress %i %i %i\n",
event->channel, event->param1, event->param2);
fflush(stdout);
break;
default:
@ -837,19 +840,23 @@ int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
* Again, it prints a message to stdout and hands the event on to the synth.
* It is not a part of the MIDI router, but an added link in the MIDI chain.
*/
int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event){
int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event)
{
switch (event->type) {
case NOTE_ON:
fprintf(stdout, "event_post_noteon %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_post_noteon %i %i %i\n",
event->channel, event->param1, event->param2);
fflush(stdout);
break;
case NOTE_OFF:
fprintf(stdout, "event_post_noteoff %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_post_noteoff %i %i %i\n",
event->channel, event->param1, event->param2);
fflush(stdout);
break;
break;
case CONTROL_CHANGE:
fprintf(stdout, "event_post_cc %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_post_cc %i %i %i\n",
event->channel, event->param1, event->param2);
fflush(stdout);
break;
case PROGRAM_CHANGE:
@ -862,7 +869,8 @@ int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event){
fprintf(stdout, "event_post_cpress %i %i\n", event->channel, event->param1);
break;
case KEY_PRESSURE:
fprintf(stdout, "event_post_kpress %i %i %i\n", event->channel, event->param1, event->param2);
fprintf(stdout, "event_post_kpress %i %i %i\n",
event->channel, event->param1, event->param2);
break;
default:
break;

View file

@ -1,22 +1,13 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
/*
Freeverb
Written by Jezar at Dreampoint, June 2000
http://www.dreampoint.co.uk
This code is public domain
Translated to C by Peter Hanappe, Mai 2001
*/
#include "fluid_rev.h"
@ -24,13 +15,6 @@
*
* REVERB
*/
/*
Written by Jezar at Dreampoint, June 2000
http://www.dreampoint.co.uk
This code is public domain
Translated to C by Peter Hanappe, Mai 2001
*/
/* Denormalising:
*
@ -182,7 +166,7 @@ fluid_comb_init(fluid_comb* comb)
fluid_real_t* buf = comb->buffer;
int len = comb->bufsize;
for (i = 0; i < len; i++) {
buf[i]=DC_OFFSET; /* This is not 100 % correct. */
buf[i] = DC_OFFSET; /* This is not 100 % correct. */
}
}
@ -335,6 +319,7 @@ new_fluid_revmodel()
if (rev == NULL) {
return NULL;
}
/* Tie the components to their buffers */
fluid_comb_setbuffer(&rev->combL[0], rev->bufcombL1, combtuningL1);
fluid_comb_setbuffer(&rev->combR[0], rev->bufcombR1, combtuningR1);
@ -413,6 +398,7 @@ fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
outL = outR = 0;
input = in[k] + DC_OFFSET;
@ -445,8 +431,9 @@ fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
outL = outR = 0;
input = in[k]+0.001;
input = in[k] + DC_OFFSET;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
@ -460,8 +447,8 @@ fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
}
/* Remove the DC offset */
outL-=DC_OFFSET;
outR-=DC_OFFSET;
outL -= DC_OFFSET;
outR -= DC_OFFSET;
/* Calculate output MIXING with anything already there */
left_out[k] += outL * rev->wet1 + outR * rev->wet2;
@ -499,6 +486,7 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
void
fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value)
{
fluid_clip(value, 0.0f, 1.0f);
rev->roomsize = (value * scaleroom) + offsetroom;
fluid_revmodel_update(rev);
}
@ -512,6 +500,7 @@ fluid_revmodel_getroomsize(fluid_revmodel_t* rev)
void
fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value)
{
fluid_clip(value, 0.0f, 1.0f);
rev->damp = value * scaledamp;
fluid_revmodel_update(rev);
}
@ -525,6 +514,7 @@ fluid_revmodel_getdamp(fluid_revmodel_t* rev)
void
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
{
fluid_clip(value, 0.0f, 1.0f);
rev->wet = value * scalewet;
fluid_revmodel_update(rev);
}
@ -538,6 +528,7 @@ fluid_revmodel_getlevel(fluid_revmodel_t* rev)
void
fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value)
{
fluid_clip(value, 0.0f, 1.0f);
rev->width = value;
fluid_revmodel_update(rev);
}

View file

@ -81,6 +81,7 @@ cca_client_t * fluid_cca_client;
* INITIALIZATION & UTILITIES
*/
void fluid_synth_settings(fluid_settings_t* settings)
{
fluid_settings_register_str(settings, "synth.verbose", "no", 0, NULL, NULL);
@ -343,6 +344,11 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
fluid_settings_getnum(settings, "synth.gain", &synth->gain);
/* register the callbacks */
fluid_settings_register_num(settings, "synth.gain",
0.2f, 0.0f, 10.0f, 0,
(fluid_num_update_t) fluid_synth_update_gain, synth);
/* do some basic sanity checking on the settings */
if (synth->midi_channels < 16) {
FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is smaller than 16. "
@ -807,6 +813,10 @@ fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
return FLUID_FAILED;
}
if (synth->verbose) {
FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", chan, num, val);
}
/* set the controller value in the channel */
fluid_channel_cc(synth->channel[chan], num, val);
@ -958,6 +968,10 @@ fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
return FLUID_FAILED;
}
if (synth->verbose) {
FLUID_LOG(FLUID_INFO, "pitchb\t%d\t%d", chan, val);
}
/* set the pitch-bend value in the channel */
fluid_channel_pitch_bend(synth->channel[chan], val);
@ -993,6 +1007,10 @@ fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val)
return FLUID_FAILED;
}
if (synth->verbose) {
FLUID_LOG(FLUID_INFO, "pitchsens\t%d\t%d", chan, val);
}
/* set the pitch-bend value in the channel */
fluid_channel_pitch_wheel_sens(synth->channel[chan], val);
@ -1071,7 +1089,7 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
}
/* special handling of channel 10 (or 9 counting from 0). channel
10 is the percussion chnnel. */
10 is the percussion channel. */
if (channel->channum == 9) {
/* try to search the drum instrument first */
@ -1194,6 +1212,16 @@ void fluid_synth_update_presets(fluid_synth_t* synth)
}
}
/*
* fluid_synth_update_gain
*/
int fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value)
{
fluid_synth_set_gain(synth, (float) value);
return 0;
}
/*
* fluid_synth_set_gain
*/

View file

@ -186,6 +186,9 @@ void fluid_synth_print_voice(fluid_synth_t* synth);
* unloaded or reloaded. */
void fluid_synth_update_presets(fluid_synth_t* synth);
int fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value);
/*
* misc
*/

View file

@ -19,7 +19,6 @@
*/
int print_pan = 1;
#include "fluidsynth_priv.h"
@ -311,7 +310,9 @@ fluid_voice_write(fluid_voice_t* voice,
fluid_real_t incr;
fluid_real_t fres;
/* All variables starting with dsp_ are used by the DSP loop. Documented in fluid_dsp_core.c */
/* All variables starting with dsp_ are used by the DSP
loop. Documented in fluid_dsp_core.c */
int dsp_phase_index;
unsigned int dsp_i;
fluid_phase_t dsp_phase, dsp_phase_incr;
@ -328,16 +329,20 @@ fluid_voice_write(fluid_voice_t* voice,
int dsp_use_filter_flag = 1;
short* dsp_data;
int dsp_interp_method = voice->interp_method;
#ifdef ENABLE_SSE
float mem_for_sse_interface[5*4+4]; /* Reserve memory */
/* +4: add four floats for 16 added bytes */
sse_t* sse_n=(sse_t*)FLUID_ALIGN16BYTE(&mem_for_sse_interface); /* Align the first element */
sse_t* sse_a=sse_n++; /* The ++ operator increases
* by the size of the structure! */
sse_t* sse_b=sse_n++;
sse_t* sse_c=sse_n++;
sse_t* sse_d=sse_n++;
sse_t* sse_e=sse_n++;
float mem_for_sse_interface[5*4+4]; /* Reserve memory */
/* +4: add four floats for 16 added bytes */
/* Align the first element */
sse_t* sse_n = (sse_t*) FLUID_ALIGN16BYTE(&mem_for_sse_interface);
sse_t* sse_a = sse_n++; /* The ++ operator increases
* by the size of the structure! */
sse_t* sse_b = sse_n++;
sse_t* sse_c = sse_n++;
sse_t* sse_d = sse_n++;
sse_t* sse_e = sse_n++;
sse_t* sse_coeff;
sse_t* sse_src;
@ -345,13 +350,14 @@ fluid_voice_write(fluid_voice_t* voice,
sse_t* sse_dest_right;
sse_t* sse_dest;
#endif
fluid_real_t dsp_buf_unaligned[FLUID_BUFSIZE+4]; /* +4: add four floats for 16 added bytes */
fluid_real_t* dsp_buf=(fluid_real_t*)FLUID_ALIGN16BYTE(&dsp_buf_unaligned);
/* fluid_real_t dsp_sample; */
/* +4: add four floats for 16 added bytes */
fluid_real_t dsp_buf_unaligned[FLUID_BUFSIZE+4];
fluid_real_t* dsp_buf = (fluid_real_t*) FLUID_ALIGN16BYTE(&dsp_buf_unaligned);
fluid_env_data_t* env_data;
fluid_real_t x;
/* make sure we're playing and that we have sample data */
if (!_PLAYING(voice)) {
return FLUID_OK;
@ -359,9 +365,7 @@ fluid_voice_write(fluid_voice_t* voice,
/******************* sample **********************/
if ((voice->sample == NULL)
// || !voice->sample->valid
) {
if (voice->sample == NULL) {
fluid_voice_off(voice);
return FLUID_OK;
}
@ -388,7 +392,7 @@ fluid_voice_write(fluid_voice_t* voice,
x = env_data->min;
voice->volenv_section++;
voice->volenv_count = 0;
} else if (x > env_data->max && 0) {
} else if (x > env_data->max) {
x = env_data->max;
voice->volenv_section++;
voice->volenv_count = 0;
@ -399,7 +403,6 @@ fluid_voice_write(fluid_voice_t* voice,
if (voice->volenv_section == FLUID_VOICE_ENVFINISHED) {
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off(voice);
return FLUID_OK;
}
@ -469,7 +472,7 @@ fluid_voice_write(fluid_voice_t* voice,
if (voice->volenv_section == FLUID_VOICE_ENVDELAY) {
/* The volume amplitude is in hold phase. No sound is produced. */
goto amp_env_in_delay_phase_skip_DSP;
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)
@ -495,28 +498,30 @@ fluid_voice_write(fluid_voice_t* voice,
/* A voice can be turned off, when an estimate for the volume
* (upper bound) falls below that volume, that will drop the
* sample below the noise floor.
* Start out with assuming a 0 dB sample... */
* sample below the noise floor. Start out with assuming a 0 dB
* sample... */
amplitude_that_reaches_noise_floor = FLUID_NOISE_FLOOR;
if (voice->has_looped) {
/* For the loop we may have a better estimate for the volume
* of the actual sample (from peak detector): */
/* For the loop we may have a better estimate for the volume of
* the actual sample (from peak detector): */
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor;
}
/* voice->attenuation_min is a lower boundary for the attenuation
* now and in the future (possibly 0 in the worst case).
* Now the amplitude of sample and volenv cannot
* exceed amp_max (since volenv_val can only drop):
* now and in the future (possibly 0 in the worst case). Now the
* amplitude of sample and volenv cannot exceed amp_max (since
* volenv_val can only drop):
*/
amp_max = fluid_cb2amp(voice->min_attenuation_cB
+ 960.0f * (1.0f - voice->volenv_val));
/* printf("Att min: %f Amp max: %f Limit: %f\n",voice->min_attenuation_cB,amp_max, amplitude_that_reaches_noise_floor); */
// printf("Amp max: %f\n",amp_max);
/* And if amp_max is already smaller than the known amplitude,
* which will attenuate the sample below the noise floor, then
* we can safely turn off the voice. Duh. */
* which will attenuate the sample below the noise floor, then we
* can safely turn off the voice. Duh. */
if (amp_max < amplitude_that_reaches_noise_floor){
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
/* printf("Voice turned off! Amp is %f\n", amp_max); */
@ -526,15 +531,16 @@ fluid_voice_write(fluid_voice_t* voice,
}
/* At this point, dsp_amp is the desired amplitude for the voice.
* This value will be reached at the end of the next buffer.
* So we raise the amplitude smoothly from the current voice
* amplitude (voice->amp) to the wanted amplitude dsp_amp.
* This value will be reached at the end of the next buffer. So we
* raise the amplitude smoothly from the current voice amplitude
* (voice->amp) to the wanted amplitude dsp_amp.
*
* By how much do we have to increase voice->amp, so that it reaches dsp_amp, when the
* increment is added FLUID_BUFSIZE times? */
* By how much do we have to increase voice->amp, so that it reaches
* dsp_amp, when the increment is added FLUID_BUFSIZE times? */
dsp_amp_incr = (dsp_amp - voice->amp) / FLUID_BUFSIZE;
/* dsp_amp will now be fed into the DSP loop.
* Use the amplitude, that came out of the last DSP loop run. */
/* dsp_amp will now be fed into the DSP loop. Use the amplitude,
* that came out of the last DSP loop run. */
dsp_amp = voice->amp;
fluid_check_fpe("voice_write amplitude calculation");
@ -542,25 +548,28 @@ fluid_voice_write(fluid_voice_t* voice,
goto post_process;
}
/* Calculate the number of samples, that the DSP loop advances through the original waveform
* with each step in the output buffer. It is the ratio between the frequencies of original
/* Calculate the number of samples, that the DSP loop advances
* through the original waveform with each step in the output
* buffer. It is the ratio between the frequencies of original
* waveform and output waveform.*/
incr = fluid_ct2hz(voice->pitch
+ voice->modlfo_val * voice->modlfo_to_pitch
+ voice->viblfo_val * voice->viblfo_to_pitch
+ voice->modenv_val * voice->modenv_to_pitch) / voice->root_pitch;
/* Transfer the phase from the voice into the dsp loop parameter dsp_phase */
/* Transfer the phase from the voice into the dsp loop parameter
dsp_phase */
fluid_phase_set(dsp_phase, voice->phase);
/* Convert the 'speed' through the original waveform to a representation 'integer part'
* and 'fractional part' */
/* Convert the 'speed' through the original waveform to a
* representation 'integer part' and 'fractional part' */
fluid_phase_set_float(dsp_phase_incr, incr);
incr *= 1.00000000000001; /* gcc optimization problem. Quick fix. */
fluid_check_fpe("voice_write phase calculation");
/* Check, if we are really making progress through the original sample.
* If the step size is rounded to 0, the DSP loop would get stuck. */
/* Check, if we are really making progress through the original
* sample. If the step size is rounded to 0, the DSP loop would get
* stuck. */
if (fluid_phase_index(dsp_phase) == 0 && fluid_phase_fract(dsp_phase) == 0){
fluid_phase_fract(dsp_phase)=1;
}
@ -571,6 +580,7 @@ fluid_voice_write(fluid_voice_t* voice,
fres = fluid_ct2hz(voice->fres
+ voice->modlfo_val * voice->modlfo_to_fc
+ voice->modenv_val * voice->modenv_to_fc);
/* Testcase for filter resonance: Use the following line, and press
* A3. There should be a _very_ pronounced resonant peak, which
* drops down, when moving the pitch bend wheel only slightly. */
@ -578,34 +588,34 @@ fluid_voice_write(fluid_voice_t* voice,
if (fres < 5) {
fres = 5;
} else if (fres > FLUID_MAX_AUDIBLE_FILTER_FC
&& voice->q_lin < FLUID_MIN_AUDIBLE_FILTER_Q) {
/* Beyond a certain point the filter does not change the sound much.
* Turn it off to save CPU cycles. */
/* Fixme: When the filter has been on once for a voice, keep it on forever. */
dsp_use_filter_flag=0;
} else if ((fres > FLUID_MAX_AUDIBLE_FILTER_FC)
&& (voice->q_lin < FLUID_MIN_AUDIBLE_FILTER_Q)) {
/* Beyond a certain point the filter does not change the sound
* much. Turn it off to save CPU cycles. */
/* Fixme: When the filter has been on once for a voice, keep it on forever. */
dsp_use_filter_flag = 0;
}
if (dsp_use_filter_flag && (abs(fres-voice->last_fres)>0.01)) {
if (dsp_use_filter_flag && (abs(fres - voice->last_fres) > 0.01)) {
/* The filter coefficients have to be recalculated (filter parameters
* have changed). Recalculation for various reasons is forced by
* setting last_fres to -1.
* The flag filter_startup indicates, that the DSP loop runs
* for the first time, in this case, the filter is set directly,
* instead of smoothly fading between old and new settings.
/* The filter coefficients have to be recalculated (filter
* parameters have changed). Recalculation for various reasons is
* forced by setting last_fres to -1. The flag filter_startup
* indicates, that the DSP loop runs for the first time, in this
* case, the filter is set directly, instead of smoothly fading
* between old and new settings.
*
* Those equations from Robert Bristow-Johnson's `Cookbook
* formulae for audio EQ biquad filter coefficients', obtained
* from Harmony-central.com / Computer / Programming They are
* from Harmony-central.com / Computer / Programming. They are
* the result of the bilinear transform on an analogue filter
* prototype. To quote, `BLT frequency warping has been taken
* into account * for both significant frequency relocation and
* for bandwidth readjustment'. */
* into account for both significant frequency relocation and for
* bandwidth readjustment'. */
fluid_real_t omega = (fluid_real_t) (2.0 * M_PI * (fres / 44100.0f));
fluid_real_t sin_coeff = (fluid_real_t) (sin(omega));
fluid_real_t cos_coeff = (fluid_real_t) (cos(omega));
fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
fluid_real_t alpha_coeff = sin_coeff / (2.0f * voice->q_lin);
fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);
@ -631,25 +641,29 @@ fluid_voice_write(fluid_voice_t* voice,
voice->a1 = a1_temp;
voice->a2 = a2_temp;
voice->b02 = b02_temp;
voice->b1 = b1_temp;
voice->filter_coeff_incr_count=0;
voice->filter_startup=0;
voice->b1 = b1_temp;
voice->filter_coeff_incr_count = 0;
voice->filter_startup = 0;
// printf("Setting initial filter coefficients.\n");
} else {
/* The filter frequency is changed.
* Calculate an increment factor, so that the new setting is reached
* after one buffer length. x_incr is added to the current value FLUID_BUFSIZE
/* The filter frequency is changed. Calculate an increment
* factor, so that the new setting is reached after one buffer
* length. x_incr is added to the current value FLUID_BUFSIZE
* times. The length is arbitrarily chosen. Longer than one
* buffer will sacrifice some performance, though.
* Note: If the filter is still too 'grainy', then increase this number at will.
* buffer will sacrifice some performance, though. Note: If
* the filter is still too 'grainy', then increase this number
* at will.
*/
#define FILTER_TRANSITION_SAMPLES (2*FLUID_BUFSIZE)
voice->a1_incr=(a1_temp-voice->a1)*(1./(fluid_real_t)(FILTER_TRANSITION_SAMPLES));
voice->a2_incr=(a2_temp-voice->a2)*(1./(fluid_real_t)(FILTER_TRANSITION_SAMPLES));
voice->b02_incr=(b02_temp-voice->b02)*(1./(fluid_real_t)(FILTER_TRANSITION_SAMPLES));
voice->b1_incr=(b1_temp-voice->b1)*(1./(fluid_real_t)(FILTER_TRANSITION_SAMPLES));
#define FILTER_TRANSITION_SAMPLES (FLUID_BUFSIZE)
voice->a1_incr = (a1_temp - voice->a1) / FILTER_TRANSITION_SAMPLES;
voice->a2_incr = (a2_temp - voice->a2) / FILTER_TRANSITION_SAMPLES;
voice->b02_incr = (b02_temp - voice->b02) / FILTER_TRANSITION_SAMPLES;
voice->b1_incr = (b1_temp - voice->b1) / FILTER_TRANSITION_SAMPLES;
/* Have to add the increments filter_coeff_incr_count times. */
voice->filter_coeff_incr_count=(FILTER_TRANSITION_SAMPLES);
voice->filter_coeff_incr_count = FILTER_TRANSITION_SAMPLES;
}
voice->last_fres = fres;
fluid_check_fpe("voice_write filter calculation");
@ -670,6 +684,10 @@ fluid_voice_write(fluid_voice_t* voice,
dsp_a2 = voice->a2;
dsp_b02 = voice->b02;
dsp_b1 = voice->b1;
dsp_a1_incr = voice->a1_incr;
dsp_a2_incr = voice->a2_incr;
dsp_b02_incr = voice->b02_incr;
dsp_b1_incr = voice->b1_incr;
dsp_filter_coeff_incr_count = voice->filter_coeff_incr_count;
fluid_check_fpe("voice_write DSP coefficients");
@ -681,11 +699,12 @@ fluid_voice_write(fluid_voice_t* voice,
* may require several runs. */
fluid_check_fpe("voice_write DSP processing");
if (
((_SAMPLEMODE(voice) == FLUID_LOOP) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
/* At which index does the loop point occur in the output buffer?
* This calculates the first index in the buffer, which uses sample data taken after the looparound. */
if (((_SAMPLEMODE(voice) == FLUID_LOOP) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
/* At which index does the loop point occur in the output buffer?
* This calculates the first index in the buffer, which uses
* sample data taken after the looparound. */
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loop_end_offset, incr);
if (end_in_buffer >= FLUID_BUFSIZE) {
@ -694,20 +713,21 @@ fluid_voice_write(fluid_voice_t* voice,
dsp_start = 0;
dsp_end = FLUID_BUFSIZE;
#include "fluid_dsp_core.c"
} else {
/* The loop occurs during the current buffer length.
* Note, that this method is unable to cope with a 'skipped' loop point.
* If, by means of witchcraft, evil magic or modulators, we end up beyond
* the loop point, a SEGV is unavoidable.
* We can't even detect this here, because the calculations are done using
* unsigned ints (only positive), and end_in_buffer would be negative
* for a skipped loop point...*/
/* The loop occurs during the current buffer length. Note, that
* this method is unable to cope with a 'skipped' loop point. *
* If, by means of witchcraft, evil magic or modulators, we end
* up beyond * the loop point, a SEGV is unavoidable. * We
* can't even detect this here, because the calculations are
* done using * unsigned ints (only positive), and end_in_buffer
* would be negative * for a skipped loop point...*/
start = 0;
while (end_in_buffer < FLUID_BUFSIZE) {
dsp_start=start;
dsp_end=end_in_buffer;
dsp_start = start;
dsp_end = end_in_buffer;
#include "fluid_dsp_core.c"
/* loop */
@ -716,26 +736,26 @@ fluid_voice_write(fluid_voice_t* voice,
start = end_in_buffer;
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loop_end_offset, incr);
}
dsp_start=start;
dsp_end=FLUID_BUFSIZE;
dsp_start = start;
dsp_end = FLUID_BUFSIZE;
#include "fluid_dsp_core.c"
}
} else {
/* Not looping right now. */
dsp_start=0;
dsp_start = 0;
end_in_buffer = fluid_phase_steps(dsp_phase, voice->end_offset, incr);
if (end_in_buffer >= FLUID_BUFSIZE) {
/* Run the whole buffer at once */
dsp_end=FLUID_BUFSIZE;
dsp_end = FLUID_BUFSIZE;
#include "fluid_dsp_core.c"
} else {
/* The sample ends in the middle of the buffer length.
* Process that far, and turn the voice off.
*/
dsp_end=end_in_buffer;
dsp_end = end_in_buffer;
#include "fluid_dsp_core.c"
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off(voice);
@ -750,8 +770,17 @@ fluid_voice_write(fluid_voice_t* voice,
voice->hist2 = dsp_hist2;
voice->phase = dsp_phase;
voice->amp = dsp_amp;
voice->a1 = dsp_a1;
voice->a2 = dsp_a2;
voice->b02 = dsp_b02;
voice->b1 = dsp_b1;
voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
/* if (dsp_filter_coeff_incr_count) { */
/* printf("ticks = %d, dsp_filter_coeff_incr_count = %d\n", */
/* voice->ticks, dsp_filter_coeff_incr_count); */
/* } */
amp_env_in_delay_phase_skip_DSP:
post_process:
voice->ticks += FLUID_BUFSIZE;
fluid_check_fpe("voice_write postprocess");
@ -1078,12 +1107,9 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
case GEN_FILTERFC:
/* The resonance frequency is converted from absolute cents to midicents
* .val and .mod are both used, this permits real-time modulation.
* The allowed range is tested in the 'fluid_ct2hz' function [PH,20021214]
*/
voice->fres = _GEN(voice, GEN_FILTERFC);
/* Range: SF2.01 section 8.1.3 # 8 (note that these numbers are NOT frequencies) */
/* The allowed range is tested in the 'fluid_ct2hz' function [PH,20021214] */
/* fluid_clip(voice->fres, 1500.0f, 13500.0f); */
/* The synthesis loop will have to recalculate the filter coefficients. */
voice->last_fres = -1.0f;
@ -1113,19 +1139,20 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
* follows: */
q_dB -= 3.01f;
/* The 'sound font' Q is defined in dB. The filter needs a linear q. Convert. */
/* The 'sound font' Q is defined in dB. The filter needs a linear
q. Convert. */
voice->q_lin = (fluid_real_t) (pow(10.0f, q_dB / 20.0f));
/* SF 2.01 page 59:
* The SoundFont specs ask for a gain reduction equal to half
* the height of the resonance peak (Q). For example, for a
* 10 dB resonance peak, the gain is reduced by 5 dB. This is
* done by multiplying the total gain with sqrt(1/Q). `Sqrt'
* divides dB by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin
* = 10 dB etc) The gain is later factored into the 'b'
* coefficients (numerator of the filter equation).
* This gain factor depends only on Q, so this is the right place to
* calculate it.
*
* The SoundFont specs ask for a gain reduction equal to half the
* height of the resonance peak (Q). For example, for a 10 dB
* resonance peak, the gain is reduced by 5 dB. This is done by
* multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
* by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
* The gain is later factored into the 'b' coefficients
* (numerator of the filter equation). This gain factor depends
* only on Q, so this is the right place to calculate it.
*/
voice->filter_gain = (fluid_real_t) (1.0 / sqrt(voice->q_lin));
@ -1341,7 +1368,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
voice->volenv_data[FLUID_VOICE_ENVRELEASE].coeff = 1.0f;
voice->volenv_data[FLUID_VOICE_ENVRELEASE].incr = count ? -1.0f / count : 0.0f;
voice->volenv_data[FLUID_VOICE_ENVRELEASE].min = 0.0f;
voice->volenv_data[FLUID_VOICE_ENVRELEASE].max = 2.0f;
voice->volenv_data[FLUID_VOICE_ENVRELEASE].max = 1.0f;
break;
/* Modulation envelope */
@ -1882,9 +1909,9 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
/* Keep start and end point in the right order */
if (voice->start_offset > voice->end_offset){
int temp=voice->start_offset;
voice->start_offset=voice->end_offset;
voice->end_offset=temp;
int temp = voice->start_offset;
voice->start_offset = voice->end_offset;
voice->end_offset = temp;
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
}

View file

@ -138,20 +138,20 @@ struct _fluid_voice_t
fluid_real_t modlfo_to_vol;
/* vib lfo */
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
unsigned int viblfo_delay; /* the delay of the lfo in samples */
fluid_real_t viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
unsigned int viblfo_delay; /* the delay of the lfo in samples */
fluid_real_t viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */
fluid_real_t viblfo_to_pitch;
/* resonant filter */
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
/* Serves as a flag: A deviation between fres and last_fres */
/* indicates, that the filter has to be recalculated. */
fluid_real_t q_lin; /* the q-factor on a linear scale */
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
int filter_startup; /* Flag: If set, the filter will be set directly.
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
/* Serves as a flag: A deviation between fres and last_fres */
/* indicates, that the filter has to be recalculated. */
fluid_real_t q_lin; /* the q-factor on a linear scale */
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
int filter_startup; /* Flag: If set, the filter will be set directly.
Else it changes smoothly. */
/* filter coefficients */

View file

@ -168,7 +168,7 @@ int main(int argc, char** argv)
int audio_groups = 0;
int audio_channels = 0;
int with_server = 0;
int dump=0;
int dump = 0;
appname = argv[0];
#ifdef HAVE_LADCCA
cca_args_t * cca_args;
@ -261,7 +261,7 @@ int main(int argc, char** argv)
break;
case 'd':
fluid_settings_setstr(settings, "synth.dump", "yes");
dump=1;
dump = 1;
break;
case 'R':
if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) {
@ -500,6 +500,7 @@ int main(int argc, char** argv)
/* In dump mode, text output is generated for events going into and out of the router.
* The example dump functions are put into the chain before and after the router..
*/
router = new_fluid_midi_router(
settings,
dump ? fluid_midi_dump_postrouter : fluid_synth_handle_midi_event,