-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathreverb.c
256 lines (217 loc) · 6.5 KB
/
reverb.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "synth.h"
#include "rate.inc"
/* reverb.c: cyan's psg reverb */
/* default values are meant to reflect those from the old optionless reverb */
static void reverb(float wetoutdB, float decayamt, float damping,
float predelayms, float roomsizems, float density);
int main(int argc, char *argv[])
{
float wetoutdB = 0.0;
float decayamt = 0.8;
float damping = 0.9;
float roomsizems = 226.75736961451;
float predelayms = roomsizems / 10;
float density = 0.8;
int i;
get_rate();
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-wetoutdB") && i+1 < argc)
wetoutdB = atof(argv[++i]);
else if (!strcmp(argv[i], "-decay") && i+1 < argc)
decayamt = atof(argv[++i]);
else if (!strcmp(argv[i], "-damping") && i+1 < argc)
damping = atof(argv[++i]);
else if (!strcmp(argv[i], "-roomsize") && i+1 < argc)
roomsizems = atof(argv[++i]);
else if (!strcmp(argv[i], "-predelay") && i+1 < argc)
predelayms = atof(argv[++i]);
else if (!strcmp(argv[i], "-density") && i+1 < argc)
density = atof(argv[++i]);
else if (!strcmp(argv[i], "-help"))
{
fprintf(stderr,
"options (useful range) [default]:\n"
" -wetoutdB [0.0 dB]\n"
" -decay (0.0 - 1.0) [0.8]\n"
" -damping (0.0 - 0.95) [0.9]\n"
" -roomsize [226.76 ms]\n"
" -predelay [22.676 ms]\n"
" -density (0.0 - 1.0) [0.8]\n"
);
exit(0);
}
else
{
fprintf(stderr,
"reverb: disregarding unknown option %s\n",
argv[i]);
}
}
SET_BINARY_MODE
reverb(wetoutdB, decayamt, damping, predelayms, roomsizems, density);
return 0;
}
#define M_20_OVER_LN10 8.68588963806503655302257838
#define M_LN10_OVER_20 0.115129254649702284200899573
#define RATTODB(x) (log(x) * M_20_OVER_LN10)
#define DBTORAT(x) exp((x) * M_LN10_OVER_20)
/*
* The most reverb stages that will be used. The actual number of
* stages depends on how much can fit in the memory used.
*/
#define RV_MAX_STAGES 1024
/*
* How much granularity shall there be in randomly deciding the
* gain of each reverb stage?
*/
#define RV_GAIN_RANGE 30
/*
* Reverb memory: increase for a denser sound (more stages).
* Using a small amount, like 128, will get more of a multi-tap
* delay type effect, with only about 4 or 5 stages.
*
* There are diminishing returns after 2048, the default.
*/
static size_t rv_mem = 2048;
/*
* Room size in sample frames. This affects how much memory
* each reverb stage uses.
*/
static int rv_roomsize = 10000;
/*
* Reverb pre-delay in sample frames. This also affects how
* much memory each reverb stage uses. Too low of a value
* might sound bad.
*/
static int rv_predelay = 1000;
/* Decay amount -- set too high if you want terrible feedback. */
static float rv_decay = 0.8f;
/* The extent to which high frequencies are dampened. */
static float rv_damp = 0.9f;
/* Reverb output level. */
static float rv_return = RV_GAIN_RANGE * 0.5f;
typedef struct revstate {
float *dl; /* The start of the delay lines. */
int dlstart[RV_MAX_STAGES]; /* Offset to start of each delay line. */
int dllen[RV_MAX_STAGES]; /* Length of each delay line. */
int dlpos[RV_MAX_STAGES]; /* Position in delay line, from start. */
float dlamp[RV_MAX_STAGES]; /* Amplitude of each stage. */
float flt[RV_MAX_STAGES]; /* Filtering state of each stage. */
} revstate_t;
static revstate_t *do_reverb(revstate_t *rev, float *samps, int nsamps,
int skip);
/* Number of samples to process at one time. */
#define CHUNKSIZE 10000
static void reverb(float wetoutdB, float decayamt, float damping,
float predelayms, float roomsizems, float density)
{
float f[2*CHUNKSIZE];
revstate_t *rev[2] = {NULL, NULL};
size_t cnt;
rv_return *= DBTORAT(wetoutdB);
rv_decay = decayamt;
/*
* In lieu of a way to link it to any measurement that really makes
* sense, make the damping value relative to 44.1 KHz since that is
* what the effect originally worked at.
*
* XXX: I don't really know for sure what I'm doing here.
*/
rv_damp = CLAMP(0.0, damping * 44100 / RATE, 0.95);
rv_predelay = (int)(predelayms / 1000.0 * RATE);
rv_roomsize = (int)(roomsizems / 1000.0 * RATE);
density = CLAMP(0.0, density, 1.0);
rv_mem = (int)pow(2, 7 + 5*density);
while ((cnt = fread(f, sizeof f[0]*2, CHUNKSIZE, stdin)) >= 1)
{
rev[0] = do_reverb(rev[0], f, cnt, 2);
rev[1] = do_reverb(rev[1], f+1, cnt, 2);
if (fwrite(f, sizeof f[0]*2, cnt, stdout) < cnt)
return;
}
}
static void init_revstate(revstate_t *rev)
{
int ix;
int memoffset;
rev->dl = (float *)(((char *)rev) + sizeof *rev);
memset(rev->dl, 0, rv_mem*RV_MAX_STAGES);
for (ix = 0, memoffset = 0; ix < RV_MAX_STAGES; ix++)
{
rev->flt[ix] = 0;
rev->dlstart[ix] = memoffset;
rev->dllen[ix] = (rand()%rv_roomsize)+rv_predelay;
memoffset += rev->dllen[ix];
rev->dlpos[ix] = 0;
rev->dlamp[ix] = (1 + rand() % (RV_GAIN_RANGE-1))
/ (float)RV_GAIN_RANGE;
if ((memoffset*sizeof (float)) >= (rv_mem*RV_MAX_STAGES))
{
/* Out of memory for reverb stages. */
rev->dllen[ix] = 0;
break;
}
}
}
/*
* "skip" parameter is how many array indices to skip when
* moving to the next sample. For example, this can be given
* as 2 to use only the first channel of stereo audio.
*/
void run_reverb(revstate_t *rev, float *samps, int nsamps, const int skip)
{
int ix;
int stage;
float sum;
for (ix = 0; ix < skip*nsamps; ix += skip)
{
sum = 0.0f; /* to hold the sum of all stages */
for (stage = 0; stage < RV_MAX_STAGES; stage++)
{
const int offset =
rev->dlstart[stage] + rev->dlpos[stage];
float revdloffset;
if (rev->dllen[stage] == 0) /* no more stages */
break;
/* Get delay line sample and fix if denormal. */
revdloffset = rev->dl[offset];
revdloffset += 1e-18;
revdloffset -= 1e-18;
sum += rev->dlamp[stage] * revdloffset;
/* Update filter state, fixing denormals. */
rev->flt[stage] =
rev->flt[stage]*rv_damp
+ (revdloffset*(1-rv_damp));
rev->flt[stage] += 1e-18;
rev->flt[stage] -= 1e-18;
rev->dl[offset] = samps[ix] * (1-rv_decay)
+ rev->flt[stage] * rv_decay;
if (++rev->dlpos[stage] == rev->dllen[stage])
rev->dlpos[stage] = 0;
}
sum /= (float)stage; /* average all stages */
samps[ix] += sum * rv_return;
}
}
static revstate_t *do_reverb(revstate_t *rev, float *samps, int nsamps,
int skip)
{
if (rev == NULL)
{
rev = malloc(sizeof *rev + RV_MAX_STAGES*rv_mem);
if (rev == NULL)
{
fprintf(stderr, "Out of memory, disabling reverb\n");
return rev;
}
else
init_revstate(rev);
}
run_reverb(rev, samps, nsamps, skip);
return rev;
}