Audacity  3.0.3
Reverb_libSoX.h
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Reverb_libSoX.h
6  Stereo reverberation effect from libSoX,
7  adapted for Audacity
8 
9  Copyright (c) 2007-2013 [email protected]
10  Licence: LGPL v2.1
11  Filter configuration based on freeverb by Jezar Wakefield.
12 
13 **********************************************************************/
14 
15 #include <cstring>
16 #include <cstdlib>
17 #ifdef __WXMSW__
18  #define M_LN10 2.30258509299404568402 /* log_e 10 */
19 #else
20  #include <cmath>
21 #endif
22 #include <algorithm>
23 using std::min;
24 using std::max;
25 
26 #define array_length(a) (sizeof(a)/sizeof(a[0]))
27 #define dB_to_linear(x) exp((x) * M_LN10 * 0.05)
28 #define midi_to_freq(n) (440 * pow(2,((n)-69)/12.))
29 #define FIFO_SIZE_T size_t
30 #define FIFO_MIN 0x4000
31 #define fifo_read_ptr(f) fifo_read(f, (FIFO_SIZE_T)0, NULL)
32 #define lsx_zalloc(var, n) var = (float *)calloc(n, sizeof(*var))
33 #define filter_advance(p) if (--(p)->ptr < (p)->buffer) (p)->ptr += (p)->size
34 #define filter_delete(p) free((p)->buffer)
35 
36 typedef struct {
37  char * data;
38  size_t allocation; /* Number of bytes allocated for data. */
39  size_t item_size; /* Size of each item in data */
40  size_t begin; /* Offset of the first byte to read. */
41  size_t end; /* 1 + Offset of the last byte to read. */
42 } fifo_t;
43 
44 static void fifo_clear(fifo_t * f)
45 {
46  f->end = f->begin = 0;
47 }
48 
49 static void * fifo_reserve(fifo_t * f, FIFO_SIZE_T n)
50 {
51  n *= f->item_size;
52 
53  if (f->begin == f->end)
54  fifo_clear(f);
55 
56  while (1) {
57  if (f->end + n <= f->allocation) {
58  void *p = f->data + f->end;
59 
60  f->end += n;
61  return p;
62  }
63  if (f->begin > FIFO_MIN) {
64  memmove(f->data, f->data + f->begin, f->end - f->begin);
65  f->end -= f->begin;
66  f->begin = 0;
67  continue;
68  }
69  f->allocation += n;
70  f->data = (char *)realloc(f->data, f->allocation);
71  }
72 }
73 
74 static void * fifo_write(fifo_t * f, FIFO_SIZE_T n, void const * data)
75 {
76  void * s = fifo_reserve(f, n);
77  if (data)
78  memcpy(s, data, n * f->item_size);
79  return s;
80 }
81 
82 static void * fifo_read(fifo_t * f, FIFO_SIZE_T n, void * data)
83 {
84  char * ret = f->data + f->begin;
85  n *= f->item_size;
86  if (n > (FIFO_SIZE_T)(f->end - f->begin))
87  return NULL;
88  if (data)
89  memcpy(data, ret, (size_t)n);
90  f->begin += n;
91  return ret;
92 }
93 
94 static void fifo_delete(fifo_t * f)
95 {
96  free(f->data);
97 }
98 
99 static void fifo_create(fifo_t * f, FIFO_SIZE_T item_size)
100 {
101  f->item_size = item_size;
102  f->allocation = FIFO_MIN;
103  f->data = (char *)malloc(f->allocation);
104  fifo_clear(f);
105 }
106 
107 typedef struct {
108  size_t size;
109  float * buffer, * ptr;
110  float store;
111 } filter_t;
112 
113 static float comb_process(filter_t * p, /* gcc -O2 will inline this */
114  float const * input, float const * feedback, float const * hf_damping)
115 {
116  float output = *p->ptr;
117  p->store = output + (p->store - output) * *hf_damping;
118  *p->ptr = *input + p->store * *feedback;
119  filter_advance(p);
120  return output;
121 }
122 
123 static float allpass_process(filter_t * p, /* gcc -O2 will inline this */
124  float const * input)
125 {
126  float output = *p->ptr;
127  *p->ptr = *input + output * .5;
128  filter_advance(p);
129  return output - *input;
130 }
131 
132 typedef struct {double b0, b1, a1, i1, o1;} one_pole_t;
133 
134 static float one_pole_process(one_pole_t * p, float i0)
135 {
136  float o0 = i0*p->b0 + p->i1*p->b1 - p->o1*p->a1;
137  p->i1 = i0;
138  return p->o1 = o0;
139 }
140 
141 static const size_t /* Filter delay lengths in samples (44100Hz sample-rate) */
142  comb_lengths[] = {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617},
143  allpass_lengths[] = {225, 341, 441, 556}, stereo_adjust = 12;
144 
145 typedef struct {
148  one_pole_t one_pole[2];
150 
151 static void filter_array_create(filter_array_t * p, double rate,
152  double scale, double offset, double fc_highpass, double fc_lowpass)
153 {
154  size_t i;
155  double r = rate * (1 / 44100.); /* Compensate for actual sample-rate */
156 
157  for (i = 0; i < array_length(comb_lengths); ++i, offset = -offset)
158  {
159  filter_t * pcomb = &p->comb[i];
160  pcomb->size = (size_t)(scale * r * (comb_lengths[i] + stereo_adjust * offset) + .5);
161  pcomb->ptr = lsx_zalloc(pcomb->buffer, pcomb->size);
162  }
163  for (i = 0; i < array_length(allpass_lengths); ++i, offset = -offset)
164  {
165  filter_t * pallpass = &p->allpass[i];
166  pallpass->size = (size_t)(r * (allpass_lengths[i] + stereo_adjust * offset) + .5);
167  pallpass->ptr = lsx_zalloc(pallpass->buffer, pallpass->size);
168  }
169  { /* EQ: highpass */
170  one_pole_t * q = &p->one_pole[0];
171  q->a1 = -exp(-2 * M_PI * fc_highpass / rate);
172  q->b0 = (1 - q->a1)/2, q->b1 = -q->b0;
173  }
174  { /* EQ: lowpass */
175  one_pole_t * q = &p->one_pole[1];
176  q->a1 = -exp(-2 * M_PI * fc_lowpass / rate);
177  q->b0 = 1 + q->a1, q->b1 = 0;
178  }
179 }
180 
182  size_t length, float const * input, float * output,
183  float const * feedback, float const * hf_damping, float const * gain)
184 {
185  while (length--) {
186  float out = 0, in = *input++;
187 
188  size_t i = array_length(comb_lengths) - 1;
189  do out += comb_process(p->comb + i, &in, feedback, hf_damping);
190  while (i--);
191 
192  i = array_length(allpass_lengths) - 1;
193  do out = allpass_process(p->allpass + i, &out);
194  while (i--);
195 
196  out = one_pole_process(&p->one_pole[0], out);
197  out = one_pole_process(&p->one_pole[1], out);
198  *output++ = out * *gain;
199  }
200 }
201 
203 {
204  size_t i;
205 
206  for (i = 0; i < array_length(allpass_lengths); ++i)
207  filter_delete(&p->allpass[i]);
208  for (i = 0; i < array_length(comb_lengths); ++i)
209  filter_delete(&p->comb[i]);
210 }
211 
212 typedef struct {
213  float feedback;
214  float hf_damping;
215  float gain;
217  filter_array_t chan[2];
218  float * out[2];
219 } reverb_t;
220 
221 static void reverb_create(reverb_t * p, double sample_rate_Hz,
222  double wet_gain_dB,
223  double room_scale, /* % */
224  double reverberance, /* % */
225  double hf_damping, /* % */
226  double pre_delay_ms,
227  double stereo_depth,
228  double tone_low, /* % */
229  double tone_high, /* % */
230  size_t buffer_size,
231  float * * out)
232 {
233  size_t i, delay = pre_delay_ms / 1000 * sample_rate_Hz + .5;
234  double scale = room_scale / 100 * .9 + .1;
235  double depth = stereo_depth / 100;
236  double a = -1 / log(1 - .3 ); /* Set minimum feedback */
237  double b = 100 / (log(1 - .98) * a + 1); /* Set maximum feedback */
238  double fc_highpass = midi_to_freq(72 - tone_low / 100 * 48);
239  double fc_lowpass = midi_to_freq(72 + tone_high/ 100 * 48);
240 
241  memset(p, 0, sizeof(*p));
242  p->feedback = 1 - exp((reverberance - b) / (a * b));
243  p->hf_damping = hf_damping / 100 * .3 + .2;
244  p->gain = dB_to_linear(wet_gain_dB) * .015;
245  fifo_create(&p->input_fifo, sizeof(float));
246  memset(fifo_write(&p->input_fifo, delay, 0), 0, delay * sizeof(float));
247  for (i = 0; i <= ceil(depth); ++i) {
248  filter_array_create(p->chan + i, sample_rate_Hz, scale, i * depth, fc_highpass, fc_lowpass);
249  out[i] = lsx_zalloc(p->out[i], buffer_size);
250  }
251 }
252 
253 static void reverb_process(reverb_t * p, size_t length)
254 {
255  size_t i;
256  for (i = 0; i < 2 && p->out[i]; ++i)
257  filter_array_process(p->chan + i, length, (float *) fifo_read_ptr(&p->input_fifo), p->out[i], &p->feedback, &p->hf_damping, &p->gain);
258  fifo_read(&p->input_fifo, length, NULL);
259 }
260 
261 static void reverb_delete(reverb_t * p)
262 {
263  size_t i;
264  for (i = 0; i < 2 && p->out[i]; ++i) {
265  free(p->out[i]);
266  filter_array_delete(p->chan + i);
267  }
268  fifo_delete(&p->input_fifo);
269 }
270 
FIFO_SIZE_T
#define FIFO_SIZE_T
Definition: Reverb_libSoX.h:29
one_pole_t::o1
double o1
Definition: Reverb_libSoX.h:132
allpass_lengths
static const size_t allpass_lengths[]
Definition: Reverb_libSoX.h:143
filter_delete
#define filter_delete(p)
Definition: Reverb_libSoX.h:34
fifo_write
static void * fifo_write(fifo_t *f, FIFO_SIZE_T n, void const *data)
Definition: Reverb_libSoX.h:74
fifo_t::end
size_t end
Definition: Reverb_libSoX.h:41
fifo_create
static void fifo_create(fifo_t *f, FIFO_SIZE_T item_size)
Definition: Reverb_libSoX.h:99
fifo_t::begin
size_t begin
Definition: Reverb_libSoX.h:40
fifo_read_ptr
#define fifo_read_ptr(f)
Definition: Reverb_libSoX.h:31
filter_array_delete
static void filter_array_delete(filter_array_t *p)
Definition: Reverb_libSoX.h:202
filter_array_create
static void filter_array_create(filter_array_t *p, double rate, double scale, double offset, double fc_highpass, double fc_lowpass)
Definition: Reverb_libSoX.h:151
reverb_t::chan
filter_array_t chan[2]
Definition: Reverb_libSoX.h:217
fifo_clear
static void fifo_clear(fifo_t *f)
Definition: Reverb_libSoX.h:44
fifo_t::item_size
size_t item_size
Definition: Reverb_libSoX.h:39
fifo_read
static void * fifo_read(fifo_t *f, FIFO_SIZE_T n, void *data)
Definition: Reverb_libSoX.h:82
filter_array_t::allpass
filter_t allpass[array_length(allpass_lengths)]
Definition: Reverb_libSoX.h:147
filter_array_process
static void filter_array_process(filter_array_t *p, size_t length, float const *input, float *output, float const *feedback, float const *hf_damping, float const *gain)
Definition: Reverb_libSoX.h:181
fifo_delete
static void fifo_delete(fifo_t *f)
Definition: Reverb_libSoX.h:94
one_pole_t::i1
double i1
Definition: Reverb_libSoX.h:132
reverb_process
static void reverb_process(reverb_t *p, size_t length)
Definition: Reverb_libSoX.h:253
lsx_zalloc
#define lsx_zalloc(var, n)
Definition: Reverb_libSoX.h:32
one_pole_t::b0
double b0
Definition: Reverb_libSoX.h:132
FIFO_MIN
#define FIFO_MIN
Definition: Reverb_libSoX.h:30
reverb_delete
static void reverb_delete(reverb_t *p)
Definition: Reverb_libSoX.h:261
reverb_t::out
float * out[2]
Definition: Reverb_libSoX.h:218
reverb_t::input_fifo
fifo_t input_fifo
Definition: Reverb_libSoX.h:216
filter_t::ptr
float * ptr
Definition: Reverb_libSoX.h:109
filter_array_t
Definition: Reverb_libSoX.h:145
filter_array_t::comb
filter_t comb[array_length(comb_lengths)]
Definition: Reverb_libSoX.h:146
one_pole_t::b1
double b1
Definition: Reverb_libSoX.h:132
filter_t
Definition: Reverb_libSoX.h:107
filter_t::size
size_t size
Definition: Reverb_libSoX.h:108
fifo_t::allocation
size_t allocation
Definition: Reverb_libSoX.h:38
one_pole_t
Definition: Reverb_libSoX.h:132
reverb_create
static void reverb_create(reverb_t *p, double sample_rate_Hz, double wet_gain_dB, double room_scale, double reverberance, double hf_damping, double pre_delay_ms, double stereo_depth, double tone_low, double tone_high, size_t buffer_size, float **out)
Definition: Reverb_libSoX.h:221
array_length
#define array_length(a)
Definition: Reverb_libSoX.h:26
filter_t::buffer
float * buffer
Definition: Reverb_libSoX.h:109
filter_array_t::one_pole
one_pole_t one_pole[2]
Definition: Reverb_libSoX.h:148
dB_to_linear
#define dB_to_linear(x)
Definition: Reverb_libSoX.h:27
comb_lengths
static const size_t comb_lengths[]
Definition: Reverb_libSoX.h:142
filter_t::store
float store
Definition: Reverb_libSoX.h:110
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
comb_process
static float comb_process(filter_t *p, float const *input, float const *feedback, float const *hf_damping)
Definition: Reverb_libSoX.h:113
reverb_t::gain
float gain
Definition: Reverb_libSoX.h:215
one_pole_t::a1
double a1
Definition: Reverb_libSoX.h:132
fifo_t::data
char * data
Definition: Reverb_libSoX.h:37
filter_advance
#define filter_advance(p)
Definition: Reverb_libSoX.h:33
reverb_t::hf_damping
float hf_damping
Definition: Reverb_libSoX.h:214
stereo_adjust
static const size_t stereo_adjust
Definition: Reverb_libSoX.h:143
reverb_t
Definition: Reverb_libSoX.h:212
M_PI
#define M_PI
Definition: Distortion.cpp:29
fifo_reserve
static void * fifo_reserve(fifo_t *f, FIFO_SIZE_T n)
Definition: Reverb_libSoX.h:49
fifo_t
Definition: Reverb_libSoX.h:36
midi_to_freq
#define midi_to_freq(n)
Definition: Reverb_libSoX.h:28
reverb_t::feedback
float feedback
Definition: Reverb_libSoX.h:213
allpass_process
static float allpass_process(filter_t *p, float const *input)
Definition: Reverb_libSoX.h:123
one_pole_process
static float one_pole_process(one_pole_t *p, float i0)
Definition: Reverb_libSoX.h:134