fix #119731: fluidsynth optimizations

This commit is contained in:
Johannes Wegener 2016-07-28 13:48:05 +02:00
parent 95bcc1e5cb
commit 65fad51543
3 changed files with 109 additions and 91 deletions

View file

@ -46,13 +46,29 @@ namespace FluidS {
* - dsp_buf: Output buffer of floating point values (FLUID_BUFSIZE in length)
*/
inline void updateAmpInc(unsigned int &nextNewAmpInc,std::map<int, qreal>::iterator &curSample2AmpInc, qreal &dsp_amp_incr, unsigned int dsp_i)
inline bool Voice::updateAmpInc(unsigned int &nextNewAmpInc, std::map<int, qreal>::iterator &curSample2AmpInc, qreal &dsp_amp_incr, unsigned int &dsp_i)
{
if (positionToTurnOff > 0 && dsp_i >= (unsigned int) positionToTurnOff)
return false;
// if volume is zero skip all phases that do not change that!
if (amp == 0.0f) {
while (dsp_amp_incr == 0.0f && curSample2AmpInc != Sample2AmpInc.end()) {
dsp_i = curSample2AmpInc->first;
curSample2AmpInc++;
nextNewAmpInc = curSample2AmpInc->first;
dsp_amp_incr = curSample2AmpInc->second;
}
if (curSample2AmpInc == Sample2AmpInc.end())
return false;
}
if (dsp_i >= nextNewAmpInc) {
curSample2AmpInc++;
nextNewAmpInc = curSample2AmpInc->first;
dsp_amp_incr = curSample2AmpInc->second;
}
return true;
}
@ -131,7 +147,6 @@ int Voice::dsp_float_interpolate_none(unsigned n)
Phase dsp_phase_incr; // end_phase;
short int *dsp_data = voice->sample->data;
float *dsp_buf = voice->dsp_buf;
float dsp_amp = voice->amp;
auto curSample2AmpInc = Sample2AmpInc.begin();
qreal dsp_amp_incr = curSample2AmpInc->second;
unsigned int nextNewAmpInc = curSample2AmpInc->first;
@ -155,13 +170,14 @@ int Voice::dsp_float_interpolate_none(unsigned n)
/* interpolate sequence of sample points */
for ( ; dsp_i < n && dsp_phase_index <= end_index; dsp_i++) {
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
dsp_buf[dsp_i] = amp * dsp_data[dsp_phase_index];
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index_round(); /* round to nearest point */
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
/* break out if not looping (buffer may not be full) */
@ -180,7 +196,6 @@ int Voice::dsp_float_interpolate_none(unsigned n)
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return dsp_i;
}
@ -198,7 +213,6 @@ int Voice::dsp_float_interpolate_linear(unsigned n)
Phase dsp_phase_incr; // end_phase;
short int *dsp_data = voice->sample->data;
float *dsp_buf = voice->dsp_buf;
float dsp_amp = voice->amp;
auto curSample2AmpInc = Sample2AmpInc.begin();
qreal dsp_amp_incr = curSample2AmpInc->second;
unsigned int nextNewAmpInc = curSample2AmpInc->first;
@ -232,14 +246,15 @@ int Voice::dsp_float_interpolate_linear(unsigned n)
/* interpolate the sequence of sample points */
for ( ; dsp_i < n && dsp_phase_index <= end_index; dsp_i++) {
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
dsp_buf[dsp_i] = amp * (coeffs[0] * dsp_data[dsp_phase_index]
+ coeffs[1] * dsp_data[dsp_phase_index+1]);
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
/* break out if buffer filled */
@ -251,14 +266,15 @@ int Voice::dsp_float_interpolate_linear(unsigned n)
/* interpolate within last point */
for (; dsp_phase_index <= end_index && dsp_i < n; dsp_i++) {
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
dsp_buf[dsp_i] = amp * (coeffs[0] * dsp_data[dsp_phase_index]
+ coeffs[1] * point);
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr; /* increment amplitude */
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr; /* increment amplitude */
}
if (!looping)
@ -277,7 +293,6 @@ int Voice::dsp_float_interpolate_linear(unsigned n)
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return dsp_i;
}
@ -345,7 +360,8 @@ int Voice::dsp_float_interpolate_4th_order(unsigned n)
/* increment phase and amplitude */
phase += dsp_phase_incr;
dsp_phase_index = phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
@ -360,7 +376,8 @@ int Voice::dsp_float_interpolate_4th_order(unsigned n)
/* increment phase and amplitude */
phase += dsp_phase_incr;
dsp_phase_index = phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
@ -381,7 +398,8 @@ int Voice::dsp_float_interpolate_4th_order(unsigned n)
/* increment phase and amplitude */
phase += dsp_phase_incr;
dsp_phase_index = phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
@ -398,7 +416,8 @@ int Voice::dsp_float_interpolate_4th_order(unsigned n)
/* increment phase and amplitude */
phase += dsp_phase_incr;
dsp_phase_index = phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
@ -437,7 +456,6 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
Phase dsp_phase_incr; // end_phase;
short int *dsp_data = voice->sample->data;
float *dsp_buf = voice->dsp_buf;
float dsp_amp = voice->amp;
auto curSample2AmpInc = Sample2AmpInc.begin();
qreal dsp_amp_incr = curSample2AmpInc->second;
unsigned int nextNewAmpInc = curSample2AmpInc->first;
@ -496,7 +514,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for ( ; dsp_phase_index == start_index && dsp_i < n; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)start_points[2]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)start_points[2]
+ coeffs[1] * (float)start_points[1]
+ coeffs[2] * (float)start_points[0]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -507,8 +525,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
start_index++;
@ -517,7 +536,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for ( ; dsp_phase_index == start_index && dsp_i < n; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)start_points[1]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)start_points[1]
+ coeffs[1] * (float)start_points[0]
+ coeffs[2] * (float)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -528,8 +547,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
start_index++;
@ -538,7 +558,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for ( ; dsp_phase_index == start_index && dsp_i < n; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)start_points[0]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)start_points[0]
+ coeffs[1] * (float)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (float)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -549,8 +569,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
start_index -= 2; /* set back to original start index */
@ -559,7 +580,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for ( ; dsp_i < n && dsp_phase_index <= end_index; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (float)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (float)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -570,8 +591,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
/* break out if buffer filled */
@ -584,7 +606,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for (; dsp_phase_index <= end_index && dsp_i < n; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (float)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (float)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -595,8 +617,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the 2nd to last point */
@ -605,7 +628,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for (; dsp_phase_index <= end_index && dsp_i < n; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (float)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (float)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -616,8 +639,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the last point */
@ -626,7 +650,7 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
for (; dsp_phase_index <= end_index && dsp_i < n; dsp_i++) {
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
dsp_buf[dsp_i] = amp * (coeffs[0] * (float)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (float)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (float)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (float)dsp_data[dsp_phase_index]
@ -637,8 +661,9 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
/* increment phase and amplitude */
dsp_phase += dsp_phase_incr;
dsp_phase_index = dsp_phase.index();
updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i);
dsp_amp += dsp_amp_incr;
if (!updateAmpInc(nextNewAmpInc, curSample2AmpInc, dsp_amp_incr, dsp_i))
return dsp_i;
amp += dsp_amp_incr;
}
if (!looping)
@ -668,7 +693,6 @@ int Voice::dsp_float_interpolate_7th_order(unsigned n)
dsp_phase -= (Phase)0x80000000;
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return dsp_i;
}

View file

@ -332,21 +332,23 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
int modLfoStart = -1;
if (ticks >= modlfo_delay)
modLfoStart = 0;
else if (n >= modlfo_delay)
modLfoStart = modlfo_delay;
if (fabs(modlfo_to_vol) > 0) {
if (ticks >= modlfo_delay)
modLfoStart = 0;
else if (n >= modlfo_delay)
modLfoStart = modlfo_delay;
if (modLfoStart >= 0) {
if (modLfoStart > 0)
volumeChanges.insert(modLfoStart);
if (modLfoStart >= 0) {
if (modLfoStart > 0)
volumeChanges.insert(modLfoStart);
unsigned int modLfoNextTurn = samplesToNextTurningPoint(modlfo_dur, modlfo_pos);
unsigned int modLfoNextTurn = samplesToNextTurningPoint(modlfo_dur, modlfo_pos);
while (modLfoNextTurn+modLfoStart < n) {
volumeChanges.insert(modLfoNextTurn+modLfoStart);
modLfoNextTurn++;
modLfoNextTurn += samplesToNextTurningPoint(modlfo_dur, modLfoNextTurn);
while (modLfoNextTurn+modLfoStart < n) {
volumeChanges.insert(modLfoNextTurn+modLfoStart);
modLfoNextTurn++;
modLfoNextTurn += samplesToNextTurningPoint(modlfo_dur, modLfoNextTurn);
}
}
}
@ -425,12 +427,6 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
* fluid_cb2amp (960.0f * (1.0f - volenv_val)
+ modlfo_val * -modlfo_to_vol);
// REMOVED DUE TO CHANGE IN ENVELOPE CALCULATION
// is an optimization
// TODO: Make it work again with sample based volume
/* We turn off a voice, if the volume has dropped low enough. */
/* 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.
@ -440,28 +436,28 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
* the sample loop
*/
/* Is the playing pointer already in the loop? */
/*if (has_looped)
amplitude_that_reaches_noise_floor = amplitude_that_reaches_noise_floor_loop;
else
amplitude_that_reaches_noise_floor = amplitude_that_reaches_noise_floor_nonloop;*/
float amplitude_that_reaches_noise_floor;
/* Is the playing pointer already in the loop? */
if (has_looped)
amplitude_that_reaches_noise_floor = amplitude_that_reaches_noise_floor_loop;
else
amplitude_that_reaches_noise_floor = amplitude_that_reaches_noise_floor_nonloop;
/* 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):
*/
/* 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):
*/
//amp_max = fluid_atten2amp (min_attenuation_cB) * volenv_val;
float amp_max = fluid_atten2amp (min_attenuation_cB) * volenv_val;
/* 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. */
if (amp_max < amplitude_that_reaches_noise_floor) {
positionToTurnOff = curPos;
}
/* 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. */
/*if (amp_max < amplitude_that_reaches_noise_floor) {
off();
ticks += n;
return;
}*/
}
if (curVolEnvSection->second != oldVolEnvSection->second) {
@ -476,6 +472,11 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
amp_incr = (target_amp - oldTargetAmp) / (curPos - lastPos);
lastPos = curPos;
Sample2AmpInc.insert(std::pair<int, qreal>(curPos, amp_incr));
// if voice is turned off after this no need to calculate any more values
if (positionToTurnOff > 0)
break;
oldTargetAmp = target_amp;
}
@ -486,17 +487,6 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
fluid_check_fpe ("voice_write amplitude calculation");
// REMOVED DUE TO CHANGE IN ENVELOPE CALCULATION
// is an optimization
// TODO: Make it work again with sample based volume
/* no volume and not changing? - No need to process */
//if ((amp == 0.0f) && (amp_incr == 0.0f)) {
// ticks += n;
// return;
// }
/* 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
@ -622,6 +612,7 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
float l_dsp_buf[n];
dsp_buf = l_dsp_buf;
memset(dsp_buf, 0, n*sizeof(float)); // init the arry with zeros so we can skip silent parts
unsigned count;
switch (interp_method) {
case FLUID_INTERP_NONE:
@ -642,8 +633,8 @@ void Voice::write(unsigned n, float* out, float* reverb, float* chorus)
if (count > 0)
effects(count, out, reverb, chorus);
/* turn off voice if short count (sample ended and not looping) */
if (count < n)
/* turn off voice if short count (sample ended and not looping) or voice reached noise floor*/
if (count < n || positionToTurnOff > 0)
off();
ticks += n;
@ -792,6 +783,7 @@ void Voice::voice_start()
* This cannot be done earlier, because it depends on modulators.
*/
check_sample_sanity_flag = FLUID_SAMPLESANITY_STARTUP;
positionToTurnOff = -1;
status = FLUID_VOICE_ON;
}

View file

@ -120,6 +120,7 @@ class Voice
float volenv_val;
float amplitude_that_reaches_noise_floor_nonloop;
float amplitude_that_reaches_noise_floor_loop;
int positionToTurnOff; // this is the sample accurate position where the sample reaches the noise floor
/* mod env */
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
@ -234,6 +235,7 @@ class Voice
void add_mod(const Mod* mod, int mode);
static void dsp_float_config();
bool updateAmpInc(unsigned int &nextNewAmpInc, std::map<int, qreal>::iterator &curSample2AmpInc, qreal &dsp_amp_incr, unsigned int &dsp_i);
int dsp_float_interpolate_none(unsigned);
int dsp_float_interpolate_linear(unsigned);
int dsp_float_interpolate_4th_order(unsigned);