1 /*
2 * GNUitar
3 * Distortion effect
4 * Copyright (C) 2000,2001,2003 Max Rudensky <fonin@ziet.zhitomir.ua>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * $Id: distort2.c,v 1.13 2005/04/24 19:11:22 fonin Exp $
21 *
22 * $Log: distort2.c,v $
23 * Revision 1.13 2005/04/24 19:11:22 fonin
24 * Optimized for zero input (after the noise filter) to avoid the extra calcs
25 *
26 * Revision 1.12 2005/04/18 12:55:50 fonin
27 * Fixed a typo in src/distort2.c
28 *
29 * Revision 1.11 2005/04/15 14:33:29 fonin
30 * Code lickup
31 *
32 * Revision 1.10 2005/04/06 19:34:20 fonin
33 * Code lickup
34 *
35 * Revision 1.9 2004/10/21 11:05:40 dexterus
36 * Fully working realtime version
37 * Fixed bugs , improved sound, added oversampling
38 * Note: this is an mathematically accurate simulation of
39 * Ibanez Tube Screamer 9, with the excetion of diodes electrical paramaters
40 * ( modified to make it sound more aggresive )
41 *
42 * Revision 1.8 2004/08/10 15:11:01 fonin
43 * Reworked distortion - process in realtime rather then use lookup table
44 *
45 * Revision 1.7 2004/07/07 19:18:42 fonin
46 * GTK2 port
47 *
48 * Revision 1.6 2003/04/21 09:35:51 fonin
49 * Bugfix with missing parameter in strncat(), line 74.
50 *
51 * Revision 1.5 2003/04/17 12:22:00 fonin
52 * More search paths for lookup dir.
53 *
54 * Revision 1.4 2003/04/16 18:40:00 fonin
55 * - lookup dir search paths for Win32;
56 * - R1 parameter should be inverted 100% == 1% and vice versa.
57 *
58 * Revision 1.3 2003/04/16 13:58:39 fonin
59 * - trying to guess the lookup directory;
60 * - filling the lookup table with constant 32767 by default.
61 *
62 * Revision 1.2 2003/04/12 20:00:56 fonin
63 * Stupid bugfix (forgot to move forward buffer pointer
64 * in the filter function); "level" control taken out.
65 *
66 * Revision 1.1 2003/04/11 18:32:24 fonin
67 * New distortion effect.
68 *
69 */
70
71 #include <stdlib.h>
72 #include <sys/stat.h>
73 #include <fcntl.h>
74 #ifndef _WIN32
75 # include <unistd.h>
76 #else
77 # include <io.h>
78 #endif
79 #include "distort2.h"
80 #include "gui.h"
81 #include "utils.h"
82 #include <math.h>
83
84
85 #define UPSAMPLE 4
86
87 #define DIST2_DOWNSCALE 16.0 / MAX_SAMPLE /* Used to reduce the signal to */
88 /* the limits needed by the */
89 /* simulation */
90 #define DIST2_UPSCALE MAX_SAMPLE * 0.2 /* And back to the normal range */
91 /* taken as a funtion of MAX_SAMPLE because that is the reference for
92 * what the 'normal' signal should be */
93
94 /* Check if the compiler is Visual C or GCC */
95 #if defined(_MSC_VER) || defined(__GNUC__)
96 # pragma intrinsic (exp,log)
97 #endif
98
99 void distort2_filter(struct effect *p, struct data_block *db);
100
101 void
update_distort2_drive(GtkAdjustment * adj,struct distort2_params * params)102 update_distort2_drive(GtkAdjustment * adj, struct distort2_params *params)
103 {
104 params->r2 = (int) adj->value * 5000;
105 params->r2 -= params->r2 % 10;
106 params->r2 += 50;
107 }
108
109 void
update_distort2_treble(GtkAdjustment * adj,struct distort2_params * params)110 update_distort2_treble(GtkAdjustment * adj, struct distort2_params *params)
111 {
112 params->noisegate = (int) adj->value;
113 RC_set_freq(params->noisegate, &(params->noise));
114 }
115
116 void
toggle_distort2(void * bullshit,struct effect * p)117 toggle_distort2(void *bullshit, struct effect *p)
118 {
119 if (p->toggle == 1) {
120 p->proc_filter = passthru;
121 p->toggle = 0;
122 } else {
123 p->proc_filter = distort2_filter;
124 p->toggle = 1;
125 }
126 }
127
128 void
toggle_treble(void * bullshit,struct distort2_params * params)129 toggle_treble(void *bullshit, struct distort2_params *params)
130 {
131 params->treble = !params->treble;
132 }
133
134 void
distort2_init(struct effect * p)135 distort2_init(struct effect *p)
136 {
137 struct distort2_params *pdistort;
138
139 GtkWidget *drive;
140 GtkWidget *drive_label;
141 GtkObject *adj_drive;
142
143 GtkWidget *treble;
144 GtkWidget *treble_label;
145 GtkObject *adj_treble;
146
147 GtkWidget *button;
148 GtkWidget *treble_switch;
149
150 GtkWidget *parmTable;
151
152 pdistort = (struct distort2_params *) p->params;
153
154 /*
155 * GUI Init
156 */
157 #ifdef HAVE_GTK
158 p->control = gtk_window_new(GTK_WINDOW_DIALOG);
159 #elif defined HAVE_GTK2
160 p->control = gtk_window_new(GTK_WINDOW_TOPLEVEL);
161 #endif
162
163 gtk_signal_connect(GTK_OBJECT(p->control), "delete_event",
164 GTK_SIGNAL_FUNC(delete_event), NULL);
165
166 parmTable = gtk_table_new(4, 2, FALSE);
167
168 adj_drive = gtk_adjustment_new((pdistort->r2 + 50) / 100,
169 1.0, 101.0, 0, 0, 0);
170 drive_label = gtk_label_new("Drive\n%");
171 gtk_table_attach(GTK_TABLE(parmTable), drive_label, 0, 1, 0, 1,
172 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
173 GTK_SHRINK),
174 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
175 GTK_SHRINK), 0, 0);
176
177 gtk_signal_connect(GTK_OBJECT(adj_drive), "value_changed",
178 GTK_SIGNAL_FUNC(update_distort2_drive), pdistort);
179 drive = gtk_vscale_new(GTK_ADJUSTMENT(adj_drive));
180 #ifdef HAVE_GTK2
181 gtk_widget_set_size_request(GTK_WIDGET(drive),0,100);
182 #endif
183
184 gtk_table_attach(GTK_TABLE(parmTable), drive, 0, 1, 1, 2,
185 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
186 GTK_SHRINK),
187 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
188 GTK_SHRINK), 0, 0);
189
190 adj_treble = gtk_adjustment_new(pdistort->noisegate,
191 1000.0, 6001.0, 1, 1, 1);
192 treble_label = gtk_label_new("Treble\nHz");
193 gtk_table_attach(GTK_TABLE(parmTable), treble_label, 2, 3, 0, 1,
194 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
195 GTK_SHRINK),
196 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
197 GTK_SHRINK), 0, 0);
198
199 gtk_signal_connect(GTK_OBJECT(adj_treble), "value_changed",
200 GTK_SIGNAL_FUNC(update_distort2_treble), pdistort);
201 treble = gtk_vscale_new(GTK_ADJUSTMENT(adj_treble));
202 #ifdef HAVE_GTK2
203 gtk_widget_set_size_request(GTK_WIDGET(treble),0,100);
204 #endif
205
206 gtk_table_attach(GTK_TABLE(parmTable), treble, 2, 3, 1, 2,
207 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
208 GTK_SHRINK),
209 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
210 GTK_SHRINK), 0, 0);
211
212 button = gtk_check_button_new_with_label("On");
213 gtk_signal_connect(GTK_OBJECT(button), "toggled",
214 GTK_SIGNAL_FUNC(toggle_distort2), p);
215
216 gtk_table_attach(GTK_TABLE(parmTable), button, 0, 1, 3, 4,
217 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
218 GTK_SHRINK),
219 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
220 GTK_SHRINK), 0, 0);
221 if (p->toggle == 1) {
222 p->toggle = 0;
223 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
224 }
225
226 treble_switch = gtk_check_button_new_with_label("On");
227 gtk_signal_connect(GTK_OBJECT(treble_switch), "toggled",
228 GTK_SIGNAL_FUNC(toggle_treble), pdistort);
229
230 gtk_table_attach(GTK_TABLE(parmTable), treble_switch, 2, 3, 3, 4,
231 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
232 GTK_SHRINK),
233 __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
234 GTK_SHRINK), 0, 0);
235
236 gtk_window_set_title(GTK_WINDOW(p->control),
237 (gchar *) ("Distortion 2"));
238 gtk_container_add(GTK_CONTAINER(p->control), parmTable);
239
240 gtk_widget_show_all(p->control);
241 }
242
243 void
distort2_filter(struct effect * p,struct data_block * db)244 distort2_filter(struct effect *p, struct data_block *db)
245 {
246 /* the original value doesn't produce enough distortion,
247 * maybe wrong electrical parameters ? */
248 // #define mUt 30*1e-3
249 #define mUt 30*1e+2
250 #define Is 10*1e-12
251
252 int i,count;
253 static int curr_channel = 0;
254 DSP_SAMPLE *s;
255 struct distort2_params *dp;
256 static double x,y,x1,f,df,dx,e1,e2;
257 static double upsample [UPSAMPLE];
258 #define DRIVE (dp->r2)
259 dp = (struct distort2_params *) p->params;
260 count = db->len;
261 s = db->data;
262
263 /* no input, no output :-) to avoid extra calc. Optimized for noise gate,
264 * when all input is zero.
265 * This is the heuristics - since there is no the standard function
266 * in the ANSI C library that reliably compares the memory region
267 * with the given byte, we compare just a few excerpts from an array.
268 * If everything is zero, we have a large chances that all array is zero. */
269 if(s[0]==0 && s[1]==0 && s[16]==0 && s[17]==0 &&
270 s[24]==0 && s[25]==0 && s[32]==0 && s[33]==0 &&
271 s[buffer_size-1]==0) {
272 dp->last[0]=dp->last[1]=dp->lastupsample=0;
273 return;
274 }
275
276 /*
277 * process signal; x - input, in the range -1, 1
278 */
279 while (count) {
280
281 /* scale down to -1..1 range */
282 x = *s ;
283 x *= DIST2_DOWNSCALE ;
284
285 /* first we prepare the lineary interpoled upsamples */
286 y = 0;
287 upsample[0] = dp->lastupsample;
288 y = 1.0 / UPSAMPLE; /* temporary usage of y */
289 for (i=1; i< UPSAMPLE; i++)
290 {
291 upsample[i] = dp->lastupsample + ( x - dp->lastupsample) *y;
292 y += 1.0 / UPSAMPLE;
293 }
294 dp->lastupsample = x;
295 /* Now the actual upsampled processing */
296 for (i=0; i<UPSAMPLE; i++)
297 {
298 x = upsample[i]; /*get one of the upsamples */
299
300 /* first compute the linear rc filter current output */
301 y = dp->c0*x + dp->d1 * dp->lyf;
302 dp->lyf = y;
303 x1 = (x-y) / 4700.0;
304
305 /* start searching from time previous point , improves speed */
306 y = dp->last[curr_channel];
307 do {
308 /* f(y) = 0 , y= ? */
309 e1 = exp ( (x-y) / mUt ); e2 = 1.0 / e1;
310
311 /* f=x1+(x-y)/DRIVE+Is*(exp((x-y)/mUt)-exp((y-x)/mUt)); optimized makes : */
312 f = x1 + (x-y)/ DRIVE + Is * (e1 - e2);
313
314 /* df/dy */
315 /*df=-1.0/DRIVE-Is/mUt*(exp((x-y)/mUt)+exp((y-x)/mUt)); optimized makes : */
316 df = -1.0 / DRIVE - Is / mUt * (e1 + e2);
317
318 /* This is the newton's algo, it searches a root of a function,
319 * f here, which must equal 0, using it's derivate. */
320 dx=f/df;
321 y-=dx;
322 }
323 while ((dx>0.01)||(dx<-0.01));
324 /* when dx gets very small, we found a solution. */
325
326 dp->last[curr_channel] = y;
327 y = doBiquad( y, &dp->cheb, curr_channel);
328 y = doBiquad( y, &dp->cheb1, curr_channel);
329 }
330
331 /* scale up from -1..1 range */
332 *s = y * DIST2_UPSCALE;
333
334 /*if(*s > MAX_SAMPLE)
335 *s=MAX_SAMPLE;
336 else if(*s < -MAX_SAMPLE)
337 *s=-MAX_SAMPLE;*/
338
339 s++;
340 count--;
341
342 if (nchannels > 1)
343 curr_channel = !curr_channel;
344
345 }
346 if(dp->treble)
347 RC_lowpass(db->data, db->len, &(dp->noise));
348 #undef DRIVE
349 }
350
351 void
distort2_done(struct effect * p)352 distort2_done(struct effect *p)
353 {
354 struct distort2_params *ap;
355
356 ap = (struct distort2_params *) p->params;
357 free(ap->cheb.mem); free(ap->cheb1.mem);
358 free(p->params);
359 gtk_widget_destroy(p->control);
360 free(p);
361 p = NULL;
362 }
363
364 void
distort2_save(struct effect * p,int fd)365 distort2_save(struct effect *p, int fd)
366 {
367 struct distort2_params *ap;
368
369 ap = (struct distort2_params *) p->params;
370
371 write(fd, &ap->r2, sizeof(ap->r2));
372 write(fd, &ap->noise, sizeof(ap->noise));
373 write(fd, &ap->treble, sizeof(ap->treble));
374 }
375
376 void
distort2_load(struct effect * p,int fd)377 distort2_load(struct effect *p, int fd)
378 {
379 struct distort2_params *ap;
380
381 ap = (struct distort2_params *) p->params;
382
383 read(fd, &ap->r2, sizeof(ap->r2));
384 read(fd, &ap->noise, sizeof(ap->noise));
385 read(fd, &ap->treble, sizeof(ap->treble));
386 if (p->toggle == 0) {
387 p->proc_filter = passthru;
388 } else {
389 p->proc_filter = distort2_filter;
390 }
391 }
392
393
394 void
distort2_create(struct effect * p)395 distort2_create(struct effect *p)
396 {
397 struct distort2_params *ap;
398 int i;
399 double Ts, Ts1;
400 double RC=(0.047*1e-6)*(4.7*1e+3);
401 p->params =
402 (struct distort2_params *) malloc(sizeof(struct distort2_params));
403 ap = (struct distort2_params *) p->params;
404
405 p->proc_init = distort2_init;
406 p->proc_filter = passthru;
407 p->proc_save = distort2_save;
408 p->proc_load = distort2_load;
409 p->toggle = 0;
410 p->id = DISTORT2;
411 p->proc_done = distort2_done;
412
413 ap->r2 = 520;
414 ap->noisegate = 3500;
415 ap->treble = 0;
416
417 RC_setup(10, 1, &(ap->noise));
418 RC_set_freq(ap->noisegate, &(ap->noise));
419 /* RC Filter tied to ground setup */
420 Ts = 1.0/sample_rate;
421 Ts1 = Ts / UPSAMPLE; /* Ts1 is Ts for upsampled processing */
422
423 /* Init stuff
424 * This is the rc filter tied to ground. */
425 ap->c0 = Ts1 / (Ts1 + RC);
426 ap->d1 = RC / (Ts1 + RC);
427 ap->lyf = 0;
428
429 for (i=0; i < nchannels; i++)
430 ap->last[i] = 0;
431 ap->lastupsample = 0;
432 ap->cheb.mem = (double*) malloc ( nchannels * sizeof (double) * 4 );
433 memset ( (void*) ap->cheb.mem, 0 , nchannels * sizeof (double) * 4 );
434 ap->cheb1.mem = (double*) malloc ( nchannels * sizeof (double) * 4 );
435 memset ( (void*) ap->cheb1.mem, 0 , nchannels * sizeof (double) * 4 );
436
437 /* 2 lowPass Chebyshev filters used in downsampling */
438 CalcChebyshev2(sample_rate * UPSAMPLE, 12000, 1, 1, &ap->cheb);
439 CalcChebyshev2(sample_rate * UPSAMPLE, 5500, 1, 1, &ap->cheb1);
440 }
441