Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/fluidsynth/src/rvoice/fluid_rev.c
4396 views
1
/******************************************************************************
2
* FluidSynth - A Software Synthesizer
3
*
4
* Copyright (C) 2003 Peter Hanappe and others.
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public License
8
* as published by the Free Software Foundation; either version 2.1 of
9
* the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free
18
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
* 02110-1301, USA
20
*
21
*
22
* FDN REVERB
23
*
24
* Freeverb used by fluidsynth (v.1.1.10 and previous) is based on
25
* Schroeder-Moorer reverberator:
26
* https://ccrma.stanford.edu/~jos/pasp/Freeverb.html
27
*
28
* This FDN reverberation is based on jot FDN reverberator.
29
* https://ccrma.stanford.edu/~jos/Reverb/FDN_Late_Reverberation.html
30
* Like Freeverb it is a late reverb which is convenient for Fluidsynth.
31
*
32
*
33
* .-------------------.
34
* .-----------------| |
35
* | - | Feedback |
36
* | .--------------| Matrix |
37
* | | |___________________|
38
* | | /|\ /|\
39
* \|/ | .---------. .-------. | - | .------.
40
* .->+ ---->| Delay 0 |-|L.P.F 0|--*-------->| |-> out
41
* .---------. | | |_________| |_______| | | | left
42
* |Tone | | | - - | |Stereo|
43
* In ->|corrector|--* | - - | | unit |
44
* mono |_________| | \|/ .---------. .-------. | | |-> out
45
* ---->+ ->| Delay 7 |-|L.P.F 7|--------*-->| | right
46
* |_________| |_______| |______|
47
* /|\ /|\ /|\ /|\
48
* | | | |
49
* roomsize --/ | width --/ |
50
* damp ------/ level ------/
51
*
52
* It takes a monophonic input and produces a stereo output.
53
*
54
* The parameters are the same than for Freeverb.
55
* Also the default response of these parameters are the same than for Freeverb:
56
* - roomsize (0 to 1): control the reverb time from 0.7 to 12.5 s.
57
* This reverberation time is ofen called T60DC.
58
*
59
* - damp (0 to 1): controls the reverb time frequency dependency.
60
* This controls the reverb time for the frequency sample rate/2
61
*
62
* When 0, the reverb time for high frequencies is the same as
63
* for DC frequency.
64
* When > 0, high frequencies have less reverb time than lower frequencies.
65
*
66
* - width (0 to 100): controls the left/right output separation.
67
* When 0, there are no separation and the signal on left and right.
68
* output is the same. This sounds like a monophonic signal.
69
* When 100, the separation between left and right is maximum.
70
*
71
* - level (0 to 1), controls the output level reverberation.
72
*
73
* This FDN reverb produces a better quality reverberation tail than Freeverb with
74
* far less ringing by using modulated delay lines that help to cancel
75
* the building of a lot of resonances in the reverberation tail even when
76
* using only 8 delays lines (NBR_DELAYS = 8) (default).
77
*
78
* The frequency density (often called "modal density" is one property that
79
* contributes to sound quality. Although 8 lines give good result, using 12 delays
80
* lines brings the overall frequency density quality a bit higher.
81
* This quality augmentation is noticeable particularly when using long reverb time
82
* (roomsize = 1) on solo instrument with long release time. Of course the cpu load
83
* augmentation is +50% relatively to 8 lines.
84
*
85
* As a general rule the reverberation tail quality is easier to perceive by ear
86
* when using:
87
* - percussive instruments (i.e piano and others).
88
* - long reverb time (roomsize = 1).
89
* - no damping (damp = 0).
90
* - Using headphone. Avoid using loud speaker, you will be quickly misguided by the
91
* natural reverberation of the room in which you are.
92
*
93
* The cpu load for 8 lines is a bit lower than for freeverb (- 3%),
94
* but higher for 12 lines (+ 41%).
95
*
96
*
97
* The memory consumption is less than for freeverb
98
* (see the results table below).
99
*
100
* Two macros are usable at compiler time:
101
* - NBR_DELAYS: number of delay lines. 8 (default) or 12.
102
* - ROOMSIZE_RESPONSE_LINEAR: allows to choose an alternate response of
103
* roomsize parameter.
104
* When this macro is not defined (the default), roomsize has the same
105
* response that Freeverb, that is:
106
* - roomsize (0 to 1) controls concave reverb time (0.7 to 12.5 s).
107
*
108
* When this macro is defined, roomsize behaves linearly:
109
* - roomsize (0 to 1) controls reverb time linearly (0.7 to 12.5 s).
110
* This linear response is convenient when using GUI controls.
111
*
112
* --------------------------------------------------------------------------
113
* Compare table:
114
* Note: the cpu load in % are relative each to other. These values are
115
* given by the fluidsynth profile commands.
116
* --------------------------------------------------------------------------
117
* reverb | NBR_DELAYS | Performances | memory size | quality
118
* | | (cpu_load: %) | (bytes)(see note) |
119
* ==========================================================================
120
* freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing
121
* | 2 x 4 all-pass | | |
122
* ----------|---------------------------------------------------------------
123
* FDN | 8 | 0.650 % | 112480 | far less
124
* modulated | |(feeverb - 3%) | (56% freeverb) | ringing
125
* |---------------------------------------------------------------
126
* | 12 | 0.942 % | 168720 | best than
127
* | |(freeverb + 41%) | (82 %freeverb) | 8 lines
128
*---------------------------------------------------------------------------
129
*
130
* Note:
131
* Values in this column is the memory consumption for sample rate <= 44100Hz.
132
* For sample rate > 44100Hz , multiply these values by (sample rate / 44100Hz).
133
* For example: for sample rate 96000Hz, the memory consumed is 244760 bytes
134
*
135
*----------------------------------------------------------------------------
136
* 'Denormalise' method to avoid loss of performance.
137
* --------------------------------------------------
138
* According to music-dsp thread 'Denormalise', Pentium processors
139
* have a hardware 'feature', that is of interest here, related to
140
* numeric underflow. We have a recursive filter. The output decays
141
* exponentially, if the input stops. So the numbers get smaller and
142
* smaller... At some point, they reach 'denormal' level. This will
143
* lead to drastic spikes in the CPU load. The effect was reproduced
144
* with the reverb - sometimes the average load over 10 s doubles!!.
145
*
146
* The 'undenormalise' macro fixes the problem: As soon as the number
147
* is close enough to denormal level, the macro forces the number to
148
* 0.0f. The original macro is:
149
*
150
* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
151
*
152
* This will zero out a number when it reaches the denormal level.
153
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
154
* every sample, expensive. The alternative macro comes from a later
155
* mail from Jon Watte. It will zap a number before it reaches
156
* denormal level. Jon suggests to run it once per block instead of
157
* every sample.
158
*/
159
160
/* Denormalising part II:
161
*
162
* Another method fixes the problem cheaper: Use a small DC-offset in
163
* the filter calculations. Now the signals converge not against 0,
164
* but against the offset. The constant offset is invisible from the
165
* outside world (i.e. it does not appear at the output. There is a
166
* very small turn-on transient response, which should not cause
167
* problems.
168
*/
169
#include "fluid_rev.h"
170
#include "fluid_sys.h"
171
172
/*----------------------------------------------------------------------------
173
Configuration macros at compiler time.
174
175
3 macros are usable at compiler time:
176
- NBR_DELAYs: number of delay lines. 8 (default) or 12.
177
- ROOMSIZE_RESPONSE_LINEAR: allows to choose an alternate response for
178
roomsize parameter.
179
- DENORMALISING enable denormalising handling.
180
-----------------------------------------------------------------------------*/
181
//#define INFOS_PRINT /* allows message to be printed on the console. */
182
183
/* Number of delay lines (must be only 8 or 12)
184
8 is the default.
185
12 produces a better quality but is +50% cpu expensive.
186
*/
187
#define NBR_DELAYS 8 /* default*/
188
189
/* response curve of parameter roomsize */
190
/*
191
The default response is the same as Freeverb:
192
- roomsize (0 to 1) controls concave reverb time (0.7 to 12.5 s).
193
194
when ROOMSIZE_RESPONSE_LINEAR is defined, the response is:
195
- roomsize (0 to 1) controls reverb time linearly (0.7 to 12.5 s).
196
*/
197
//#define ROOMSIZE_RESPONSE_LINEAR
198
199
/* DENORMALISING enable denormalising handling */
200
#define DENORMALISING
201
202
#ifdef DENORMALISING
203
#define DC_OFFSET 1e-8f
204
#else
205
#define DC_OFFSET 0.0f
206
#endif
207
208
/*----------------------------------------------------------------------------
209
Initial internal reverb settings (at reverb creation time)
210
-----------------------------------------------------------------------------*/
211
/* SCALE_WET_WIDTH is a compensation weight factor to get an output
212
amplitude (wet) rather independent of the width setting.
213
0: the output amplitude is fully dependent on the width setting.
214
>0: the output amplitude is less dependent on the width setting.
215
With a SCALE_WET_WIDTH of 0.2 the output amplitude is rather
216
independent of width setting (see fluid_revmodel_update()).
217
*/
218
#define SCALE_WET_WIDTH 0.2f
219
220
/* It is best to inject the input signal less ofen. This contributes to obtain
221
a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. */
222
#define FIXED_GAIN 0.1f /* input gain */
223
224
/* SCALE_WET is adjusted to 5.0 to get internal output level equivalent to freeverb */
225
#define SCALE_WET 5.0f /* scale output gain */
226
227
/*----------------------------------------------------------------------------
228
Internal FDN late reverb settings
229
-----------------------------------------------------------------------------*/
230
231
/*-- Reverberation time settings ----------------------------------
232
MIN_DC_REV_TIME est defined egal to the minimum value of freeverb:
233
MAX_DC_REV_TIME est defined egal to the maximum value of freeverb:
234
T60DC is computed from gi and the longest delay line in freeverb: L8 = 1617
235
T60 = -3 * Li * T / log10(gi)
236
T60 = -3 * Li * / (log10(gi) * sr)
237
238
- Li: length of comb filter delay line.
239
- sr: sample rate.
240
- gi: the feedback gain.
241
242
The minimum value for freeverb correspond to gi = 0.7.
243
with Mi = 1617, sr at 44100 Hz, and gi = 0.7 => MIN_DC_REV_TIME = 0.7 s
244
245
The maximum value for freeverb correspond to gi = 0.98.
246
with Mi = 1617, sr at 44100 Hz, and gi = 0.98 => MAX_DC_REV_TIME = 12.5 s
247
*/
248
249
#define MIN_DC_REV_TIME 0.7f /* minimum T60DC reverb time: seconds */
250
#define MAX_DC_REV_TIME 12.5f /* maximumm T60DC time in seconds */
251
#define RANGE_REV_TIME (MAX_DC_REV_TIME - MIN_DC_REV_TIME)
252
253
/* macro to compute internal reverberation time versus roomsize parameter */
254
#define GET_DC_REV_TIME(roomsize) (MIN_DC_REV_TIME + RANGE_REV_TIME * roomsize)
255
256
/*-- Modulation related settings ----------------------------------*/
257
/* For many instruments, the range for MOD_FREQ and MOD_DEPTH should be:
258
259
MOD_DEPTH: [3..6] (in samples).
260
MOD_FREQ: [0.5 ..2.0] (in Hz).
261
262
Values below the lower limits are often not sufficient to cancel unwanted
263
"ringing"(resonant frequency).
264
Values above upper limits augment the unwanted "chorus".
265
266
With NBR_DELAYS to 8:
267
MOD_DEPTH must be >= 4 to cancel the unwanted "ringing".[4..6].
268
With NBR_DELAYS to 12:
269
MOD_DEPTH to 3 is sufficient to cancel the unwanted "ringing".[3..6]
270
*/
271
#define MOD_DEPTH 4 /* modulation depth (samples)*/
272
#define MOD_RATE 50 /* modulation rate (samples)*/
273
#define MOD_FREQ 1.0f /* modulation frequency (Hz) */
274
/*
275
Number of samples to add to the desired length of a delay line. This
276
allow to take account of modulation interpolation.
277
1 is sufficient with MOD_DEPTH equal to 4.
278
*/
279
#define INTERP_SAMPLES_NBR 1
280
281
/* phase offset between modulators waveform */
282
#define MOD_PHASE (360.0f/(float) NBR_DELAYS)
283
284
#if (NBR_DELAYS == 8)
285
#define DELAY_L0 601
286
#define DELAY_L1 691
287
#define DELAY_L2 773
288
#define DELAY_L3 839
289
#define DELAY_L4 919
290
#define DELAY_L5 997
291
#define DELAY_L6 1061
292
#define DELAY_L7 1129
293
#elif (NBR_DELAYS == 12)
294
#define DELAY_L0 601
295
#define DELAY_L1 691
296
#define DELAY_L2 773
297
#define DELAY_L3 839
298
#define DELAY_L4 919
299
#define DELAY_L5 997
300
#define DELAY_L6 1061
301
#define DELAY_L7 1093
302
#define DELAY_L8 1129
303
#define DELAY_L9 1151
304
#define DELAY_L10 1171
305
#define DELAY_L11 1187
306
#endif
307
308
309
/*---------------------------------------------------------------------------*/
310
/* The FDN late feed back matrix: A
311
T
312
A = P - 2 / N * u * u
313
N N N N
314
315
N: the matrix dimension (i.e NBR_DELAYS).
316
P: permutation matrix.
317
u: is a column vector of 1.
318
319
*/
320
#define FDN_MATRIX_FACTOR (fluid_real_t)(-2.0 / NBR_DELAYS)
321
322
/*----------------------------------------------------------------------------
323
Internal FDN late structures and static functions
324
-----------------------------------------------------------------------------*/
325
326
327
/*-----------------------------------------------------------------------------
328
Delay absorbent low pass filter
329
-----------------------------------------------------------------------------*/
330
typedef struct
331
{
332
fluid_real_t buffer;
333
fluid_real_t b0, a1; /* filter coefficients */
334
} fdn_delay_lpf;
335
336
/*-----------------------------------------------------------------------------
337
Sets coefficients for delay absorbent low pass filter.
338
@param lpf pointer on low pass filter structure.
339
@param b0,a1 coefficients.
340
-----------------------------------------------------------------------------*/
341
static void set_fdn_delay_lpf(fdn_delay_lpf *lpf,
342
fluid_real_t b0, fluid_real_t a1)
343
{
344
lpf->b0 = b0;
345
lpf->a1 = a1;
346
}
347
348
/*-----------------------------------------------------------------------------
349
Process delay absorbent low pass filter.
350
@param mod_delay modulated delay line.
351
@param in, input sample.
352
@param out output sample.
353
-----------------------------------------------------------------------------*/
354
/* process low pass damping filter (input, output, delay) */
355
#define process_damping_filter(in,out,mod_delay) \
356
{\
357
out = in * mod_delay->dl.damping.b0 - mod_delay->dl.damping.buffer * \
358
mod_delay->dl.damping.a1;\
359
mod_delay->dl.damping.buffer = out;\
360
}\
361
362
363
/*-----------------------------------------------------------------------------
364
Delay line :
365
The delay line is composed of the line plus an absorbent low pass filter
366
to get frequency dependent reverb time.
367
-----------------------------------------------------------------------------*/
368
typedef struct
369
{
370
fluid_real_t *line; /* buffer line */
371
int size; /* effective internal size (in samples) */
372
/*-------------*/
373
int line_in; /* line in position */
374
int line_out; /* line out position */
375
/*-------------*/
376
fdn_delay_lpf damping; /* damping low pass filter */
377
} delay_line;
378
379
380
/*-----------------------------------------------------------------------------
381
Clears a delay line to DC_OFFSET float value.
382
@param dl pointer on delay line structure
383
-----------------------------------------------------------------------------*/
384
static void clear_delay_line(delay_line *dl)
385
{
386
int i;
387
388
for(i = 0; i < dl->size; i++)
389
{
390
dl->line[i] = DC_OFFSET;
391
}
392
}
393
394
/*-----------------------------------------------------------------------------
395
Push a sample val into the delay line
396
-----------------------------------------------------------------------------*/
397
#define push_in_delay_line(dl, val) \
398
{\
399
dl->line[dl->line_in] = val;\
400
/* Incrementation and circular motion if necessary */\
401
if(++dl->line_in >= dl->size) dl->line_in -= dl->size;\
402
}\
403
404
/*-----------------------------------------------------------------------------
405
Modulator for modulated delay line
406
-----------------------------------------------------------------------------*/
407
408
/*-----------------------------------------------------------------------------
409
Sinusoidal modulator
410
-----------------------------------------------------------------------------*/
411
/* modulator are integrated in modulated delay line */
412
typedef struct
413
{
414
fluid_real_t a1; /* Coefficient: a1 = 2 * cos(w) */
415
fluid_real_t buffer1; /* buffer1 */
416
fluid_real_t buffer2; /* buffer2 */
417
fluid_real_t reset_buffer2;/* reset value of buffer2 */
418
} sinus_modulator;
419
420
/*-----------------------------------------------------------------------------
421
Sets the frequency of sinus oscillator.
422
423
@param mod pointer on modulator structure.
424
@param freq frequency of the oscillator in Hz.
425
@param sample_rate sample rate on audio output in Hz.
426
@param phase initial phase of the oscillator in degree (0 to 360).
427
-----------------------------------------------------------------------------*/
428
static void set_mod_frequency(sinus_modulator *mod,
429
float freq, float sample_rate, float phase)
430
{
431
fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */
432
fluid_real_t a;
433
434
mod->a1 = 2 * FLUID_COS(w);
435
436
a = (2 * FLUID_M_PI / 360) * phase;
437
438
mod->buffer2 = FLUID_SIN(a - w); /* y(n-1) = sin(-initial angle) */
439
mod->buffer1 = FLUID_SIN(a); /* y(n) = sin(initial phase) */
440
mod->reset_buffer2 = FLUID_SIN(FLUID_M_PI / 2 - w); /* reset value for PI/2 */
441
}
442
443
/*-----------------------------------------------------------------------------
444
Gets current value of sinus modulator:
445
y(n) = a1 . y(n-1) - y(n-2)
446
out = a1 . buffer1 - buffer2
447
448
@param pointer on modulator structure.
449
@return current value of the modulator sine wave.
450
-----------------------------------------------------------------------------*/
451
static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod)
452
{
453
fluid_real_t out;
454
out = mod->a1 * mod->buffer1 - mod->buffer2;
455
mod->buffer2 = mod->buffer1;
456
457
if(out >= 1.0f) /* reset in case of instability near PI/2 */
458
{
459
out = 1.0f; /* forces output to the right value */
460
mod->buffer2 = mod->reset_buffer2;
461
}
462
463
if(out <= -1.0f) /* reset in case of instability near -PI/2 */
464
{
465
out = -1.0f; /* forces output to the right value */
466
mod->buffer2 = - mod->reset_buffer2;
467
}
468
469
mod->buffer1 = out;
470
return out;
471
}
472
473
/*-----------------------------------------------------------------------------
474
Modulated delay line. The line is composed of:
475
- the delay line with its damping low pass filter.
476
- the sinusoidal modulator.
477
- center output position modulated by the modulator.
478
- variable rate control of center output position.
479
- first order All-Pass interpolator.
480
-----------------------------------------------------------------------------*/
481
typedef struct
482
{
483
/* delay line with damping low pass filter member */
484
delay_line dl; /* delayed line */
485
/*---------------------------*/
486
/* Sinusoidal modulator member */
487
sinus_modulator mod; /* sinus modulator */
488
/*-------------------------*/
489
/* center output position members */
490
fluid_real_t center_pos_mod; /* center output position modulated by modulator */
491
int mod_depth; /* modulation depth (in samples) */
492
/*-------------------------*/
493
/* variable rate control of center output position */
494
int index_rate; /* index rate to know when to update center_pos_mod */
495
int mod_rate; /* rate at which center_pos_mod is updated */
496
/*-------------------------*/
497
/* first order All-Pass interpolator members */
498
fluid_real_t frac_pos_mod; /* fractional position part between samples) */
499
/* previous value used when interpolating using fractional */
500
fluid_real_t buffer;
501
} mod_delay_line;
502
503
/*-----------------------------------------------------------------------------
504
Return norminal delay length
505
506
@param mdl, pointer on modulated delay line.
507
-----------------------------------------------------------------------------*/
508
static int get_mod_delay_line_length(mod_delay_line *mdl)
509
{
510
return (mdl->dl.size - mdl->mod_depth - INTERP_SAMPLES_NBR);
511
}
512
513
/*-----------------------------------------------------------------------------
514
Reads the sample value out of the modulated delay line.
515
@param mdl, pointer on modulated delay line.
516
@return the sample value.
517
-----------------------------------------------------------------------------*/
518
static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl)
519
{
520
fluid_real_t out_index; /* new modulated index position */
521
int int_out_index; /* integer part of out_index */
522
fluid_real_t out; /* value to return */
523
524
/* Checks if the modulator must be updated (every mod_rate samples). */
525
/* Important: center_pos_mod must be used immediately for the
526
first sample. So, mdl->index_rate must be initialized
527
to mdl->mod_rate (set_mod_delay_line()) */
528
529
if(++mdl->index_rate >= mdl->mod_rate)
530
{
531
mdl->index_rate = 0;
532
533
/* out_index = center position (center_pos_mod) + sinus waweform */
534
out_index = mdl->center_pos_mod +
535
get_mod_sinus(&mdl->mod) * mdl->mod_depth;
536
537
/* extracts integer part in int_out_index */
538
if(out_index >= 0.0f)
539
{
540
int_out_index = (int)out_index; /* current integer part */
541
542
/* forces read index (line_out) with integer modulation value */
543
/* Boundary check and circular motion as needed */
544
if((mdl->dl.line_out = int_out_index) >= mdl->dl.size)
545
{
546
mdl->dl.line_out -= mdl->dl.size;
547
}
548
}
549
else /* negative */
550
{
551
int_out_index = (int)(out_index - 1); /* previous integer part */
552
/* forces read index (line_out) with integer modulation value */
553
/* circular motion as needed */
554
mdl->dl.line_out = int_out_index + mdl->dl.size;
555
}
556
557
/* extracts fractionnal part. (it will be used when interpolating
558
between line_out and line_out +1) and memorize it.
559
Memorizing is necessary for modulation rate above 1 */
560
mdl->frac_pos_mod = out_index - int_out_index;
561
562
/* updates center position (center_pos_mod) to the next position
563
specified by modulation rate */
564
if((mdl->center_pos_mod += mdl->mod_rate) >= mdl->dl.size)
565
{
566
mdl->center_pos_mod -= mdl->dl.size;
567
}
568
}
569
570
/* First order all-pass interpolation ----------------------------------*/
571
/* https://ccrma.stanford.edu/~jos/pasp/First_Order_Allpass_Interpolation.html */
572
/* begins interpolation: read current sample */
573
out = mdl->dl.line[mdl->dl.line_out];
574
575
/* updates line_out to the next sample.
576
Boundary check and circular motion as needed */
577
if(++mdl->dl.line_out >= mdl->dl.size)
578
{
579
mdl->dl.line_out -= mdl->dl.size;
580
}
581
582
/* Fractional interpolation between next sample (at next position) and
583
previous output added to current sample.
584
*/
585
out += mdl->frac_pos_mod * (mdl->dl.line[mdl->dl.line_out] - mdl->buffer);
586
mdl->buffer = out; /* memorizes current output */
587
return out;
588
}
589
590
/*-----------------------------------------------------------------------------
591
Late structure
592
-----------------------------------------------------------------------------*/
593
struct _fluid_late
594
{
595
fluid_real_t samplerate; /* sample rate */
596
fluid_real_t sample_rate_max; /* sample rate maximum */
597
/*----- High pass tone corrector -------------------------------------*/
598
fluid_real_t tone_buffer;
599
fluid_real_t b1, b2;
600
/*----- Modulated delay lines lines ----------------------------------*/
601
mod_delay_line mod_delay_lines[NBR_DELAYS];
602
/*-----------------------------------------------------------------------*/
603
/* Output coefficients for separate Left and right stereo outputs */
604
fluid_real_t out_left_gain[NBR_DELAYS]; /* Left delay lines' output gains */
605
fluid_real_t out_right_gain[NBR_DELAYS];/* Right delay lines' output gains*/
606
};
607
608
typedef struct _fluid_late fluid_late;
609
/*-----------------------------------------------------------------------------
610
fluidsynth reverb structure
611
-----------------------------------------------------------------------------*/
612
struct _fluid_revmodel_t
613
{
614
/* reverb parameters */
615
fluid_real_t roomsize; /* acting on reverb time */
616
fluid_real_t damp; /* acting on frequency dependent reverb time */
617
fluid_real_t level, wet1, wet2; /* output level */
618
fluid_real_t width; /* width stereo separation */
619
620
/* fdn reverberation structure */
621
fluid_late late;
622
};
623
624
/*-----------------------------------------------------------------------------
625
Updates Reverb time and absorbent filters coefficients from parameters:
626
627
@param late pointer on late structure.
628
@param roomsize (0 to 1): acting on reverb time.
629
@param damping (0 to 1): acting on absorbent damping filter.
630
631
Design formulas:
632
https://ccrma.stanford.edu/~jos/Reverb/First_Order_Delay_Filter_Design.html
633
https://ccrma.stanford.edu/~jos/Reverb/Tonal_Correction_Filter.html
634
-----------------------------------------------------------------------------*/
635
static void update_rev_time_damping(fluid_late *late,
636
fluid_real_t roomsize, fluid_real_t damp)
637
{
638
int i;
639
fluid_real_t sample_period = 1 / late->samplerate; /* Sampling period */
640
int delay_length; /* delay length */
641
fluid_real_t dc_rev_time; /* Reverb time at 0 Hz (in seconds) */
642
643
fluid_real_t alpha, alpha2;
644
645
/*--------------------------------------------
646
Computes dc_rev_time and alpha
647
----------------------------------------------*/
648
{
649
fluid_real_t gi_tmp, ai_tmp;
650
#ifdef ROOMSIZE_RESPONSE_LINEAR
651
/* roomsize parameter behave linearly:
652
* - roomsize (0 to 1) controls reverb time linearly (0.7 to 10 s).
653
* This linear response is convenient when using GUI controls.
654
*/
655
/*-----------------------------------------
656
Computes dc_rev_time
657
------------------------------------------*/
658
dc_rev_time = GET_DC_REV_TIME(roomsize);
659
delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]);
660
/* computes gi_tmp from dc_rev_time using relation E2 */
661
gi_tmp = FLUID_POW(10, -3 * delay_length *
662
sample_period / dc_rev_time); /* E2 */
663
#else
664
/* roomsize parameters have the same response that Freeverb, that is:
665
* - roomsize (0 to 1) controls concave reverb time (0.7 to 10 s).
666
*/
667
{
668
/*-----------------------------------------
669
Computes dc_rev_time
670
------------------------------------------*/
671
fluid_real_t gi_min, gi_max;
672
673
/* values gi_min et gi_max are computed using E2 for the line with
674
maximum delay */
675
delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]);
676
gi_max = FLUID_POW(10, (-3 * delay_length / MAX_DC_REV_TIME) *
677
sample_period); /* E2 */
678
gi_min = FLUID_POW(10, (-3 * delay_length / MIN_DC_REV_TIME) *
679
sample_period); /* E2 */
680
/* gi = f(roomsize, gi_max, gi_min) */
681
gi_tmp = gi_min + roomsize * (gi_max - gi_min);
682
/* Computes T60DC from gi using inverse of relation E2.*/
683
dc_rev_time = -3 * FLUID_M_LN10 * delay_length * sample_period / FLUID_LOGF(gi_tmp);
684
}
685
#endif /* ROOMSIZE_RESPONSE_LINEAR */
686
/*--------------------------------------------
687
Computes alpha
688
----------------------------------------------*/
689
/* Computes alpha from damp,ai_tmp,gi_tmp using relation R */
690
/* - damp (0 to 1) controls concave reverb time for fs/2 frequency (T60DC to 0) */
691
ai_tmp = 1.0f * damp;
692
693
/* Preserve the square of R */
694
alpha2 = 1.f / (1.f - ai_tmp / ((20.f / 80.f) * FLUID_LOGF(gi_tmp)));
695
696
alpha = FLUID_SQRT(alpha2); /* R */
697
}
698
699
/* updates tone corrector coefficients b1,b2 from alpha */
700
{
701
/*
702
Beta = (1 - alpha) / (1 + alpha)
703
b1 = 1/(1-beta)
704
b2 = beta * b1
705
*/
706
fluid_real_t beta = (1 - alpha) / (1 + alpha);
707
late->b1 = 1 / (1 - beta);
708
late->b2 = beta * late->b1;
709
late->tone_buffer = 0.0f;
710
}
711
712
/* updates damping coefficients of all lines (gi , ai) from dc_rev_time, alpha */
713
for(i = 0; i < NBR_DELAYS; i++)
714
{
715
fluid_real_t gi, ai;
716
717
/* delay length */
718
delay_length = get_mod_delay_line_length(&late->mod_delay_lines[i]);
719
720
/* iir low pass filter gain */
721
gi = FLUID_POW(10, -3 * delay_length * sample_period / dc_rev_time);
722
723
/* iir low pass filter feedback gain */
724
ai = (20.f / 80.f) * FLUID_LOGF(gi) * (1.f - 1.f / alpha2);
725
726
/* b0 = gi * (1 - ai), a1 = - ai */
727
set_fdn_delay_lpf(&late->mod_delay_lines[i].dl.damping,
728
gi * (1.f - ai), -ai);
729
}
730
}
731
732
/*-----------------------------------------------------------------------------
733
Updates stereo coefficients
734
@param late pointer on late structure
735
@param wet level integrated in stereo coefficients.
736
-----------------------------------------------------------------------------*/
737
static void update_stereo_coefficient(fluid_late *late, fluid_real_t wet1)
738
{
739
int i;
740
fluid_real_t wet;
741
742
for(i = 0; i < NBR_DELAYS; i++)
743
{
744
/* delay lines output gains vectors Left and Right
745
746
L R
747
0 | 1 1|
748
1 |-1 1|
749
2 | 1 -1|
750
3 |-1 -1|
751
752
4 | 1 1|
753
5 |-1 1|
754
stereo gain = 6 | 1 -1|
755
7 |-1 -1|
756
757
8 | 1 1|
758
9 |-1 1|
759
10| 1 -1|
760
11|-1 -1|
761
*/
762
763
/* for left line: 00, ,02, ,04, ,06, ,08, ,10, ,12,... left_gain = +1 */
764
/* for left line: ,01, ,03, ,05, ,07, ,09, ,11,... left_gain = -1 */
765
wet = wet1;
766
if(i & 1)
767
{
768
wet = -wet1;
769
}
770
late->out_left_gain[i] = wet;
771
772
/* for right line: 00,01, ,04,05, ,08,09, ,12,13 right_gain = +1 */
773
/* for right line: ,02 ,03, ,06,07, ,10,11,... right_gain = -1 */
774
wet = wet1;
775
if(i & 2)
776
{
777
wet = -wet1;
778
}
779
late->out_right_gain[i] = wet;
780
}
781
}
782
783
/*-----------------------------------------------------------------------------
784
fluid_late destructor.
785
@param late pointer on late structure.
786
-----------------------------------------------------------------------------*/
787
static void delete_fluid_rev_late(fluid_late *late)
788
{
789
int i;
790
fluid_return_if_fail(late != NULL);
791
792
/* free the delay lines */
793
for(i = 0; i < NBR_DELAYS; i++)
794
{
795
FLUID_FREE(late->mod_delay_lines[i].dl.line);
796
}
797
}
798
799
800
/* Nominal delay lines length table (in samples) */
801
static const int nom_delay_length[NBR_DELAYS] =
802
{
803
DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3,
804
DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7,
805
#if (NBR_DELAYS == 12)
806
DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11
807
#endif
808
};
809
810
/*
811
1)"modal density" is one property that contributes to the quality of the reverb tail.
812
The more is the modal density, the less are unwanted resonant frequencies
813
build during the decay time: modal density = total delay / sample rate.
814
815
Delay line's length given by static table delay_length[] are nominal
816
to get minimum modal density of 0.15 at sample rate 44100Hz.
817
Here we set length_factor to 2 to multiply this nominal modal
818
density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for
819
sample rate <= 44100.
820
821
For sample rate > 44100, length_factor is multiplied by
822
sample_rate / 44100. This ensures that the default modal density keeps inchanged.
823
(Without this compensation, the default modal density would be diminished for
824
new sample rate change above 44100Hz).
825
826
2)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing").
827
Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz.
828
For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures
829
that the effect of modulated delay line remains inchanged.
830
*/
831
static void compensate_from_sample_rate(fluid_real_t sample_rate,
832
fluid_real_t *mod_depth,
833
fluid_real_t *length_factor)
834
{
835
*mod_depth = MOD_DEPTH;
836
*length_factor = 2.0f;
837
if(sample_rate > 44100.0f)
838
{
839
fluid_real_t sample_rate_factor = sample_rate/44100.0f;
840
*length_factor *= sample_rate_factor;
841
*mod_depth *= sample_rate_factor;
842
}
843
}
844
845
/*-----------------------------------------------------------------------------
846
Creates all modulated lines.
847
@param late, pointer on the fnd late reverb to initialize.
848
@param sample_rate_max, the maximum audio sample rate expected.
849
@return FLUID_OK if success, FLUID_FAILED otherwise.
850
-----------------------------------------------------------------------------*/
851
static int create_mod_delay_lines(fluid_late *late,
852
fluid_real_t sample_rate_max)
853
{
854
int i;
855
856
fluid_real_t mod_depth, length_factor;
857
858
/* compute mod_depth, length factor */
859
compensate_from_sample_rate(sample_rate_max, &mod_depth, &length_factor);
860
861
late->sample_rate_max = sample_rate_max;
862
863
#ifdef INFOS_PRINT // allows message to be printed on the console.
864
printf("length_factor:%f, mod_depth:%f\n", length_factor, mod_depth);
865
/* Print: modal density and total memory bytes */
866
{
867
int i;
868
int total_delay = 0; /* total delay in samples */
869
for (i = 0; i < NBR_DELAYS; i++)
870
{
871
int length = (length_factor * nom_delay_length[i])
872
+ mod_depth + INTERP_SAMPLES_NBR;
873
total_delay += length;
874
}
875
876
/* modal density and total memory bytes */
877
printf("modal density:%f, total delay:%d, total memory:%d bytes\n",
878
total_delay / sample_rate_max ,total_delay ,
879
total_delay * sizeof(fluid_real_t));
880
}
881
#endif
882
883
for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */
884
{
885
int delay_length = nom_delay_length[i] * length_factor;
886
mod_delay_line *mdl = &late->mod_delay_lines[i];
887
888
/*-------------------------------------------------------------------*/
889
/* checks parameter */
890
if(delay_length < 1)
891
{
892
return FLUID_FAILED;
893
}
894
895
/* limits mod_depth to the requested delay length */
896
if(mod_depth >= delay_length)
897
{
898
FLUID_LOG(FLUID_INFO,
899
"fdn reverb: modulation depth has been limited");
900
mod_depth = delay_length - 1;
901
}
902
903
/*---------------------------------------------------------------------
904
allocates delay lines
905
*/
906
907
/* real size of the line in use (in samples):
908
size = INTERP_SAMPLES_NBR + mod_depth + delay_length */
909
mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR;
910
mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size);
911
912
if(! mdl->dl.line)
913
{
914
return FLUID_FAILED;
915
}
916
}
917
return FLUID_OK;
918
}
919
920
/*-----------------------------------------------------------------------------
921
Initialize all modulated lines.
922
@param late, pointer on the fnd late reverb to initialize.
923
@param sample_rate, the audio sample rate.
924
@return FLUID_OK if success, FLUID_FAILED otherwise.
925
-----------------------------------------------------------------------------*/
926
static void initialize_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)
927
{
928
int i;
929
fluid_real_t mod_depth, length_factor;
930
931
/* update delay line parameter dependent of sample rate */
932
late->samplerate = sample_rate;
933
934
/* compute mod_depth, length factor */
935
compensate_from_sample_rate(sample_rate, &mod_depth, &length_factor);
936
937
for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */
938
{
939
mod_delay_line *mdl = &late->mod_delay_lines[i];
940
int delay_length = nom_delay_length[i] * length_factor;
941
942
/* limits mod_depth to the requested delay length */
943
if(mod_depth >= delay_length)
944
{
945
mod_depth = delay_length - 1;
946
}
947
948
mdl->mod_depth = mod_depth;
949
950
clear_delay_line(&mdl->dl); /* clears the buffer */
951
952
/* Initializes line_in to the start of the buffer */
953
mdl->dl.line_in = 0;
954
955
/* Initializes line_out index INTERP_SAMPLES_NBR samples after
956
line_in so that the delay between line_out and line_in is:
957
mod_depth + delay_length
958
*/
959
mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR;
960
961
/* Damping low pass filter ------------------------------------------*/
962
mdl->dl.damping.buffer = 0;
963
964
/*---------------------------------------------------------------------
965
Initializes modulation members:
966
- modulated center position: center_pos_mod
967
- modulation rate (the speed at which center_pos_mod is modulated: mod_rate
968
- index rate to know when to update center_pos_mod:index_rate
969
- interpolator member: buffer, frac_pos_mod
970
---------------------------------------------------------------------*/
971
/* Initializes the modulated center position (center_pos_mod) so that:
972
- the delay between line_out and center_pos_mod is mod_depth.
973
- the delay between center_pos_mod and line_in is delay_length.
974
*/
975
mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth;
976
977
/* Sets the modulation rate. This rate defines how often
978
the center position (center_pos_mod ) is modulated .
979
The value is expressed in samples. The default value is 1 that means that
980
center_pos_mod is updated at every sample.
981
For example with a value of 2, the center position position will be
982
updated only one time every 2 samples only.
983
*/
984
if(MOD_RATE < 1 || MOD_RATE > mdl->dl.size)
985
{
986
FLUID_LOG(FLUID_INFO, "fdn reverb: modulation rate is out of range");
987
mdl->mod_rate = 1; /* default modulation rate: every one sample */
988
}
989
else
990
{
991
mdl->mod_rate = MOD_RATE;
992
}
993
994
/* index rate to control when to update center_pos_mod.
995
Important: must be set to get center_pos_mod immediately used for
996
the reading of first sample (see get_mod_delay())
997
*/
998
mdl->index_rate = mdl->mod_rate;
999
1000
/* initializes first order All-Pass interpolator members */
1001
mdl->buffer = 0; /* previous delay sample value */
1002
mdl->frac_pos_mod = 0; /* frac. position (between consecutives sample) */
1003
1004
1005
/* Sets local Modulators parameters: frequency and phase.
1006
Each modulateur are shifted of MOD_PHASE degree
1007
*/
1008
set_mod_frequency(&mdl->mod,
1009
MOD_FREQ * MOD_RATE,
1010
sample_rate,
1011
(float)(MOD_PHASE * i));
1012
}
1013
}
1014
1015
/*
1016
Clears the delay lines.
1017
1018
@param rev pointer on the reverb.
1019
*/
1020
static void
1021
fluid_revmodel_init(fluid_revmodel_t *rev)
1022
{
1023
int i;
1024
1025
/* clears all the delay lines */
1026
for(i = 0; i < NBR_DELAYS; i ++)
1027
{
1028
clear_delay_line(&rev->late.mod_delay_lines[i].dl);
1029
}
1030
}
1031
1032
1033
/*
1034
updates internal parameters.
1035
1036
@param rev pointer on the reverb.
1037
*/
1038
static void
1039
fluid_revmodel_update(fluid_revmodel_t *rev)
1040
{
1041
/* Recalculate internal values after parameters change */
1042
1043
/* The stereo amplitude equation (wet1 and wet2 below) have a
1044
tendency to produce high amplitude with high width values ( 1 < width < 100).
1045
This results in an unwanted noisy output clipped by the audio card.
1046
To avoid this dependency, we divide by (1 + rev->width * SCALE_WET_WIDTH)
1047
Actually, with a SCALE_WET_WIDTH of 0.2, (regardless of level setting),
1048
the output amplitude (wet) seems rather independent of width setting */
1049
fluid_real_t wet = (rev->level * SCALE_WET) /
1050
(1.0f + rev->width * SCALE_WET_WIDTH);
1051
1052
/* wet1 and wet2 are used by the stereo effect controlled by the width setting
1053
for producing a stereo ouptput from a monophonic reverb signal.
1054
Please see the note above about a side effect tendency */
1055
1056
rev->wet1 = wet * (rev->width / 2.0f + 0.5f);
1057
rev->wet2 = wet * ((1.0f - rev->width) / 2.0f);
1058
1059
/* integrates wet1 in stereo coefficient (this will save one multiply) */
1060
update_stereo_coefficient(&rev->late, rev->wet1);
1061
1062
if(rev->wet1 > 0.0f)
1063
{
1064
rev->wet2 /= rev->wet1;
1065
}
1066
1067
/* Reverberation time and damping */
1068
update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);
1069
}
1070
1071
/*----------------------------------------------------------------------------
1072
Reverb API
1073
-----------------------------------------------------------------------------*/
1074
/*
1075
* Creates a reverb. Once created the reverb have no parameters set, so
1076
* fluid_revmodel_set() must be called at least one time after calling
1077
* new_fluid_revmodel().
1078
*
1079
* @param sample_rate_max maximum sample rate expected in Hz.
1080
*
1081
* @param sample_rate actual sample rate needed in Hz.
1082
* @return pointer on the new reverb or NULL if memory error.
1083
* Reverb API.
1084
*/
1085
fluid_revmodel_t *
1086
new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate)
1087
{
1088
fluid_revmodel_t *rev;
1089
1090
if(sample_rate <= 0)
1091
{
1092
return NULL;
1093
}
1094
1095
rev = FLUID_NEW(fluid_revmodel_t);
1096
1097
if(rev == NULL)
1098
{
1099
return NULL;
1100
}
1101
1102
FLUID_MEMSET(&rev->late, 0, sizeof(fluid_late));
1103
1104
/*--------------------------------------------------------------------------
1105
Create fdn late reverb.
1106
*/
1107
1108
/* update minimum value for sample_rate_max */
1109
if(sample_rate > sample_rate_max)
1110
{
1111
sample_rate_max = sample_rate;
1112
}
1113
1114
/*--------------------------------------------------------------------------
1115
Allocate the modulated delay lines
1116
*/
1117
if(create_mod_delay_lines(&rev->late, sample_rate_max) == FLUID_FAILED)
1118
{
1119
delete_fluid_revmodel(rev);
1120
return NULL;
1121
}
1122
1123
/*--------------------------------------------------------------------------
1124
Initialize the fdn reverb
1125
*/
1126
/* Initialize all modulated lines. */
1127
initialize_mod_delay_lines(&rev->late, sample_rate);
1128
1129
return rev;
1130
}
1131
1132
/*
1133
* free the reverb.
1134
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
1135
* function, calling delete_fluid_revmodel() isn't multi task safe because
1136
* delay line are freed. To deal properly with this issue follow the steps:
1137
*
1138
* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().
1139
* reverb functions.
1140
* 2) Delete the reverb by calling delete_fluid_revmodel().
1141
*
1142
* @param rev pointer on reverb to free.
1143
* Reverb API.
1144
*/
1145
void
1146
delete_fluid_revmodel(fluid_revmodel_t *rev)
1147
{
1148
fluid_return_if_fail(rev != NULL);
1149
delete_fluid_rev_late(&rev->late);
1150
FLUID_FREE(rev);
1151
}
1152
1153
/*
1154
* Sets one or more reverb parameters. Note this must be called at least one
1155
* time after calling new_fluid_revmodel() and before any call to
1156
* fluid_revmodel_processXXX() and fluid_revmodel_samplerate_change().
1157
*
1158
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
1159
* function, calling fluid_revmodel_set() could produce audible clics.
1160
* If this is a problem, optionally call fluid_revmodel_reset() before calling
1161
* fluid_revmodel_set().
1162
*
1163
* @param rev Reverb instance.
1164
* @param set One or more flags from #fluid_revmodel_set_t indicating what
1165
* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters).
1166
* @param roomsize Reverb room size.
1167
* @param damping Reverb damping.
1168
* @param width Reverb width.
1169
* @param level Reverb level.
1170
*
1171
* Reverb API.
1172
*/
1173
void
1174
fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
1175
fluid_real_t damping, fluid_real_t width, fluid_real_t level)
1176
{
1177
fluid_return_if_fail(rev != NULL);
1178
1179
/*-----------------------------------*/
1180
if(set & FLUID_REVMODEL_SET_ROOMSIZE)
1181
{
1182
fluid_clip(roomsize, 0.0f, 1.0f);
1183
rev->roomsize = roomsize;
1184
}
1185
1186
/*-----------------------------------*/
1187
if(set & FLUID_REVMODEL_SET_DAMPING)
1188
{
1189
fluid_clip(damping, 0.0f, 1.0f);
1190
rev->damp = damping;
1191
}
1192
1193
/*-----------------------------------*/
1194
if(set & FLUID_REVMODEL_SET_WIDTH)
1195
{
1196
rev->width = width;
1197
}
1198
1199
/*-----------------------------------*/
1200
if(set & FLUID_REVMODEL_SET_LEVEL)
1201
{
1202
fluid_clip(level, 0.0f, 1.0f);
1203
rev->level = level;
1204
}
1205
1206
/* updates internal parameters */
1207
fluid_revmodel_update(rev);
1208
}
1209
1210
/*
1211
* Applies a sample rate change on the reverb.
1212
* fluid_revmodel_set() must be called at least one time before calling
1213
* this function.
1214
*
1215
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
1216
* function, calling fluid_revmodel_samplerate_change() isn't multi task safe.
1217
* To deal properly with this issue follow the steps:
1218
* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().
1219
* reverb functions.
1220
* Optionally, call fluid_revmodel_reset() to damp the reverb.
1221
* 2) Change sample rate by calling fluid_revmodel_samplerate_change().
1222
* 3) Restart reverb processing (i.e enabling calling of any fluid_revmodel_processXXX()
1223
* reverb functions.
1224
*
1225
* Another solution is to substitute step (2):
1226
* 2.1) delete the reverb by calling delete_fluid_revmodel().
1227
* 2.2) create the reverb by calling new_fluid_revmodel().
1228
*
1229
* The best solution would be that this function be called only by the same task
1230
* calling fluid_revmodel_processXXX().
1231
*
1232
* @param rev the reverb.
1233
* @param sample_rate new sample rate value. Must be <= sample_rate_max
1234
* @return FLUID_OK if success, FLUID_FAILED if new sample rate is greater
1235
* then the maximumum sample rate set at creation time. The reverb will
1236
* continue to work but with possible lost of quality.
1237
* If this is a problem, the caller should follow steps 2.1 and 2.2.
1238
* Reverb API.
1239
*/
1240
int
1241
fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
1242
{
1243
int status = FLUID_OK;
1244
1245
fluid_return_val_if_fail(rev != NULL, FLUID_FAILED);
1246
1247
if(sample_rate > rev->late.sample_rate_max)
1248
{
1249
FLUID_LOG(FLUID_WARN,
1250
"fdn reverb: sample rate %.0f Hz is deduced to %.0f Hz\n",
1251
sample_rate, rev->late.sample_rate_max);
1252
1253
/* Reduce sample rate to the maximum value set at creation time.
1254
The reverb will continue to work with possible lost of quality.
1255
*/
1256
sample_rate = rev->late.sample_rate_max;
1257
status = FLUID_FAILED;
1258
}
1259
1260
/* Initialize all modulated lines according to sample rate change. */
1261
initialize_mod_delay_lines(&rev->late, sample_rate);
1262
1263
/* updates damping filter coefficients according to sample rate change */
1264
update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);
1265
1266
return status;
1267
}
1268
1269
/*
1270
* Damps the reverb by clearing the delay lines.
1271
* @param rev the reverb.
1272
*
1273
* Reverb API.
1274
*/
1275
void
1276
fluid_revmodel_reset(fluid_revmodel_t *rev)
1277
{
1278
fluid_return_if_fail(rev != NULL);
1279
1280
fluid_revmodel_init(rev);
1281
}
1282
1283
/*-----------------------------------------------------------------------------
1284
* fdn reverb process replace.
1285
* @param rev pointer on reverb.
1286
* @param in monophonic buffer input (FLUID_BUFSIZE sample).
1287
* @param left_out stereo left processed output (FLUID_BUFSIZE sample).
1288
* @param right_out stereo right processed output (FLUID_BUFSIZE sample).
1289
*
1290
* The processed reverb is replacing anything there in out.
1291
* Reverb API.
1292
-----------------------------------------------------------------------------*/
1293
void
1294
fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in,
1295
fluid_real_t *left_out, fluid_real_t *right_out)
1296
{
1297
int i, k;
1298
1299
fluid_real_t xn; /* mono input x(n) */
1300
fluid_real_t out_tone_filter; /* tone corrector output */
1301
fluid_real_t out_left, out_right; /* output stereo Left and Right */
1302
fluid_real_t matrix_factor; /* partial matrix computation */
1303
fluid_real_t delay_out_s; /* sample */
1304
fluid_real_t delay_out[NBR_DELAYS]; /* Line output + damper output */
1305
1306
for(k = 0; k < FLUID_BUFSIZE; k++)
1307
{
1308
/* stereo output */
1309
out_left = out_right = 0;
1310
1311
#ifdef DENORMALISING
1312
/* Input is adjusted by DC_OFFSET. */
1313
xn = (in[k]) * FIXED_GAIN + DC_OFFSET;
1314
#else
1315
xn = (in[k]) * FIXED_GAIN;
1316
#endif
1317
1318
/*--------------------------------------------------------------------
1319
tone correction.
1320
*/
1321
out_tone_filter = xn * rev->late.b1 - rev->late.b2 * rev->late.tone_buffer;
1322
rev->late.tone_buffer = xn;
1323
xn = out_tone_filter;
1324
/*--------------------------------------------------------------------
1325
process feedback delayed network:
1326
- xn is the input signal.
1327
- before inserting in the line input we first we get the delay lines
1328
output, filter them and compute output in delay_out[].
1329
- also matrix_factor is computed (to simplify further matrix product)
1330
---------------------------------------------------------------------*/
1331
/* We begin with the modulated output delay line + damping filter */
1332
matrix_factor = 0;
1333
1334
for(i = 0; i < NBR_DELAYS; i++)
1335
{
1336
mod_delay_line *mdl = &rev->late.mod_delay_lines[i];
1337
/* get current modulated output */
1338
delay_out_s = get_mod_delay(mdl);
1339
1340
/* process low pass damping filter
1341
(input:delay_out_s, output:delay_out_s) */
1342
process_damping_filter(delay_out_s, delay_out_s, mdl);
1343
1344
/* Result in delay_out[], and matrix_factor.
1345
These will be of use later during input line process */
1346
delay_out[i] = delay_out_s; /* result in delay_out[] */
1347
matrix_factor += delay_out_s; /* result in matrix_factor */
1348
1349
/* Process stereo output */
1350
/* stereo left = left + out_left_gain * delay_out */
1351
out_left += rev->late.out_left_gain[i] * delay_out_s;
1352
/* stereo right= right+ out_right_gain * delay_out */
1353
out_right += rev->late.out_right_gain[i] * delay_out_s;
1354
}
1355
1356
/* now we process the input delay line.Each input is a combination of
1357
- xn: input signal
1358
- delay_out[] the output of a delay line given by a permutation matrix P
1359
- and matrix_factor.
1360
This computes: in_delay_line = xn + (delay_out[] * matrix A) with
1361
an algorithm equivalent but faster than using a product with matrix A.
1362
*/
1363
/* matrix_factor = output sum * (-2.0)/N */
1364
matrix_factor *= FDN_MATRIX_FACTOR;
1365
matrix_factor += xn; /* adds reverb input signal */
1366
1367
for(i = 1; i < NBR_DELAYS; i++)
1368
{
1369
/* delay_in[i-1] = delay_out[i] + matrix_factor */
1370
delay_line *dl = &rev->late.mod_delay_lines[i - 1].dl;
1371
push_in_delay_line(dl, delay_out[i] + matrix_factor);
1372
}
1373
1374
/* last line input (NB_DELAY-1) */
1375
/* delay_in[0] = delay_out[NB_DELAY -1] + matrix_factor */
1376
{
1377
delay_line *dl = &rev->late.mod_delay_lines[NBR_DELAYS - 1].dl;
1378
push_in_delay_line(dl, delay_out[0] + matrix_factor);
1379
}
1380
1381
/*-------------------------------------------------------------------*/
1382
#ifdef DENORMALISING
1383
/* Removes the DC offset */
1384
out_left -= DC_OFFSET;
1385
out_right -= DC_OFFSET;
1386
#endif
1387
1388
/* Calculates stereo output REPLACING anything already there: */
1389
/*
1390
left_out[k] = out_left * rev->wet1 + out_right * rev->wet2;
1391
right_out[k] = out_right * rev->wet1 + out_left * rev->wet2;
1392
1393
As wet1 is integrated in stereo coefficient wet 1 is now
1394
integrated in out_left and out_right, so we simplify previous
1395
relation by suppression of one multiply as this:
1396
1397
left_out[k] = out_left + out_right * rev->wet2;
1398
right_out[k] = out_right + out_left * rev->wet2;
1399
*/
1400
left_out[k] = out_left + out_right * rev->wet2;
1401
right_out[k] = out_right + out_left * rev->wet2;
1402
}
1403
}
1404
1405
1406
/*-----------------------------------------------------------------------------
1407
* fdn reverb process mix.
1408
* @param rev pointer on reverb.
1409
* @param in monophonic buffer input (FLUID_BUFSIZE samples).
1410
* @param left_out stereo left processed output (FLUID_BUFSIZE samples).
1411
* @param right_out stereo right processed output (FLUID_BUFSIZE samples).
1412
*
1413
* The processed reverb is mixed in out with samples already there in out.
1414
* Reverb API.
1415
-----------------------------------------------------------------------------*/
1416
void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,
1417
fluid_real_t *left_out, fluid_real_t *right_out)
1418
{
1419
int i, k;
1420
1421
fluid_real_t xn; /* mono input x(n) */
1422
fluid_real_t out_tone_filter; /* tone corrector output */
1423
fluid_real_t out_left, out_right; /* output stereo Left and Right */
1424
fluid_real_t matrix_factor; /* partial matrix term */
1425
fluid_real_t delay_out_s; /* sample */
1426
fluid_real_t delay_out[NBR_DELAYS]; /* Line output + damper output */
1427
1428
for(k = 0; k < FLUID_BUFSIZE; k++)
1429
{
1430
/* stereo output */
1431
out_left = out_right = 0;
1432
#ifdef DENORMALISING
1433
/* Input is adjusted by DC_OFFSET. */
1434
xn = (in[k]) * FIXED_GAIN + DC_OFFSET;
1435
#else
1436
xn = (in[k]) * FIXED_GAIN;
1437
#endif
1438
1439
/*--------------------------------------------------------------------
1440
tone correction
1441
*/
1442
out_tone_filter = xn * rev->late.b1 - rev->late.b2 * rev->late.tone_buffer;
1443
rev->late.tone_buffer = xn;
1444
xn = out_tone_filter;
1445
/*--------------------------------------------------------------------
1446
process feedback delayed network:
1447
- xn is the input signal.
1448
- before inserting in the line input we first we get the delay lines
1449
output, filter them and compute output in local delay_out[].
1450
- also matrix_factor is computed (to simplify further matrix product).
1451
---------------------------------------------------------------------*/
1452
/* We begin with the modulated output delay line + damping filter */
1453
matrix_factor = 0;
1454
1455
for(i = 0; i < NBR_DELAYS; i++)
1456
{
1457
mod_delay_line *mdl = &rev->late.mod_delay_lines[i];
1458
/* get current modulated output */
1459
delay_out_s = get_mod_delay(mdl);
1460
1461
/* process low pass damping filter
1462
(input:delay_out_s, output:delay_out_s) */
1463
process_damping_filter(delay_out_s, delay_out_s, mdl);
1464
1465
/* Result in delay_out[], and matrix_factor.
1466
These will be of use later during input line process */
1467
delay_out[i] = delay_out_s; /* result in delay_out[] */
1468
matrix_factor += delay_out_s; /* result in matrix_factor */
1469
1470
/* Process stereo output */
1471
/* stereo left = left + out_left_gain * delay_out */
1472
out_left += rev->late.out_left_gain[i] * delay_out_s;
1473
/* stereo right= right+ out_right_gain * delay_out */
1474
out_right += rev->late.out_right_gain[i] * delay_out_s;
1475
}
1476
1477
/* now we process the input delay line. Each input is a combination of:
1478
- xn: input signal
1479
- delay_out[] the output of a delay line given by a permutation matrix P
1480
- and matrix_factor.
1481
This computes: in_delay_line = xn + (delay_out[] * matrix A) with
1482
an algorithm equivalent but faster than using a product with matrix A.
1483
*/
1484
/* matrix_factor = output sum * (-2.0)/N */
1485
matrix_factor *= FDN_MATRIX_FACTOR;
1486
matrix_factor += xn; /* adds reverb input signal */
1487
1488
for(i = 1; i < NBR_DELAYS; i++)
1489
{
1490
/* delay_in[i-1] = delay_out[i] + matrix_factor */
1491
delay_line *dl = &rev->late.mod_delay_lines[i - 1].dl;
1492
push_in_delay_line(dl, delay_out[i] + matrix_factor);
1493
}
1494
1495
/* last line input (NB_DELAY-1) */
1496
/* delay_in[0] = delay_out[NB_DELAY -1] + matrix_factor */
1497
{
1498
delay_line *dl = &rev->late.mod_delay_lines[NBR_DELAYS - 1].dl;
1499
push_in_delay_line(dl, delay_out[0] + matrix_factor);
1500
}
1501
1502
/*-------------------------------------------------------------------*/
1503
#ifdef DENORMALISING
1504
/* Removes the DC offset */
1505
out_left -= DC_OFFSET;
1506
out_right -= DC_OFFSET;
1507
#endif
1508
/* Calculates stereo output MIXING anything already there: */
1509
/*
1510
left_out[k] += out_left * rev->wet1 + out_right * rev->wet2;
1511
right_out[k] += out_right * rev->wet1 + out_left * rev->wet2;
1512
1513
As wet1 is integrated in stereo coefficient wet 1 is now
1514
integrated in out_left and out_right, so we simplify previous
1515
relation by suppression of one multiply as this:
1516
1517
left_out[k] += out_left + out_right * rev->wet2;
1518
right_out[k] += out_right + out_left * rev->wet2;
1519
*/
1520
left_out[k] += out_left + out_right * rev->wet2;
1521
right_out[k] += out_right + out_left * rev->wet2;
1522
}
1523
}
1524
1525