Path: blob/master/libs/fluidsynth/src/rvoice/fluid_rev.c
4396 views
/******************************************************************************1* FluidSynth - A Software Synthesizer2*3* Copyright (C) 2003 Peter Hanappe and others.4*5* This library is free software; you can redistribute it and/or6* modify it under the terms of the GNU Lesser General Public License7* as published by the Free Software Foundation; either version 2.1 of8* the License, or (at your option) any later version.9*10* This library is distributed in the hope that it will be useful, but11* WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU13* Lesser General Public License for more details.14*15* You should have received a copy of the GNU Lesser General Public16* License along with this library; if not, write to the Free17* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA18* 02110-1301, USA19*20*21* FDN REVERB22*23* Freeverb used by fluidsynth (v.1.1.10 and previous) is based on24* Schroeder-Moorer reverberator:25* https://ccrma.stanford.edu/~jos/pasp/Freeverb.html26*27* This FDN reverberation is based on jot FDN reverberator.28* https://ccrma.stanford.edu/~jos/Reverb/FDN_Late_Reverberation.html29* Like Freeverb it is a late reverb which is convenient for Fluidsynth.30*31*32* .-------------------.33* .-----------------| |34* | - | Feedback |35* | .--------------| Matrix |36* | | |___________________|37* | | /|\ /|\38* \|/ | .---------. .-------. | - | .------.39* .->+ ---->| Delay 0 |-|L.P.F 0|--*-------->| |-> out40* .---------. | | |_________| |_______| | | | left41* |Tone | | | - - | |Stereo|42* In ->|corrector|--* | - - | | unit |43* mono |_________| | \|/ .---------. .-------. | | |-> out44* ---->+ ->| Delay 7 |-|L.P.F 7|--------*-->| | right45* |_________| |_______| |______|46* /|\ /|\ /|\ /|\47* | | | |48* roomsize --/ | width --/ |49* damp ------/ level ------/50*51* It takes a monophonic input and produces a stereo output.52*53* The parameters are the same than for Freeverb.54* Also the default response of these parameters are the same than for Freeverb:55* - roomsize (0 to 1): control the reverb time from 0.7 to 12.5 s.56* This reverberation time is ofen called T60DC.57*58* - damp (0 to 1): controls the reverb time frequency dependency.59* This controls the reverb time for the frequency sample rate/260*61* When 0, the reverb time for high frequencies is the same as62* for DC frequency.63* When > 0, high frequencies have less reverb time than lower frequencies.64*65* - width (0 to 100): controls the left/right output separation.66* When 0, there are no separation and the signal on left and right.67* output is the same. This sounds like a monophonic signal.68* When 100, the separation between left and right is maximum.69*70* - level (0 to 1), controls the output level reverberation.71*72* This FDN reverb produces a better quality reverberation tail than Freeverb with73* far less ringing by using modulated delay lines that help to cancel74* the building of a lot of resonances in the reverberation tail even when75* using only 8 delays lines (NBR_DELAYS = 8) (default).76*77* The frequency density (often called "modal density" is one property that78* contributes to sound quality. Although 8 lines give good result, using 12 delays79* lines brings the overall frequency density quality a bit higher.80* This quality augmentation is noticeable particularly when using long reverb time81* (roomsize = 1) on solo instrument with long release time. Of course the cpu load82* augmentation is +50% relatively to 8 lines.83*84* As a general rule the reverberation tail quality is easier to perceive by ear85* when using:86* - percussive instruments (i.e piano and others).87* - long reverb time (roomsize = 1).88* - no damping (damp = 0).89* - Using headphone. Avoid using loud speaker, you will be quickly misguided by the90* natural reverberation of the room in which you are.91*92* The cpu load for 8 lines is a bit lower than for freeverb (- 3%),93* but higher for 12 lines (+ 41%).94*95*96* The memory consumption is less than for freeverb97* (see the results table below).98*99* Two macros are usable at compiler time:100* - NBR_DELAYS: number of delay lines. 8 (default) or 12.101* - ROOMSIZE_RESPONSE_LINEAR: allows to choose an alternate response of102* roomsize parameter.103* When this macro is not defined (the default), roomsize has the same104* response that Freeverb, that is:105* - roomsize (0 to 1) controls concave reverb time (0.7 to 12.5 s).106*107* When this macro is defined, roomsize behaves linearly:108* - roomsize (0 to 1) controls reverb time linearly (0.7 to 12.5 s).109* This linear response is convenient when using GUI controls.110*111* --------------------------------------------------------------------------112* Compare table:113* Note: the cpu load in % are relative each to other. These values are114* given by the fluidsynth profile commands.115* --------------------------------------------------------------------------116* reverb | NBR_DELAYS | Performances | memory size | quality117* | | (cpu_load: %) | (bytes)(see note) |118* ==========================================================================119* freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing120* | 2 x 4 all-pass | | |121* ----------|---------------------------------------------------------------122* FDN | 8 | 0.650 % | 112480 | far less123* modulated | |(feeverb - 3%) | (56% freeverb) | ringing124* |---------------------------------------------------------------125* | 12 | 0.942 % | 168720 | best than126* | |(freeverb + 41%) | (82 %freeverb) | 8 lines127*---------------------------------------------------------------------------128*129* Note:130* Values in this column is the memory consumption for sample rate <= 44100Hz.131* For sample rate > 44100Hz , multiply these values by (sample rate / 44100Hz).132* For example: for sample rate 96000Hz, the memory consumed is 244760 bytes133*134*----------------------------------------------------------------------------135* 'Denormalise' method to avoid loss of performance.136* --------------------------------------------------137* According to music-dsp thread 'Denormalise', Pentium processors138* have a hardware 'feature', that is of interest here, related to139* numeric underflow. We have a recursive filter. The output decays140* exponentially, if the input stops. So the numbers get smaller and141* smaller... At some point, they reach 'denormal' level. This will142* lead to drastic spikes in the CPU load. The effect was reproduced143* with the reverb - sometimes the average load over 10 s doubles!!.144*145* The 'undenormalise' macro fixes the problem: As soon as the number146* is close enough to denormal level, the macro forces the number to147* 0.0f. The original macro is:148*149* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f150*151* This will zero out a number when it reaches the denormal level.152* Advantage: Maximum dynamic range Disadvantage: We'll have to check153* every sample, expensive. The alternative macro comes from a later154* mail from Jon Watte. It will zap a number before it reaches155* denormal level. Jon suggests to run it once per block instead of156* every sample.157*/158159/* Denormalising part II:160*161* Another method fixes the problem cheaper: Use a small DC-offset in162* the filter calculations. Now the signals converge not against 0,163* but against the offset. The constant offset is invisible from the164* outside world (i.e. it does not appear at the output. There is a165* very small turn-on transient response, which should not cause166* problems.167*/168#include "fluid_rev.h"169#include "fluid_sys.h"170171/*----------------------------------------------------------------------------172Configuration macros at compiler time.1731743 macros are usable at compiler time:175- NBR_DELAYs: number of delay lines. 8 (default) or 12.176- ROOMSIZE_RESPONSE_LINEAR: allows to choose an alternate response for177roomsize parameter.178- DENORMALISING enable denormalising handling.179-----------------------------------------------------------------------------*/180//#define INFOS_PRINT /* allows message to be printed on the console. */181182/* Number of delay lines (must be only 8 or 12)1838 is the default.18412 produces a better quality but is +50% cpu expensive.185*/186#define NBR_DELAYS 8 /* default*/187188/* response curve of parameter roomsize */189/*190The default response is the same as Freeverb:191- roomsize (0 to 1) controls concave reverb time (0.7 to 12.5 s).192193when ROOMSIZE_RESPONSE_LINEAR is defined, the response is:194- roomsize (0 to 1) controls reverb time linearly (0.7 to 12.5 s).195*/196//#define ROOMSIZE_RESPONSE_LINEAR197198/* DENORMALISING enable denormalising handling */199#define DENORMALISING200201#ifdef DENORMALISING202#define DC_OFFSET 1e-8f203#else204#define DC_OFFSET 0.0f205#endif206207/*----------------------------------------------------------------------------208Initial internal reverb settings (at reverb creation time)209-----------------------------------------------------------------------------*/210/* SCALE_WET_WIDTH is a compensation weight factor to get an output211amplitude (wet) rather independent of the width setting.2120: the output amplitude is fully dependent on the width setting.213>0: the output amplitude is less dependent on the width setting.214With a SCALE_WET_WIDTH of 0.2 the output amplitude is rather215independent of width setting (see fluid_revmodel_update()).216*/217#define SCALE_WET_WIDTH 0.2f218219/* It is best to inject the input signal less ofen. This contributes to obtain220a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. */221#define FIXED_GAIN 0.1f /* input gain */222223/* SCALE_WET is adjusted to 5.0 to get internal output level equivalent to freeverb */224#define SCALE_WET 5.0f /* scale output gain */225226/*----------------------------------------------------------------------------227Internal FDN late reverb settings228-----------------------------------------------------------------------------*/229230/*-- Reverberation time settings ----------------------------------231MIN_DC_REV_TIME est defined egal to the minimum value of freeverb:232MAX_DC_REV_TIME est defined egal to the maximum value of freeverb:233T60DC is computed from gi and the longest delay line in freeverb: L8 = 1617234T60 = -3 * Li * T / log10(gi)235T60 = -3 * Li * / (log10(gi) * sr)236237- Li: length of comb filter delay line.238- sr: sample rate.239- gi: the feedback gain.240241The minimum value for freeverb correspond to gi = 0.7.242with Mi = 1617, sr at 44100 Hz, and gi = 0.7 => MIN_DC_REV_TIME = 0.7 s243244The maximum value for freeverb correspond to gi = 0.98.245with Mi = 1617, sr at 44100 Hz, and gi = 0.98 => MAX_DC_REV_TIME = 12.5 s246*/247248#define MIN_DC_REV_TIME 0.7f /* minimum T60DC reverb time: seconds */249#define MAX_DC_REV_TIME 12.5f /* maximumm T60DC time in seconds */250#define RANGE_REV_TIME (MAX_DC_REV_TIME - MIN_DC_REV_TIME)251252/* macro to compute internal reverberation time versus roomsize parameter */253#define GET_DC_REV_TIME(roomsize) (MIN_DC_REV_TIME + RANGE_REV_TIME * roomsize)254255/*-- Modulation related settings ----------------------------------*/256/* For many instruments, the range for MOD_FREQ and MOD_DEPTH should be:257258MOD_DEPTH: [3..6] (in samples).259MOD_FREQ: [0.5 ..2.0] (in Hz).260261Values below the lower limits are often not sufficient to cancel unwanted262"ringing"(resonant frequency).263Values above upper limits augment the unwanted "chorus".264265With NBR_DELAYS to 8:266MOD_DEPTH must be >= 4 to cancel the unwanted "ringing".[4..6].267With NBR_DELAYS to 12:268MOD_DEPTH to 3 is sufficient to cancel the unwanted "ringing".[3..6]269*/270#define MOD_DEPTH 4 /* modulation depth (samples)*/271#define MOD_RATE 50 /* modulation rate (samples)*/272#define MOD_FREQ 1.0f /* modulation frequency (Hz) */273/*274Number of samples to add to the desired length of a delay line. This275allow to take account of modulation interpolation.2761 is sufficient with MOD_DEPTH equal to 4.277*/278#define INTERP_SAMPLES_NBR 1279280/* phase offset between modulators waveform */281#define MOD_PHASE (360.0f/(float) NBR_DELAYS)282283#if (NBR_DELAYS == 8)284#define DELAY_L0 601285#define DELAY_L1 691286#define DELAY_L2 773287#define DELAY_L3 839288#define DELAY_L4 919289#define DELAY_L5 997290#define DELAY_L6 1061291#define DELAY_L7 1129292#elif (NBR_DELAYS == 12)293#define DELAY_L0 601294#define DELAY_L1 691295#define DELAY_L2 773296#define DELAY_L3 839297#define DELAY_L4 919298#define DELAY_L5 997299#define DELAY_L6 1061300#define DELAY_L7 1093301#define DELAY_L8 1129302#define DELAY_L9 1151303#define DELAY_L10 1171304#define DELAY_L11 1187305#endif306307308/*---------------------------------------------------------------------------*/309/* The FDN late feed back matrix: A310T311A = P - 2 / N * u * u312N N N N313314N: the matrix dimension (i.e NBR_DELAYS).315P: permutation matrix.316u: is a column vector of 1.317318*/319#define FDN_MATRIX_FACTOR (fluid_real_t)(-2.0 / NBR_DELAYS)320321/*----------------------------------------------------------------------------322Internal FDN late structures and static functions323-----------------------------------------------------------------------------*/324325326/*-----------------------------------------------------------------------------327Delay absorbent low pass filter328-----------------------------------------------------------------------------*/329typedef struct330{331fluid_real_t buffer;332fluid_real_t b0, a1; /* filter coefficients */333} fdn_delay_lpf;334335/*-----------------------------------------------------------------------------336Sets coefficients for delay absorbent low pass filter.337@param lpf pointer on low pass filter structure.338@param b0,a1 coefficients.339-----------------------------------------------------------------------------*/340static void set_fdn_delay_lpf(fdn_delay_lpf *lpf,341fluid_real_t b0, fluid_real_t a1)342{343lpf->b0 = b0;344lpf->a1 = a1;345}346347/*-----------------------------------------------------------------------------348Process delay absorbent low pass filter.349@param mod_delay modulated delay line.350@param in, input sample.351@param out output sample.352-----------------------------------------------------------------------------*/353/* process low pass damping filter (input, output, delay) */354#define process_damping_filter(in,out,mod_delay) \355{\356out = in * mod_delay->dl.damping.b0 - mod_delay->dl.damping.buffer * \357mod_delay->dl.damping.a1;\358mod_delay->dl.damping.buffer = out;\359}\360361362/*-----------------------------------------------------------------------------363Delay line :364The delay line is composed of the line plus an absorbent low pass filter365to get frequency dependent reverb time.366-----------------------------------------------------------------------------*/367typedef struct368{369fluid_real_t *line; /* buffer line */370int size; /* effective internal size (in samples) */371/*-------------*/372int line_in; /* line in position */373int line_out; /* line out position */374/*-------------*/375fdn_delay_lpf damping; /* damping low pass filter */376} delay_line;377378379/*-----------------------------------------------------------------------------380Clears a delay line to DC_OFFSET float value.381@param dl pointer on delay line structure382-----------------------------------------------------------------------------*/383static void clear_delay_line(delay_line *dl)384{385int i;386387for(i = 0; i < dl->size; i++)388{389dl->line[i] = DC_OFFSET;390}391}392393/*-----------------------------------------------------------------------------394Push a sample val into the delay line395-----------------------------------------------------------------------------*/396#define push_in_delay_line(dl, val) \397{\398dl->line[dl->line_in] = val;\399/* Incrementation and circular motion if necessary */\400if(++dl->line_in >= dl->size) dl->line_in -= dl->size;\401}\402403/*-----------------------------------------------------------------------------404Modulator for modulated delay line405-----------------------------------------------------------------------------*/406407/*-----------------------------------------------------------------------------408Sinusoidal modulator409-----------------------------------------------------------------------------*/410/* modulator are integrated in modulated delay line */411typedef struct412{413fluid_real_t a1; /* Coefficient: a1 = 2 * cos(w) */414fluid_real_t buffer1; /* buffer1 */415fluid_real_t buffer2; /* buffer2 */416fluid_real_t reset_buffer2;/* reset value of buffer2 */417} sinus_modulator;418419/*-----------------------------------------------------------------------------420Sets the frequency of sinus oscillator.421422@param mod pointer on modulator structure.423@param freq frequency of the oscillator in Hz.424@param sample_rate sample rate on audio output in Hz.425@param phase initial phase of the oscillator in degree (0 to 360).426-----------------------------------------------------------------------------*/427static void set_mod_frequency(sinus_modulator *mod,428float freq, float sample_rate, float phase)429{430fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */431fluid_real_t a;432433mod->a1 = 2 * FLUID_COS(w);434435a = (2 * FLUID_M_PI / 360) * phase;436437mod->buffer2 = FLUID_SIN(a - w); /* y(n-1) = sin(-initial angle) */438mod->buffer1 = FLUID_SIN(a); /* y(n) = sin(initial phase) */439mod->reset_buffer2 = FLUID_SIN(FLUID_M_PI / 2 - w); /* reset value for PI/2 */440}441442/*-----------------------------------------------------------------------------443Gets current value of sinus modulator:444y(n) = a1 . y(n-1) - y(n-2)445out = a1 . buffer1 - buffer2446447@param pointer on modulator structure.448@return current value of the modulator sine wave.449-----------------------------------------------------------------------------*/450static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod)451{452fluid_real_t out;453out = mod->a1 * mod->buffer1 - mod->buffer2;454mod->buffer2 = mod->buffer1;455456if(out >= 1.0f) /* reset in case of instability near PI/2 */457{458out = 1.0f; /* forces output to the right value */459mod->buffer2 = mod->reset_buffer2;460}461462if(out <= -1.0f) /* reset in case of instability near -PI/2 */463{464out = -1.0f; /* forces output to the right value */465mod->buffer2 = - mod->reset_buffer2;466}467468mod->buffer1 = out;469return out;470}471472/*-----------------------------------------------------------------------------473Modulated delay line. The line is composed of:474- the delay line with its damping low pass filter.475- the sinusoidal modulator.476- center output position modulated by the modulator.477- variable rate control of center output position.478- first order All-Pass interpolator.479-----------------------------------------------------------------------------*/480typedef struct481{482/* delay line with damping low pass filter member */483delay_line dl; /* delayed line */484/*---------------------------*/485/* Sinusoidal modulator member */486sinus_modulator mod; /* sinus modulator */487/*-------------------------*/488/* center output position members */489fluid_real_t center_pos_mod; /* center output position modulated by modulator */490int mod_depth; /* modulation depth (in samples) */491/*-------------------------*/492/* variable rate control of center output position */493int index_rate; /* index rate to know when to update center_pos_mod */494int mod_rate; /* rate at which center_pos_mod is updated */495/*-------------------------*/496/* first order All-Pass interpolator members */497fluid_real_t frac_pos_mod; /* fractional position part between samples) */498/* previous value used when interpolating using fractional */499fluid_real_t buffer;500} mod_delay_line;501502/*-----------------------------------------------------------------------------503Return norminal delay length504505@param mdl, pointer on modulated delay line.506-----------------------------------------------------------------------------*/507static int get_mod_delay_line_length(mod_delay_line *mdl)508{509return (mdl->dl.size - mdl->mod_depth - INTERP_SAMPLES_NBR);510}511512/*-----------------------------------------------------------------------------513Reads the sample value out of the modulated delay line.514@param mdl, pointer on modulated delay line.515@return the sample value.516-----------------------------------------------------------------------------*/517static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl)518{519fluid_real_t out_index; /* new modulated index position */520int int_out_index; /* integer part of out_index */521fluid_real_t out; /* value to return */522523/* Checks if the modulator must be updated (every mod_rate samples). */524/* Important: center_pos_mod must be used immediately for the525first sample. So, mdl->index_rate must be initialized526to mdl->mod_rate (set_mod_delay_line()) */527528if(++mdl->index_rate >= mdl->mod_rate)529{530mdl->index_rate = 0;531532/* out_index = center position (center_pos_mod) + sinus waweform */533out_index = mdl->center_pos_mod +534get_mod_sinus(&mdl->mod) * mdl->mod_depth;535536/* extracts integer part in int_out_index */537if(out_index >= 0.0f)538{539int_out_index = (int)out_index; /* current integer part */540541/* forces read index (line_out) with integer modulation value */542/* Boundary check and circular motion as needed */543if((mdl->dl.line_out = int_out_index) >= mdl->dl.size)544{545mdl->dl.line_out -= mdl->dl.size;546}547}548else /* negative */549{550int_out_index = (int)(out_index - 1); /* previous integer part */551/* forces read index (line_out) with integer modulation value */552/* circular motion as needed */553mdl->dl.line_out = int_out_index + mdl->dl.size;554}555556/* extracts fractionnal part. (it will be used when interpolating557between line_out and line_out +1) and memorize it.558Memorizing is necessary for modulation rate above 1 */559mdl->frac_pos_mod = out_index - int_out_index;560561/* updates center position (center_pos_mod) to the next position562specified by modulation rate */563if((mdl->center_pos_mod += mdl->mod_rate) >= mdl->dl.size)564{565mdl->center_pos_mod -= mdl->dl.size;566}567}568569/* First order all-pass interpolation ----------------------------------*/570/* https://ccrma.stanford.edu/~jos/pasp/First_Order_Allpass_Interpolation.html */571/* begins interpolation: read current sample */572out = mdl->dl.line[mdl->dl.line_out];573574/* updates line_out to the next sample.575Boundary check and circular motion as needed */576if(++mdl->dl.line_out >= mdl->dl.size)577{578mdl->dl.line_out -= mdl->dl.size;579}580581/* Fractional interpolation between next sample (at next position) and582previous output added to current sample.583*/584out += mdl->frac_pos_mod * (mdl->dl.line[mdl->dl.line_out] - mdl->buffer);585mdl->buffer = out; /* memorizes current output */586return out;587}588589/*-----------------------------------------------------------------------------590Late structure591-----------------------------------------------------------------------------*/592struct _fluid_late593{594fluid_real_t samplerate; /* sample rate */595fluid_real_t sample_rate_max; /* sample rate maximum */596/*----- High pass tone corrector -------------------------------------*/597fluid_real_t tone_buffer;598fluid_real_t b1, b2;599/*----- Modulated delay lines lines ----------------------------------*/600mod_delay_line mod_delay_lines[NBR_DELAYS];601/*-----------------------------------------------------------------------*/602/* Output coefficients for separate Left and right stereo outputs */603fluid_real_t out_left_gain[NBR_DELAYS]; /* Left delay lines' output gains */604fluid_real_t out_right_gain[NBR_DELAYS];/* Right delay lines' output gains*/605};606607typedef struct _fluid_late fluid_late;608/*-----------------------------------------------------------------------------609fluidsynth reverb structure610-----------------------------------------------------------------------------*/611struct _fluid_revmodel_t612{613/* reverb parameters */614fluid_real_t roomsize; /* acting on reverb time */615fluid_real_t damp; /* acting on frequency dependent reverb time */616fluid_real_t level, wet1, wet2; /* output level */617fluid_real_t width; /* width stereo separation */618619/* fdn reverberation structure */620fluid_late late;621};622623/*-----------------------------------------------------------------------------624Updates Reverb time and absorbent filters coefficients from parameters:625626@param late pointer on late structure.627@param roomsize (0 to 1): acting on reverb time.628@param damping (0 to 1): acting on absorbent damping filter.629630Design formulas:631https://ccrma.stanford.edu/~jos/Reverb/First_Order_Delay_Filter_Design.html632https://ccrma.stanford.edu/~jos/Reverb/Tonal_Correction_Filter.html633-----------------------------------------------------------------------------*/634static void update_rev_time_damping(fluid_late *late,635fluid_real_t roomsize, fluid_real_t damp)636{637int i;638fluid_real_t sample_period = 1 / late->samplerate; /* Sampling period */639int delay_length; /* delay length */640fluid_real_t dc_rev_time; /* Reverb time at 0 Hz (in seconds) */641642fluid_real_t alpha, alpha2;643644/*--------------------------------------------645Computes dc_rev_time and alpha646----------------------------------------------*/647{648fluid_real_t gi_tmp, ai_tmp;649#ifdef ROOMSIZE_RESPONSE_LINEAR650/* roomsize parameter behave linearly:651* - roomsize (0 to 1) controls reverb time linearly (0.7 to 10 s).652* This linear response is convenient when using GUI controls.653*/654/*-----------------------------------------655Computes dc_rev_time656------------------------------------------*/657dc_rev_time = GET_DC_REV_TIME(roomsize);658delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]);659/* computes gi_tmp from dc_rev_time using relation E2 */660gi_tmp = FLUID_POW(10, -3 * delay_length *661sample_period / dc_rev_time); /* E2 */662#else663/* roomsize parameters have the same response that Freeverb, that is:664* - roomsize (0 to 1) controls concave reverb time (0.7 to 10 s).665*/666{667/*-----------------------------------------668Computes dc_rev_time669------------------------------------------*/670fluid_real_t gi_min, gi_max;671672/* values gi_min et gi_max are computed using E2 for the line with673maximum delay */674delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]);675gi_max = FLUID_POW(10, (-3 * delay_length / MAX_DC_REV_TIME) *676sample_period); /* E2 */677gi_min = FLUID_POW(10, (-3 * delay_length / MIN_DC_REV_TIME) *678sample_period); /* E2 */679/* gi = f(roomsize, gi_max, gi_min) */680gi_tmp = gi_min + roomsize * (gi_max - gi_min);681/* Computes T60DC from gi using inverse of relation E2.*/682dc_rev_time = -3 * FLUID_M_LN10 * delay_length * sample_period / FLUID_LOGF(gi_tmp);683}684#endif /* ROOMSIZE_RESPONSE_LINEAR */685/*--------------------------------------------686Computes alpha687----------------------------------------------*/688/* Computes alpha from damp,ai_tmp,gi_tmp using relation R */689/* - damp (0 to 1) controls concave reverb time for fs/2 frequency (T60DC to 0) */690ai_tmp = 1.0f * damp;691692/* Preserve the square of R */693alpha2 = 1.f / (1.f - ai_tmp / ((20.f / 80.f) * FLUID_LOGF(gi_tmp)));694695alpha = FLUID_SQRT(alpha2); /* R */696}697698/* updates tone corrector coefficients b1,b2 from alpha */699{700/*701Beta = (1 - alpha) / (1 + alpha)702b1 = 1/(1-beta)703b2 = beta * b1704*/705fluid_real_t beta = (1 - alpha) / (1 + alpha);706late->b1 = 1 / (1 - beta);707late->b2 = beta * late->b1;708late->tone_buffer = 0.0f;709}710711/* updates damping coefficients of all lines (gi , ai) from dc_rev_time, alpha */712for(i = 0; i < NBR_DELAYS; i++)713{714fluid_real_t gi, ai;715716/* delay length */717delay_length = get_mod_delay_line_length(&late->mod_delay_lines[i]);718719/* iir low pass filter gain */720gi = FLUID_POW(10, -3 * delay_length * sample_period / dc_rev_time);721722/* iir low pass filter feedback gain */723ai = (20.f / 80.f) * FLUID_LOGF(gi) * (1.f - 1.f / alpha2);724725/* b0 = gi * (1 - ai), a1 = - ai */726set_fdn_delay_lpf(&late->mod_delay_lines[i].dl.damping,727gi * (1.f - ai), -ai);728}729}730731/*-----------------------------------------------------------------------------732Updates stereo coefficients733@param late pointer on late structure734@param wet level integrated in stereo coefficients.735-----------------------------------------------------------------------------*/736static void update_stereo_coefficient(fluid_late *late, fluid_real_t wet1)737{738int i;739fluid_real_t wet;740741for(i = 0; i < NBR_DELAYS; i++)742{743/* delay lines output gains vectors Left and Right744745L R7460 | 1 1|7471 |-1 1|7482 | 1 -1|7493 |-1 -1|7507514 | 1 1|7525 |-1 1|753stereo gain = 6 | 1 -1|7547 |-1 -1|7557568 | 1 1|7579 |-1 1|75810| 1 -1|75911|-1 -1|760*/761762/* for left line: 00, ,02, ,04, ,06, ,08, ,10, ,12,... left_gain = +1 */763/* for left line: ,01, ,03, ,05, ,07, ,09, ,11,... left_gain = -1 */764wet = wet1;765if(i & 1)766{767wet = -wet1;768}769late->out_left_gain[i] = wet;770771/* for right line: 00,01, ,04,05, ,08,09, ,12,13 right_gain = +1 */772/* for right line: ,02 ,03, ,06,07, ,10,11,... right_gain = -1 */773wet = wet1;774if(i & 2)775{776wet = -wet1;777}778late->out_right_gain[i] = wet;779}780}781782/*-----------------------------------------------------------------------------783fluid_late destructor.784@param late pointer on late structure.785-----------------------------------------------------------------------------*/786static void delete_fluid_rev_late(fluid_late *late)787{788int i;789fluid_return_if_fail(late != NULL);790791/* free the delay lines */792for(i = 0; i < NBR_DELAYS; i++)793{794FLUID_FREE(late->mod_delay_lines[i].dl.line);795}796}797798799/* Nominal delay lines length table (in samples) */800static const int nom_delay_length[NBR_DELAYS] =801{802DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3,803DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7,804#if (NBR_DELAYS == 12)805DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11806#endif807};808809/*8101)"modal density" is one property that contributes to the quality of the reverb tail.811The more is the modal density, the less are unwanted resonant frequencies812build during the decay time: modal density = total delay / sample rate.813814Delay line's length given by static table delay_length[] are nominal815to get minimum modal density of 0.15 at sample rate 44100Hz.816Here we set length_factor to 2 to multiply this nominal modal817density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for818sample rate <= 44100.819820For sample rate > 44100, length_factor is multiplied by821sample_rate / 44100. This ensures that the default modal density keeps inchanged.822(Without this compensation, the default modal density would be diminished for823new sample rate change above 44100Hz).8248252)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing").826Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz.827For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures828that the effect of modulated delay line remains inchanged.829*/830static void compensate_from_sample_rate(fluid_real_t sample_rate,831fluid_real_t *mod_depth,832fluid_real_t *length_factor)833{834*mod_depth = MOD_DEPTH;835*length_factor = 2.0f;836if(sample_rate > 44100.0f)837{838fluid_real_t sample_rate_factor = sample_rate/44100.0f;839*length_factor *= sample_rate_factor;840*mod_depth *= sample_rate_factor;841}842}843844/*-----------------------------------------------------------------------------845Creates all modulated lines.846@param late, pointer on the fnd late reverb to initialize.847@param sample_rate_max, the maximum audio sample rate expected.848@return FLUID_OK if success, FLUID_FAILED otherwise.849-----------------------------------------------------------------------------*/850static int create_mod_delay_lines(fluid_late *late,851fluid_real_t sample_rate_max)852{853int i;854855fluid_real_t mod_depth, length_factor;856857/* compute mod_depth, length factor */858compensate_from_sample_rate(sample_rate_max, &mod_depth, &length_factor);859860late->sample_rate_max = sample_rate_max;861862#ifdef INFOS_PRINT // allows message to be printed on the console.863printf("length_factor:%f, mod_depth:%f\n", length_factor, mod_depth);864/* Print: modal density and total memory bytes */865{866int i;867int total_delay = 0; /* total delay in samples */868for (i = 0; i < NBR_DELAYS; i++)869{870int length = (length_factor * nom_delay_length[i])871+ mod_depth + INTERP_SAMPLES_NBR;872total_delay += length;873}874875/* modal density and total memory bytes */876printf("modal density:%f, total delay:%d, total memory:%d bytes\n",877total_delay / sample_rate_max ,total_delay ,878total_delay * sizeof(fluid_real_t));879}880#endif881882for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */883{884int delay_length = nom_delay_length[i] * length_factor;885mod_delay_line *mdl = &late->mod_delay_lines[i];886887/*-------------------------------------------------------------------*/888/* checks parameter */889if(delay_length < 1)890{891return FLUID_FAILED;892}893894/* limits mod_depth to the requested delay length */895if(mod_depth >= delay_length)896{897FLUID_LOG(FLUID_INFO,898"fdn reverb: modulation depth has been limited");899mod_depth = delay_length - 1;900}901902/*---------------------------------------------------------------------903allocates delay lines904*/905906/* real size of the line in use (in samples):907size = INTERP_SAMPLES_NBR + mod_depth + delay_length */908mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR;909mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size);910911if(! mdl->dl.line)912{913return FLUID_FAILED;914}915}916return FLUID_OK;917}918919/*-----------------------------------------------------------------------------920Initialize all modulated lines.921@param late, pointer on the fnd late reverb to initialize.922@param sample_rate, the audio sample rate.923@return FLUID_OK if success, FLUID_FAILED otherwise.924-----------------------------------------------------------------------------*/925static void initialize_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)926{927int i;928fluid_real_t mod_depth, length_factor;929930/* update delay line parameter dependent of sample rate */931late->samplerate = sample_rate;932933/* compute mod_depth, length factor */934compensate_from_sample_rate(sample_rate, &mod_depth, &length_factor);935936for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */937{938mod_delay_line *mdl = &late->mod_delay_lines[i];939int delay_length = nom_delay_length[i] * length_factor;940941/* limits mod_depth to the requested delay length */942if(mod_depth >= delay_length)943{944mod_depth = delay_length - 1;945}946947mdl->mod_depth = mod_depth;948949clear_delay_line(&mdl->dl); /* clears the buffer */950951/* Initializes line_in to the start of the buffer */952mdl->dl.line_in = 0;953954/* Initializes line_out index INTERP_SAMPLES_NBR samples after955line_in so that the delay between line_out and line_in is:956mod_depth + delay_length957*/958mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR;959960/* Damping low pass filter ------------------------------------------*/961mdl->dl.damping.buffer = 0;962963/*---------------------------------------------------------------------964Initializes modulation members:965- modulated center position: center_pos_mod966- modulation rate (the speed at which center_pos_mod is modulated: mod_rate967- index rate to know when to update center_pos_mod:index_rate968- interpolator member: buffer, frac_pos_mod969---------------------------------------------------------------------*/970/* Initializes the modulated center position (center_pos_mod) so that:971- the delay between line_out and center_pos_mod is mod_depth.972- the delay between center_pos_mod and line_in is delay_length.973*/974mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth;975976/* Sets the modulation rate. This rate defines how often977the center position (center_pos_mod ) is modulated .978The value is expressed in samples. The default value is 1 that means that979center_pos_mod is updated at every sample.980For example with a value of 2, the center position position will be981updated only one time every 2 samples only.982*/983if(MOD_RATE < 1 || MOD_RATE > mdl->dl.size)984{985FLUID_LOG(FLUID_INFO, "fdn reverb: modulation rate is out of range");986mdl->mod_rate = 1; /* default modulation rate: every one sample */987}988else989{990mdl->mod_rate = MOD_RATE;991}992993/* index rate to control when to update center_pos_mod.994Important: must be set to get center_pos_mod immediately used for995the reading of first sample (see get_mod_delay())996*/997mdl->index_rate = mdl->mod_rate;998999/* initializes first order All-Pass interpolator members */1000mdl->buffer = 0; /* previous delay sample value */1001mdl->frac_pos_mod = 0; /* frac. position (between consecutives sample) */100210031004/* Sets local Modulators parameters: frequency and phase.1005Each modulateur are shifted of MOD_PHASE degree1006*/1007set_mod_frequency(&mdl->mod,1008MOD_FREQ * MOD_RATE,1009sample_rate,1010(float)(MOD_PHASE * i));1011}1012}10131014/*1015Clears the delay lines.10161017@param rev pointer on the reverb.1018*/1019static void1020fluid_revmodel_init(fluid_revmodel_t *rev)1021{1022int i;10231024/* clears all the delay lines */1025for(i = 0; i < NBR_DELAYS; i ++)1026{1027clear_delay_line(&rev->late.mod_delay_lines[i].dl);1028}1029}103010311032/*1033updates internal parameters.10341035@param rev pointer on the reverb.1036*/1037static void1038fluid_revmodel_update(fluid_revmodel_t *rev)1039{1040/* Recalculate internal values after parameters change */10411042/* The stereo amplitude equation (wet1 and wet2 below) have a1043tendency to produce high amplitude with high width values ( 1 < width < 100).1044This results in an unwanted noisy output clipped by the audio card.1045To avoid this dependency, we divide by (1 + rev->width * SCALE_WET_WIDTH)1046Actually, with a SCALE_WET_WIDTH of 0.2, (regardless of level setting),1047the output amplitude (wet) seems rather independent of width setting */1048fluid_real_t wet = (rev->level * SCALE_WET) /1049(1.0f + rev->width * SCALE_WET_WIDTH);10501051/* wet1 and wet2 are used by the stereo effect controlled by the width setting1052for producing a stereo ouptput from a monophonic reverb signal.1053Please see the note above about a side effect tendency */10541055rev->wet1 = wet * (rev->width / 2.0f + 0.5f);1056rev->wet2 = wet * ((1.0f - rev->width) / 2.0f);10571058/* integrates wet1 in stereo coefficient (this will save one multiply) */1059update_stereo_coefficient(&rev->late, rev->wet1);10601061if(rev->wet1 > 0.0f)1062{1063rev->wet2 /= rev->wet1;1064}10651066/* Reverberation time and damping */1067update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);1068}10691070/*----------------------------------------------------------------------------1071Reverb API1072-----------------------------------------------------------------------------*/1073/*1074* Creates a reverb. Once created the reverb have no parameters set, so1075* fluid_revmodel_set() must be called at least one time after calling1076* new_fluid_revmodel().1077*1078* @param sample_rate_max maximum sample rate expected in Hz.1079*1080* @param sample_rate actual sample rate needed in Hz.1081* @return pointer on the new reverb or NULL if memory error.1082* Reverb API.1083*/1084fluid_revmodel_t *1085new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate)1086{1087fluid_revmodel_t *rev;10881089if(sample_rate <= 0)1090{1091return NULL;1092}10931094rev = FLUID_NEW(fluid_revmodel_t);10951096if(rev == NULL)1097{1098return NULL;1099}11001101FLUID_MEMSET(&rev->late, 0, sizeof(fluid_late));11021103/*--------------------------------------------------------------------------1104Create fdn late reverb.1105*/11061107/* update minimum value for sample_rate_max */1108if(sample_rate > sample_rate_max)1109{1110sample_rate_max = sample_rate;1111}11121113/*--------------------------------------------------------------------------1114Allocate the modulated delay lines1115*/1116if(create_mod_delay_lines(&rev->late, sample_rate_max) == FLUID_FAILED)1117{1118delete_fluid_revmodel(rev);1119return NULL;1120}11211122/*--------------------------------------------------------------------------1123Initialize the fdn reverb1124*/1125/* Initialize all modulated lines. */1126initialize_mod_delay_lines(&rev->late, sample_rate);11271128return rev;1129}11301131/*1132* free the reverb.1133* Note that while the reverb is used by calling any fluid_revmodel_processXXX()1134* function, calling delete_fluid_revmodel() isn't multi task safe because1135* delay line are freed. To deal properly with this issue follow the steps:1136*1137* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().1138* reverb functions.1139* 2) Delete the reverb by calling delete_fluid_revmodel().1140*1141* @param rev pointer on reverb to free.1142* Reverb API.1143*/1144void1145delete_fluid_revmodel(fluid_revmodel_t *rev)1146{1147fluid_return_if_fail(rev != NULL);1148delete_fluid_rev_late(&rev->late);1149FLUID_FREE(rev);1150}11511152/*1153* Sets one or more reverb parameters. Note this must be called at least one1154* time after calling new_fluid_revmodel() and before any call to1155* fluid_revmodel_processXXX() and fluid_revmodel_samplerate_change().1156*1157* Note that while the reverb is used by calling any fluid_revmodel_processXXX()1158* function, calling fluid_revmodel_set() could produce audible clics.1159* If this is a problem, optionally call fluid_revmodel_reset() before calling1160* fluid_revmodel_set().1161*1162* @param rev Reverb instance.1163* @param set One or more flags from #fluid_revmodel_set_t indicating what1164* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters).1165* @param roomsize Reverb room size.1166* @param damping Reverb damping.1167* @param width Reverb width.1168* @param level Reverb level.1169*1170* Reverb API.1171*/1172void1173fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,1174fluid_real_t damping, fluid_real_t width, fluid_real_t level)1175{1176fluid_return_if_fail(rev != NULL);11771178/*-----------------------------------*/1179if(set & FLUID_REVMODEL_SET_ROOMSIZE)1180{1181fluid_clip(roomsize, 0.0f, 1.0f);1182rev->roomsize = roomsize;1183}11841185/*-----------------------------------*/1186if(set & FLUID_REVMODEL_SET_DAMPING)1187{1188fluid_clip(damping, 0.0f, 1.0f);1189rev->damp = damping;1190}11911192/*-----------------------------------*/1193if(set & FLUID_REVMODEL_SET_WIDTH)1194{1195rev->width = width;1196}11971198/*-----------------------------------*/1199if(set & FLUID_REVMODEL_SET_LEVEL)1200{1201fluid_clip(level, 0.0f, 1.0f);1202rev->level = level;1203}12041205/* updates internal parameters */1206fluid_revmodel_update(rev);1207}12081209/*1210* Applies a sample rate change on the reverb.1211* fluid_revmodel_set() must be called at least one time before calling1212* this function.1213*1214* Note that while the reverb is used by calling any fluid_revmodel_processXXX()1215* function, calling fluid_revmodel_samplerate_change() isn't multi task safe.1216* To deal properly with this issue follow the steps:1217* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().1218* reverb functions.1219* Optionally, call fluid_revmodel_reset() to damp the reverb.1220* 2) Change sample rate by calling fluid_revmodel_samplerate_change().1221* 3) Restart reverb processing (i.e enabling calling of any fluid_revmodel_processXXX()1222* reverb functions.1223*1224* Another solution is to substitute step (2):1225* 2.1) delete the reverb by calling delete_fluid_revmodel().1226* 2.2) create the reverb by calling new_fluid_revmodel().1227*1228* The best solution would be that this function be called only by the same task1229* calling fluid_revmodel_processXXX().1230*1231* @param rev the reverb.1232* @param sample_rate new sample rate value. Must be <= sample_rate_max1233* @return FLUID_OK if success, FLUID_FAILED if new sample rate is greater1234* then the maximumum sample rate set at creation time. The reverb will1235* continue to work but with possible lost of quality.1236* If this is a problem, the caller should follow steps 2.1 and 2.2.1237* Reverb API.1238*/1239int1240fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)1241{1242int status = FLUID_OK;12431244fluid_return_val_if_fail(rev != NULL, FLUID_FAILED);12451246if(sample_rate > rev->late.sample_rate_max)1247{1248FLUID_LOG(FLUID_WARN,1249"fdn reverb: sample rate %.0f Hz is deduced to %.0f Hz\n",1250sample_rate, rev->late.sample_rate_max);12511252/* Reduce sample rate to the maximum value set at creation time.1253The reverb will continue to work with possible lost of quality.1254*/1255sample_rate = rev->late.sample_rate_max;1256status = FLUID_FAILED;1257}12581259/* Initialize all modulated lines according to sample rate change. */1260initialize_mod_delay_lines(&rev->late, sample_rate);12611262/* updates damping filter coefficients according to sample rate change */1263update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);12641265return status;1266}12671268/*1269* Damps the reverb by clearing the delay lines.1270* @param rev the reverb.1271*1272* Reverb API.1273*/1274void1275fluid_revmodel_reset(fluid_revmodel_t *rev)1276{1277fluid_return_if_fail(rev != NULL);12781279fluid_revmodel_init(rev);1280}12811282/*-----------------------------------------------------------------------------1283* fdn reverb process replace.1284* @param rev pointer on reverb.1285* @param in monophonic buffer input (FLUID_BUFSIZE sample).1286* @param left_out stereo left processed output (FLUID_BUFSIZE sample).1287* @param right_out stereo right processed output (FLUID_BUFSIZE sample).1288*1289* The processed reverb is replacing anything there in out.1290* Reverb API.1291-----------------------------------------------------------------------------*/1292void1293fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in,1294fluid_real_t *left_out, fluid_real_t *right_out)1295{1296int i, k;12971298fluid_real_t xn; /* mono input x(n) */1299fluid_real_t out_tone_filter; /* tone corrector output */1300fluid_real_t out_left, out_right; /* output stereo Left and Right */1301fluid_real_t matrix_factor; /* partial matrix computation */1302fluid_real_t delay_out_s; /* sample */1303fluid_real_t delay_out[NBR_DELAYS]; /* Line output + damper output */13041305for(k = 0; k < FLUID_BUFSIZE; k++)1306{1307/* stereo output */1308out_left = out_right = 0;13091310#ifdef DENORMALISING1311/* Input is adjusted by DC_OFFSET. */1312xn = (in[k]) * FIXED_GAIN + DC_OFFSET;1313#else1314xn = (in[k]) * FIXED_GAIN;1315#endif13161317/*--------------------------------------------------------------------1318tone correction.1319*/1320out_tone_filter = xn * rev->late.b1 - rev->late.b2 * rev->late.tone_buffer;1321rev->late.tone_buffer = xn;1322xn = out_tone_filter;1323/*--------------------------------------------------------------------1324process feedback delayed network:1325- xn is the input signal.1326- before inserting in the line input we first we get the delay lines1327output, filter them and compute output in delay_out[].1328- also matrix_factor is computed (to simplify further matrix product)1329---------------------------------------------------------------------*/1330/* We begin with the modulated output delay line + damping filter */1331matrix_factor = 0;13321333for(i = 0; i < NBR_DELAYS; i++)1334{1335mod_delay_line *mdl = &rev->late.mod_delay_lines[i];1336/* get current modulated output */1337delay_out_s = get_mod_delay(mdl);13381339/* process low pass damping filter1340(input:delay_out_s, output:delay_out_s) */1341process_damping_filter(delay_out_s, delay_out_s, mdl);13421343/* Result in delay_out[], and matrix_factor.1344These will be of use later during input line process */1345delay_out[i] = delay_out_s; /* result in delay_out[] */1346matrix_factor += delay_out_s; /* result in matrix_factor */13471348/* Process stereo output */1349/* stereo left = left + out_left_gain * delay_out */1350out_left += rev->late.out_left_gain[i] * delay_out_s;1351/* stereo right= right+ out_right_gain * delay_out */1352out_right += rev->late.out_right_gain[i] * delay_out_s;1353}13541355/* now we process the input delay line.Each input is a combination of1356- xn: input signal1357- delay_out[] the output of a delay line given by a permutation matrix P1358- and matrix_factor.1359This computes: in_delay_line = xn + (delay_out[] * matrix A) with1360an algorithm equivalent but faster than using a product with matrix A.1361*/1362/* matrix_factor = output sum * (-2.0)/N */1363matrix_factor *= FDN_MATRIX_FACTOR;1364matrix_factor += xn; /* adds reverb input signal */13651366for(i = 1; i < NBR_DELAYS; i++)1367{1368/* delay_in[i-1] = delay_out[i] + matrix_factor */1369delay_line *dl = &rev->late.mod_delay_lines[i - 1].dl;1370push_in_delay_line(dl, delay_out[i] + matrix_factor);1371}13721373/* last line input (NB_DELAY-1) */1374/* delay_in[0] = delay_out[NB_DELAY -1] + matrix_factor */1375{1376delay_line *dl = &rev->late.mod_delay_lines[NBR_DELAYS - 1].dl;1377push_in_delay_line(dl, delay_out[0] + matrix_factor);1378}13791380/*-------------------------------------------------------------------*/1381#ifdef DENORMALISING1382/* Removes the DC offset */1383out_left -= DC_OFFSET;1384out_right -= DC_OFFSET;1385#endif13861387/* Calculates stereo output REPLACING anything already there: */1388/*1389left_out[k] = out_left * rev->wet1 + out_right * rev->wet2;1390right_out[k] = out_right * rev->wet1 + out_left * rev->wet2;13911392As wet1 is integrated in stereo coefficient wet 1 is now1393integrated in out_left and out_right, so we simplify previous1394relation by suppression of one multiply as this:13951396left_out[k] = out_left + out_right * rev->wet2;1397right_out[k] = out_right + out_left * rev->wet2;1398*/1399left_out[k] = out_left + out_right * rev->wet2;1400right_out[k] = out_right + out_left * rev->wet2;1401}1402}140314041405/*-----------------------------------------------------------------------------1406* fdn reverb process mix.1407* @param rev pointer on reverb.1408* @param in monophonic buffer input (FLUID_BUFSIZE samples).1409* @param left_out stereo left processed output (FLUID_BUFSIZE samples).1410* @param right_out stereo right processed output (FLUID_BUFSIZE samples).1411*1412* The processed reverb is mixed in out with samples already there in out.1413* Reverb API.1414-----------------------------------------------------------------------------*/1415void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,1416fluid_real_t *left_out, fluid_real_t *right_out)1417{1418int i, k;14191420fluid_real_t xn; /* mono input x(n) */1421fluid_real_t out_tone_filter; /* tone corrector output */1422fluid_real_t out_left, out_right; /* output stereo Left and Right */1423fluid_real_t matrix_factor; /* partial matrix term */1424fluid_real_t delay_out_s; /* sample */1425fluid_real_t delay_out[NBR_DELAYS]; /* Line output + damper output */14261427for(k = 0; k < FLUID_BUFSIZE; k++)1428{1429/* stereo output */1430out_left = out_right = 0;1431#ifdef DENORMALISING1432/* Input is adjusted by DC_OFFSET. */1433xn = (in[k]) * FIXED_GAIN + DC_OFFSET;1434#else1435xn = (in[k]) * FIXED_GAIN;1436#endif14371438/*--------------------------------------------------------------------1439tone correction1440*/1441out_tone_filter = xn * rev->late.b1 - rev->late.b2 * rev->late.tone_buffer;1442rev->late.tone_buffer = xn;1443xn = out_tone_filter;1444/*--------------------------------------------------------------------1445process feedback delayed network:1446- xn is the input signal.1447- before inserting in the line input we first we get the delay lines1448output, filter them and compute output in local delay_out[].1449- also matrix_factor is computed (to simplify further matrix product).1450---------------------------------------------------------------------*/1451/* We begin with the modulated output delay line + damping filter */1452matrix_factor = 0;14531454for(i = 0; i < NBR_DELAYS; i++)1455{1456mod_delay_line *mdl = &rev->late.mod_delay_lines[i];1457/* get current modulated output */1458delay_out_s = get_mod_delay(mdl);14591460/* process low pass damping filter1461(input:delay_out_s, output:delay_out_s) */1462process_damping_filter(delay_out_s, delay_out_s, mdl);14631464/* Result in delay_out[], and matrix_factor.1465These will be of use later during input line process */1466delay_out[i] = delay_out_s; /* result in delay_out[] */1467matrix_factor += delay_out_s; /* result in matrix_factor */14681469/* Process stereo output */1470/* stereo left = left + out_left_gain * delay_out */1471out_left += rev->late.out_left_gain[i] * delay_out_s;1472/* stereo right= right+ out_right_gain * delay_out */1473out_right += rev->late.out_right_gain[i] * delay_out_s;1474}14751476/* now we process the input delay line. Each input is a combination of:1477- xn: input signal1478- delay_out[] the output of a delay line given by a permutation matrix P1479- and matrix_factor.1480This computes: in_delay_line = xn + (delay_out[] * matrix A) with1481an algorithm equivalent but faster than using a product with matrix A.1482*/1483/* matrix_factor = output sum * (-2.0)/N */1484matrix_factor *= FDN_MATRIX_FACTOR;1485matrix_factor += xn; /* adds reverb input signal */14861487for(i = 1; i < NBR_DELAYS; i++)1488{1489/* delay_in[i-1] = delay_out[i] + matrix_factor */1490delay_line *dl = &rev->late.mod_delay_lines[i - 1].dl;1491push_in_delay_line(dl, delay_out[i] + matrix_factor);1492}14931494/* last line input (NB_DELAY-1) */1495/* delay_in[0] = delay_out[NB_DELAY -1] + matrix_factor */1496{1497delay_line *dl = &rev->late.mod_delay_lines[NBR_DELAYS - 1].dl;1498push_in_delay_line(dl, delay_out[0] + matrix_factor);1499}15001501/*-------------------------------------------------------------------*/1502#ifdef DENORMALISING1503/* Removes the DC offset */1504out_left -= DC_OFFSET;1505out_right -= DC_OFFSET;1506#endif1507/* Calculates stereo output MIXING anything already there: */1508/*1509left_out[k] += out_left * rev->wet1 + out_right * rev->wet2;1510right_out[k] += out_right * rev->wet1 + out_left * rev->wet2;15111512As wet1 is integrated in stereo coefficient wet 1 is now1513integrated in out_left and out_right, so we simplify previous1514relation by suppression of one multiply as this:15151516left_out[k] += out_left + out_right * rev->wet2;1517right_out[k] += out_right + out_left * rev->wet2;1518*/1519left_out[k] += out_left + out_right * rev->wet2;1520right_out[k] += out_right + out_left * rev->wet2;1521}1522}152315241525