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