1 /* WhySynth DSSI software synthesizer plugin
2 *
3 * Copyright (C) 2008, 2010 Sean Bolton and others.
4 *
5 * Nearly all of this code comes from the file reverbsc.c in
6 * Csound 5.08, copyright (c) 2005 Istvan Varga. Comments from
7 * the original source:
8 *
9 * 8 delay line FDN reverb, with feedback matrix based upon
10 * physical modeling scattering junction of 8 lossless waveguides
11 * of equal characteristic impedance. Based on Julius O. Smith III,
12 * "A New Approach to Digital Reverberation using Closed Waveguide
13 * Networks," Proceedings of the International Computer Music
14 * Conference 1985, p. 47-53 (also available as a seperate
15 * publication from CCRMA), as well as some more recent papers by
16 * Smith and others.
17 *
18 * Csound orchestra version coded by Sean Costello, October 1999
19 *
20 * C implementation (C) 2005 Istvan Varga
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License as
24 * published by the Free Software Foundation; either version 2 of
25 * the License, or (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be
28 * useful, but WITHOUT ANY WARRANTY; without even the implied
29 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
30 * PURPOSE. See the GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public
33 * License along with this program; if not, write to the Free
34 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
35 * Boston, MA 02110-1301 USA.
36 */
37
38 #define _BSD_SOURCE 1
39 #define _SVID_SOURCE 1
40 #define _ISOC99_SOURCE 1
41
42 #include <math.h>
43
44 #include <ladspa.h>
45
46 #include "whysynth_types.h"
47 #include "dssp_event.h"
48 #include "effects.h"
49
50 #define DEFAULT_SRATE 44100.0
51 // #define MIN_SRATE 5000.0
52 // #define MAX_SRATE 1000000.0
53 // #define MAX_PITCHMOD 20.0
54 #define DELAYPOS_SHIFT 28
55 #define DELAYPOS_SCALE 0x10000000
56 #define DELAYPOS_MASK 0x0FFFFFFF
57
58 /* reverbParams[n][0] = delay time (in seconds) */
59 /* reverbParams[n][1] = random variation in delay time (in seconds) */
60 /* reverbParams[n][2] = random variation frequency (in 1/sec) */
61 /* reverbParams[n][3] = random seed (0 - 32767) */
62
63 static const double reverbParams[8][4] = {
64 { (2473.0 / DEFAULT_SRATE), 0.0010, 3.100, 1966.0 },
65 { (2767.0 / DEFAULT_SRATE), 0.0011, 3.500, 29491.0 },
66 { (3217.0 / DEFAULT_SRATE), 0.0017, 1.110, 22937.0 },
67 { (3557.0 / DEFAULT_SRATE), 0.0006, 3.973, 9830.0 },
68 { (3907.0 / DEFAULT_SRATE), 0.0010, 2.341, 20643.0 },
69 { (4127.0 / DEFAULT_SRATE), 0.0011, 1.897, 22937.0 },
70 { (2143.0 / DEFAULT_SRATE), 0.0017, 0.891, 29491.0 },
71 { (1933.0 / DEFAULT_SRATE), 0.0006, 3.221, 14417.0 }
72 };
73
74 static const double outputGain = 0.35;
75 static const double jpScale = 0.25;
76
77 typedef struct {
78 int writePos;
79 int bufferSize;
80 int readPos;
81 int readPosFrac;
82 int readPosFrac_inc;
83 int seedVal;
84 int randLine_cnt;
85 double filterState;
86 float *buf;
87 } delayLine;
88
89 typedef struct {
90 double dampFact;
91 float prv_LPFreq;
92 delayLine delayLines[8];
93 } SC_REVERB;
94
95 static int
delay_line_max_samples(y_synth_t * synth,int n)96 delay_line_max_samples(y_synth_t *synth, int n)
97 {
98 double maxDel;
99
100 maxDel = reverbParams[n][0];
101 /* was: maxDel += (reverbParams[n][1] * (double) *(p->iPitchMod) * 1.125); */
102 maxDel += (reverbParams[n][1] * 10.0 * 1.125);
103 return (int) (maxDel * (double) synth->sample_rate + 16.5);
104 }
105
106 static double
pitch_mod(y_synth_t * synth)107 pitch_mod(y_synth_t *synth)
108 {
109 double m = (double) *(synth->effect_param6);
110
111 if (m < 0.8)
112 return (m / 0.8);
113 else
114 return 1.0 + (m - 0.8) * 45.0;
115 }
116
117 static void
next_random_lineseg(y_synth_t * synth,SC_REVERB * p,delayLine * lp,int n)118 next_random_lineseg(y_synth_t *synth, SC_REVERB *p, delayLine *lp, int n)
119 {
120 double prvDel, nxtDel, phs_incVal;
121
122 /* update random seed */
123 if (lp->seedVal < 0)
124 lp->seedVal += 0x10000;
125 lp->seedVal = (lp->seedVal * 15625 + 1) & 0xFFFF;
126 if (lp->seedVal >= 0x8000)
127 lp->seedVal -= 0x10000;
128 /* length of next segment in samples */
129 lp->randLine_cnt = (int) (((double)synth->sample_rate / reverbParams[n][2]) + 0.5);
130 prvDel = (double) lp->writePos;
131 prvDel -= ((double) lp->readPos
132 + ((double) lp->readPosFrac / (double) DELAYPOS_SCALE));
133 while (prvDel < 0.0)
134 prvDel += (double) lp->bufferSize;
135 prvDel = prvDel / (double)synth->sample_rate; /* previous delay time in seconds */
136 nxtDel = (double) lp->seedVal * reverbParams[n][1] / 32768.0;
137 /* next delay time in seconds */
138 /* was: nxtDel = reverbParams[n][0] + (nxtDel * (double) *(p->iPitchMod)); */
139 nxtDel = reverbParams[n][0] + (nxtDel * pitch_mod(synth));
140 /* calculate phase increment per sample */
141 phs_incVal = (prvDel - nxtDel) / (double) lp->randLine_cnt;
142 phs_incVal = phs_incVal * (double)synth->sample_rate + 1.0;
143 lp->readPosFrac_inc = (int) (phs_incVal * DELAYPOS_SCALE + 0.5);
144 }
145
146 static void
init_delay_line(y_synth_t * synth,SC_REVERB * p,delayLine * lp,int n)147 init_delay_line(y_synth_t *synth, SC_REVERB *p, delayLine *lp, int n)
148 {
149 double readPos;
150
151 /* delay line bufferSize and buffer address already set up */
152 lp->writePos = 0;
153 /* set random seed */
154 lp->seedVal = (int) (reverbParams[n][3] + 0.5);
155 /* set initial delay time */
156 readPos = (double) lp->seedVal * reverbParams[n][1] / 32768.0;
157 /* was: readPos = reverbParams[n][0] + (readPos * (double) *(p->iPitchMod)); */
158 readPos = reverbParams[n][0] + (readPos * pitch_mod(synth));
159 readPos = (double) lp->bufferSize - (readPos * (double)synth->sample_rate);
160 lp->readPos = (int) readPos;
161 readPos = (readPos - (double) lp->readPos) * (double) DELAYPOS_SCALE;
162 lp->readPosFrac = (int) (readPos + 0.5);
163 /* initialise first random line segment */
164 next_random_lineseg(synth, p, lp, n);
165 /* delay line already cleared to zero */
166 }
167
168 void
effect_screverb_request_buffers(y_synth_t * synth)169 effect_screverb_request_buffers(y_synth_t *synth)
170 {
171 SC_REVERB *p = (SC_REVERB *)effects_request_buffer(synth, sizeof(SC_REVERB));
172 int i, nBytes;
173
174 memset(p, 0, sizeof(SC_REVERB));
175
176 effects_request_silencing_of_subsequent_allocations(synth);
177
178 /* calculate the number of bytes to allocate */
179 nBytes = 0;
180 for (i = 0; i < 8; i++) {
181 p->delayLines[i].bufferSize = delay_line_max_samples(synth, i);
182 nBytes = p->delayLines[i].bufferSize * sizeof(float);
183 nBytes = (nBytes + 15) & (~15);
184 p->delayLines[i].buf = (float *) effects_request_buffer(synth, nBytes);
185 }
186 }
187
188 void
effect_screverb_setup(y_synth_t * synth)189 effect_screverb_setup(y_synth_t *synth)
190 {
191 SC_REVERB *p = (SC_REVERB *)synth->effect_buffer;
192 int i;
193
194 /* set up delay lines */
195 for (i = 0; i < 8; i++)
196 init_delay_line(synth, p, &p->delayLines[i], i);
197 p->dampFact = 1.0;
198 p->prv_LPFreq = -1.0f;
199 }
200
201 void
effect_screverb_process(y_synth_t * synth,unsigned long sample_count,LADSPA_Data * out_left,LADSPA_Data * out_right)202 effect_screverb_process(y_synth_t *synth, unsigned long sample_count,
203 LADSPA_Data *out_left, LADSPA_Data *out_right)
204 {
205 SC_REVERB *p = (SC_REVERB *)synth->effect_buffer;
206 float wet, dry;
207 double ainL, ainR, aoutL, aoutR, feedback;
208 double vm1, v0, v1, v2, am1, a0, a1, a2, frac;
209 delayLine *lp;
210 int i, n, readPos;
211
212 wet = *(synth->effect_mix);
213 dry = 1.0f - wet;
214
215 // *(synth->effect_param4) = kfblvl = kFeedBack
216 // *(synth->effect_param5) = kfco = kLPFreq
217 // *(synth->effect_param6) = ipitchm = iPitchMod
218
219 /* calculate tone filter coefficient if frequency changed */
220 if (fabs(*(synth->effect_param5) - p->prv_LPFreq) > 1e-7f) {
221 p->prv_LPFreq = *(synth->effect_param5);
222 /* was: p->dampFact = 2.0 - cos(p->prv_LPFreq * TWOPI / p->sampleRate); */
223 p->dampFact = 2.0 - cos((double) p->prv_LPFreq * M_PI);
224 p->dampFact = p->dampFact - sqrt(p->dampFact * p->dampFact - 1.0);
225 }
226 feedback = sqrt(*(synth->effect_param4));
227 /* update delay lines */
228 for (i = 0; i < sample_count; i++) {
229 /* DC blocker */
230 synth->dc_block_l_ynm1 = synth->voice_bus_l[i] - synth->dc_block_l_xnm1 +
231 synth->dc_block_r * synth->dc_block_l_ynm1;
232 ainL = (double)synth->dc_block_l_ynm1;
233 synth->dc_block_l_xnm1 = synth->voice_bus_l[i];
234 synth->dc_block_r_ynm1 = synth->voice_bus_r[i] - synth->dc_block_r_xnm1 +
235 synth->dc_block_r * synth->dc_block_r_ynm1;
236 ainR = (double)synth->dc_block_r_ynm1;
237 synth->dc_block_r_xnm1 = synth->voice_bus_r[i];
238 /* calculate "resultant junction pressure" and mix to input signals */
239 aoutL = 0.0;
240 for (n = 0; n < 8; n++)
241 aoutL += p->delayLines[n].filterState;
242 aoutL *= jpScale;
243 ainR += aoutL;
244 ainL += aoutL;
245 aoutL = aoutR = 0.0;
246 /* loop through all delay lines */
247 for (n = 0; n < 8; n++) {
248 lp = &p->delayLines[n];
249 /* send input signal and feedback to delay line */
250 lp->buf[lp->writePos] = (float) ((n & 1 ? ainR : ainL)
251 - lp->filterState);
252 if (++lp->writePos >= lp->bufferSize)
253 lp->writePos -= lp->bufferSize;
254 /* read from delay line with cubic interpolation */
255 if (lp->readPosFrac >= DELAYPOS_SCALE) {
256 lp->readPos += (lp->readPosFrac >> DELAYPOS_SHIFT);
257 lp->readPosFrac &= DELAYPOS_MASK;
258 }
259 if (lp->readPos >= lp->bufferSize)
260 lp->readPos -= lp->bufferSize;
261 readPos = lp->readPos;
262 frac = (double) lp->readPosFrac * (1.0 / (double) DELAYPOS_SCALE);
263 /* calculate interpolation coefficients */
264 a2 = frac * frac; a2 -= 1.0; a2 *= (1.0 / 6.0);
265 a1 = frac; a1 += 1.0; a1 *= 0.5; am1 = a1 - 1.0;
266 a0 = 3.0 * a2; a1 -= a0; am1 -= a2; a0 -= frac;
267 /* read four samples for interpolation */
268 if (readPos > 0 && readPos < (lp->bufferSize - 2)) {
269 vm1 = (double) (lp->buf[readPos - 1]);
270 v0 = (double) (lp->buf[readPos]);
271 v1 = (double) (lp->buf[readPos + 1]);
272 v2 = (double) (lp->buf[readPos + 2]);
273 } else {
274 /* at buffer wrap-around, need to check index */
275 if (--readPos < 0) readPos += lp->bufferSize;
276 vm1 = (double) lp->buf[readPos];
277 if (++readPos >= lp->bufferSize) readPos -= lp->bufferSize;
278 v0 = (double) lp->buf[readPos];
279 if (++readPos >= lp->bufferSize) readPos -= lp->bufferSize;
280 v1 = (double) lp->buf[readPos];
281 if (++readPos >= lp->bufferSize) readPos -= lp->bufferSize;
282 v2 = (double) lp->buf[readPos];
283 }
284 v0 = (am1 * vm1 + a0 * v0 + a1 * v1 + a2 * v2) * frac + v0;
285 /* update buffer read position */
286 lp->readPosFrac += lp->readPosFrac_inc;
287 /* apply feedback gain and lowpass filter */
288 v0 *= feedback;
289 v0 = (lp->filterState - v0) * p->dampFact + v0;
290 lp->filterState = v0;
291 /* mix to output */
292 if (n & 1)
293 aoutR += v0;
294 else
295 aoutL += v0;
296 /* start next random line segment if current one has reached endpoint */
297 if (--(lp->randLine_cnt) <= 0)
298 next_random_lineseg(synth, p, lp, n);
299 }
300 out_left[i] = wet * (float) (aoutL * outputGain) + dry * synth->voice_bus_l[i];
301 out_right[i] = wet * (float) (aoutR * outputGain) + dry * synth->voice_bus_r[i];
302 }
303 }
304
305