1 /*
2  * GNUitar
3  * Chorus 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: chorus.c,v 1.12 2004/08/10 15:07:31 fonin Exp $
21  *
22  * $Log: chorus.c,v $
23  * Revision 1.12  2004/08/10 15:07:31  fonin
24  * Support processing in float/int - type DSP_SAMPLE
25  *
26  * Revision 1.11  2004/07/07 19:18:42  fonin
27  * GTK2 port
28  *
29  * Revision 1.10  2003/03/11 22:04:00  fonin
30  * Measure control sliders in standard units (ms, %).
31  *
32  * Revision 1.9  2003/03/09 20:49:45  fonin
33  * Structures were redesigned to allow to change sampling params.
34  *
35  * Revision 1.8  2003/02/05 21:10:10  fonin
36  * Cleanup before release.
37  *
38  * Revision 1.7  2003/02/03 11:39:25  fonin
39  * Copyright year changed.
40  *
41  * Revision 1.6  2003/02/01 19:15:12  fonin
42  * Use sizeof(variable) instead sizeof(type) in load/save procedures,
43  * when reading/writing from file.
44  *
45  * Revision 1.5  2003/01/30 21:35:29  fonin
46  * Got rid of rnd_window_pos().
47  *
48  * Revision 1.4  2003/01/29 19:34:00  fonin
49  * Win32 port.
50  *
51  * Revision 1.3  2001/06/02 13:59:04  fonin
52  * Fixed bug caused backbuff_get() assertion in chorus_filter().
53  * Added GNU disclaimer.
54  *
55  * Revision 1.2  2001/03/25 12:10:49  fonin
56  * Effect window control ignores delete event.
57  *
58  * Revision 1.1.1.1  2001/01/11 13:21:15  fonin
59  * Version 0.1.0 Release 1 beta
60  *
61  */
62 
63 #include "chorus.h"
64 #include "backbuf.h"
65 #include "gui.h"
66 #include <math.h>
67 #ifndef _WIN32
68 #    include <unistd.h>
69 #else
70 #    include "utils.h"
71 #    include <io.h>
72 #endif
73 #include <stdio.h>
74 #include <stdlib.h>
75 
76 int             sinLookUp[360];
77 short           isSinLookUp = 0;
78 
79 void
80                 chorus_filter(struct effect *p, struct data_block *db);
81 
82 void
update_chorus_speed(GtkAdjustment * adj,struct chorus_params * params)83 update_chorus_speed(GtkAdjustment * adj, struct chorus_params *params)
84 {
85     params->speed =
86 	(int) 360.0 *sample_rate / (adj->value * 1000.0 * nchannels);
87 }
88 
89 void
update_chorus_depth(GtkAdjustment * adj,struct chorus_params * params)90 update_chorus_depth(GtkAdjustment * adj, struct chorus_params *params)
91 {
92     params->depth = (int) adj->value / 2;
93 }
94 
95 void
update_chorus_mode(GtkAdjustment * adj,struct chorus_params * params)96 update_chorus_mode(GtkAdjustment * adj, struct chorus_params *params)
97 {
98     if (params->mode == 0) {
99 	params->mode = 1;
100     } else {
101 	params->mode = 0;
102     }
103 }
104 
105 void
update_chorus_wet(GtkAdjustment * adj,struct chorus_params * params)106 update_chorus_wet(GtkAdjustment * adj, struct chorus_params *params)
107 {
108     params->wet = (int) adj->value * 2.56;
109 }
110 
111 void
update_chorus_dry(GtkAdjustment * adj,struct chorus_params * params)112 update_chorus_dry(GtkAdjustment * adj, struct chorus_params *params)
113 {
114     params->dry = (int) adj->value * 2.56;
115 }
116 
117 void
update_chorus_regen(GtkAdjustment * adj,struct chorus_params * params)118 update_chorus_regen(GtkAdjustment * adj, struct chorus_params *params)
119 {
120     params->regen = (int) adj->value * 2.56;
121 }
122 
123 void
toggle_chorus(void * bullshit,struct effect * p)124 toggle_chorus(void *bullshit, struct effect *p)
125 {
126     if (p->toggle == 1) {
127 	p->proc_filter = passthru;
128 	p->toggle = 0;
129     } else {
130 	p->proc_filter = chorus_filter;
131 	p->toggle = 1;
132     }
133 }
134 
135 
136 void
chorus_init(struct effect * p)137 chorus_init(struct effect *p)
138 {
139     struct chorus_params *pchorus;
140 
141     GtkWidget      *speed;
142     GtkWidget      *speed_label;
143     GtkObject      *adj_speed;
144 
145     GtkWidget      *depth;
146     GtkWidget      *depth_label;
147     GtkObject      *adj_depth;
148 
149     GtkWidget      *wet;
150     GtkWidget      *wet_label;
151     GtkObject      *adj_wet;
152 
153     GtkWidget      *dry;
154     GtkWidget      *dry_label;
155     GtkObject      *adj_dry;
156 
157     GtkWidget      *regen;
158     GtkWidget      *regen_label;
159     GtkObject      *adj_regen;
160 
161     GtkWidget      *button;
162     GtkWidget      *flange;
163 
164     GtkWidget      *parmTable;
165 
166     pchorus = (struct chorus_params *) p->params;
167 
168     /*
169      * GUI Init
170      */
171 #ifdef HAVE_GTK
172     p->control = gtk_window_new(GTK_WINDOW_DIALOG);
173 #elif defined HAVE_GTK2
174     p->control = gtk_window_new(GTK_WINDOW_TOPLEVEL);
175 #endif
176 
177     gtk_signal_connect(GTK_OBJECT(p->control), "delete_event",
178 		       GTK_SIGNAL_FUNC(delete_event), NULL);
179 
180     parmTable = gtk_table_new(2, 8, FALSE);
181 
182     adj_speed =
183 	gtk_adjustment_new(sample_rate * 360 /
184 			   (pchorus->speed * 1000 * nchannels), 1.0, 3500,
185 			   0.1, 1.0, 1.0);
186     speed_label = gtk_label_new("Speed\n1/ms");
187     gtk_table_attach(GTK_TABLE(parmTable), speed_label, 3, 4, 0, 1,
188 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
189 					GTK_SHRINK),
190 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
191 					GTK_SHRINK), 0, 0);
192 
193 
194     gtk_signal_connect(GTK_OBJECT(adj_speed), "value_changed",
195 		       GTK_SIGNAL_FUNC(update_chorus_speed), pchorus);
196 
197     speed = gtk_vscale_new(GTK_ADJUSTMENT(adj_speed));
198 #ifdef HAVE_GTK2
199     gtk_widget_set_size_request(GTK_WIDGET(speed),0,100);
200 #endif
201 
202     gtk_table_attach(GTK_TABLE(parmTable), speed, 3, 4, 1, 2,
203 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
204 					GTK_SHRINK),
205 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
206 					GTK_SHRINK), 0, 0);
207 
208 
209     adj_depth =
210 	gtk_adjustment_new(pchorus->depth * 2, 0.0, 101.0, 1.0, 1.0, 1.0);
211     depth_label = gtk_label_new("Depth\n%");
212     gtk_table_attach(GTK_TABLE(parmTable), depth_label, 0, 1, 0, 1,
213 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
214 					GTK_SHRINK),
215 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
216 					GTK_SHRINK), 0, 0);
217 
218 
219     gtk_signal_connect(GTK_OBJECT(adj_depth), "value_changed",
220 		       GTK_SIGNAL_FUNC(update_chorus_depth), pchorus);
221 
222     depth = gtk_vscale_new(GTK_ADJUSTMENT(adj_depth));
223 
224     gtk_table_attach(GTK_TABLE(parmTable), depth, 0, 1, 1, 2,
225 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
226 					GTK_SHRINK),
227 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
228 					GTK_SHRINK), 0, 0);
229 
230     adj_wet =
231 	gtk_adjustment_new(pchorus->wet / 2.56, 0.0, 101.0, 1.0, 1.0, 1.0);
232     wet_label = gtk_label_new("Wet\n%");
233     gtk_table_attach(GTK_TABLE(parmTable), wet_label, 5, 6, 0, 1,
234 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
235 					GTK_SHRINK),
236 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
237 					GTK_SHRINK), 0, 0);
238 
239 
240     gtk_signal_connect(GTK_OBJECT(adj_wet), "value_changed",
241 		       GTK_SIGNAL_FUNC(update_chorus_wet), pchorus);
242 
243     wet = gtk_vscale_new(GTK_ADJUSTMENT(adj_wet));
244 
245     gtk_table_attach(GTK_TABLE(parmTable), wet, 5, 6, 1, 2,
246 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
247 					GTK_SHRINK),
248 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
249 					GTK_SHRINK), 0, 0);
250 
251     adj_dry =
252 	gtk_adjustment_new(pchorus->dry / 2.56, 0.0, 101.0, 1.0, 1.0, 1.0);
253     dry_label = gtk_label_new("Dry\n%");
254     gtk_table_attach(GTK_TABLE(parmTable), dry_label, 7, 8, 0, 1,
255 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
256 					GTK_SHRINK),
257 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
258 					GTK_SHRINK), 0, 0);
259 
260 
261     gtk_signal_connect(GTK_OBJECT(adj_wet), "value_changed",
262 		       GTK_SIGNAL_FUNC(update_chorus_dry), pchorus);
263 
264     dry = gtk_vscale_new(GTK_ADJUSTMENT(adj_dry));
265 
266     gtk_table_attach(GTK_TABLE(parmTable), dry, 7, 8, 1, 2,
267 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
268 					GTK_SHRINK),
269 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
270 					GTK_SHRINK), 0, 0);
271 
272     adj_regen =
273 	gtk_adjustment_new(pchorus->regen / 2.56, 0.0, 101.0, 1.0, 1.0,
274 			   1.0);
275     regen_label = gtk_label_new("Regen\n%");
276     gtk_table_attach(GTK_TABLE(parmTable), regen_label, 9, 10, 0, 1,
277 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
278 					GTK_SHRINK),
279 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
280 					GTK_SHRINK), 0, 0);
281 
282 
283     gtk_signal_connect(GTK_OBJECT(adj_regen), "value_changed",
284 		       GTK_SIGNAL_FUNC(update_chorus_regen), pchorus);
285 
286     regen = gtk_vscale_new(GTK_ADJUSTMENT(adj_regen));
287 
288     gtk_table_attach(GTK_TABLE(parmTable), regen, 9, 10, 1, 2,
289 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
290 					GTK_SHRINK),
291 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
292 					GTK_SHRINK), 0, 0);
293 
294     flange = gtk_check_button_new_with_label("Flange");
295     gtk_signal_connect(GTK_OBJECT(flange), "toggled",
296 		       GTK_SIGNAL_FUNC(update_chorus_mode), pchorus);
297 
298     gtk_table_attach(GTK_TABLE(parmTable), flange, 3, 4, 3, 4,
299 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
300 					GTK_SHRINK),
301 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
302 					GTK_SHRINK), 0, 0);
303     if (pchorus->mode == 1) {
304 	pchorus->mode = 0;
305 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(flange), TRUE);
306     }
307 
308     button = gtk_check_button_new_with_label("On");
309     gtk_signal_connect(GTK_OBJECT(button), "toggled",
310 		       GTK_SIGNAL_FUNC(toggle_chorus), p);
311 
312     gtk_table_attach(GTK_TABLE(parmTable), button, 3, 4, 5, 6,
313 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
314 					GTK_SHRINK),
315 		     __GTKATTACHOPTIONS(GTK_FILL | GTK_EXPAND |
316 					GTK_SHRINK), 0, 0);
317     if (p->toggle == 1) {
318 	p->toggle = 0;
319 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
320     }
321 
322     gtk_window_set_title(GTK_WINDOW(p->control), (gchar *) ("Chorus"));
323     gtk_container_add(GTK_CONTAINER(p->control), parmTable);
324 
325     gtk_widget_show_all(p->control);
326 }
327 
328 void
chorus_filter(struct effect * p,struct data_block * db)329 chorus_filter(struct effect *p, struct data_block *db)
330 {
331     struct chorus_params *cp;
332     int             count;
333     DSP_SAMPLE     *s;
334     int             dly = 0;
335     float           AngInc,
336                     Ang;
337     DSP_SAMPLE      tmp,
338                     tot,
339                     rgn;
340     int		    currchannel = 0;
341 
342     cp = (struct chorus_params *) p->params;
343 
344     s = db->data;
345     count = db->len;
346 
347 //#define MaxDly ((int)cp->depth * 8)
348 #define MaxDly (cp->depth * 8)
349     AngInc = cp->speed / 1000.0f;
350     Ang = cp->ang;
351 
352     /*
353      * process the samples
354      */
355     while (count) {
356 	tmp = *s;
357 	tmp *= cp->dry;
358 	tmp /= 256;
359 	switch (cp->mode) {
360 	case 0:		/* chorus */
361 	    dly = MaxDly * (1024 + sinLookUp[(int) cp->ang]);
362 	    break;
363 	case 1:		/* flange */
364 	    dly = 16 * MaxDly * (1024 + sinLookUp[(int) Ang] / 16);
365 	    break;
366 	};
367 	dly /= 2048;
368 	Ang += AngInc;
369 	if (Ang >= 359.0f)
370 	    Ang = 0.0f;
371 	if (dly < 0)
372 	    dly = 0;
373 
374 	tot = backbuff_get(cp->memory[currchannel], (unsigned int) dly);
375 	tot *= cp->wet;
376 	tot /= 256;
377 	tot += tmp;
378 #ifdef CLIP_EVERYWHERE
379 	tot =
380 	    (tot < -MAX_SAMPLE) ? -MAX_SAMPLE : (tot >
381 						 MAX_SAMPLE) ? MAX_SAMPLE :
382 	    tot;
383 #endif
384 	rgn =
385 	    (backbuff_get(cp->memory[currchannel], (unsigned int) dly) *
386 	     cp->regen) / 256 + *s;
387 #ifdef CLIP_EVERYWHERE
388 	rgn =
389 	    (rgn < -MAX_SAMPLE) ? -MAX_SAMPLE : (rgn >
390 						 MAX_SAMPLE) ? MAX_SAMPLE :
391 	    rgn;
392 #endif
393 	backbuff_add(cp->memory[currchannel], rgn);
394 	*s = tot;
395 
396 	if (nchannels > 1)
397 	    currchannel = !currchannel;
398 	s++;
399 	count--;
400     }
401 
402     cp->ang = Ang;
403 
404 #undef MaxDly
405 }
406 
407 void
chorus_done(struct effect * p)408 chorus_done(struct effect *p)
409 {
410     struct chorus_params *cp;
411     int             i;
412 
413     cp = (struct chorus_params *) p->params;
414 
415     for (i = 0; i < MAX_CHANNELS; i++) {
416 	backbuff_done(cp->memory[i]);
417 	free(cp->memory[i]);
418     }
419     free(p->params);
420     gtk_widget_destroy(p->control);
421     free(p);
422     p = NULL;
423 }
424 
425 void
initSinLookUp(void)426 initSinLookUp(void)
427 {
428     int             i;
429     float           arg,
430                     val;
431 
432     if (isSinLookUp)
433 	return;
434     printf("\nInitializing sin lookup table");
435     for (i = 0; i < 360; i++) {
436 	arg = ((float) i * M_PI) / 180.0f;
437 	val = sin(arg);
438 	sinLookUp[i] = (int) (val * 1024);
439     }
440     isSinLookUp = 1;
441 }
442 
443 void
chorus_save(struct effect * p,int fd)444 chorus_save(struct effect *p, int fd)
445 {
446     struct chorus_params *cp;
447 
448     cp = (struct chorus_params *) p->params;
449 
450     write(fd, &cp->wet, sizeof(cp->wet));
451     write(fd, &cp->dry, sizeof(cp->dry));
452     write(fd, &cp->depth, sizeof(cp->depth));
453     write(fd, &cp->mode, sizeof(cp->mode));
454     write(fd, &cp->speed, sizeof(cp->speed));
455     write(fd, &cp->regen, sizeof(cp->regen));
456 }
457 
458 void
chorus_load(struct effect * p,int fd)459 chorus_load(struct effect *p, int fd)
460 {
461     struct chorus_params *cp;
462 
463     cp = (struct chorus_params *) p->params;
464 
465     read(fd, &cp->wet, sizeof(cp->wet));
466     read(fd, &cp->dry, sizeof(cp->dry));
467     read(fd, &cp->depth, sizeof(cp->depth));
468     read(fd, &cp->mode, sizeof(cp->mode));
469     read(fd, &cp->speed, sizeof(cp->speed));
470     read(fd, &cp->regen, sizeof(cp->regen));
471     if (p->toggle == 0) {
472 	p->proc_filter = passthru;
473     } else {
474 	p->proc_filter = chorus_filter;
475     }
476 }
477 
478 void
chorus_create(struct effect * p)479 chorus_create(struct effect *p)
480 {
481     struct chorus_params *cp;
482     int             i;
483 
484     p->params =
485 	(struct chorus_params *) malloc(sizeof(struct chorus_params));
486     p->proc_init = chorus_init;
487     p->proc_filter = passthru;
488     p->toggle = 0;
489     p->id = CHORUS;
490     p->proc_done = chorus_done;
491     p->proc_save = chorus_save;
492     p->proc_load = chorus_load;
493     cp = (struct chorus_params *) p->params;
494 
495     for (i = 0; i < MAX_CHANNELS; i++) {
496 	cp->memory[i] = (struct backBuf *) malloc(sizeof(struct backBuf));
497 	backbuff_init(cp->memory[i], sample_rate);	/* 1 second memory */
498     }
499     cp->ang = 0.0f;
500     cp->depth = 50;
501     cp->speed = 5;
502     cp->mode = 0;
503     cp->wet = 250;
504     cp->dry = 200;
505     cp->regen = 0;
506 }
507