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