rework canvas zoom, add 3 plugins from 7.2, tweak cwdw boundry, vdevicex11 dupl close...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / chorus / chorus.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2017-2019 Adam Williams <broadcast at earthling dot net>
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  */
21
22 #include "chorus.h"
23 #include "clip.h"
24 #include "confirmsave.h"
25 #include "bchash.h"
26 #include "bcsignals.h"
27 #include "errorbox.h"
28 #include "filexml.h"
29 #include "language.h"
30 #include "samples.h"
31 #include "theme.h"
32 #include "transportque.inc"
33 #include "units.h"
34
35 #include "vframe.h"
36
37 #include <math.h>
38 #include <string.h>
39 #include <time.h>
40 #include <unistd.h>
41
42
43 // min rate for the GUI
44 #define MIN_RATE 0.0
45 // min rate to avoid division by zero
46 #define MIN_RATE2 0.10
47 #define MAX_RATE 10.0
48 #define MIN_OFFSET 0.0
49 #define MAX_OFFSET 100.0
50 #define MIN_DEPTH 0.0
51 #define MAX_DEPTH 100.0
52 #define MIN_VOICES 1
53 #define MAX_VOICES 64
54
55
56
57 PluginClient* new_plugin(PluginServer *server)
58 {
59         return new Chorus(server);
60 }
61
62
63
64 Chorus::Chorus(PluginServer *server)
65  : PluginAClient(server)
66 {
67         srand(time(0));
68         need_reconfigure = 1;
69     dsp_in = 0;
70     dsp_in_allocated = 0;
71     voices = 0;
72     last_position = -1;
73     flanging_table = 0;
74     table_size = 0;
75     history_buffer = 0;
76     history_size = 0;
77 }
78
79 Chorus::~Chorus()
80 {
81     if(dsp_in)
82     {
83                 for(int i = 0; i < PluginClient::total_in_buffers; i++)
84                 {
85                         delete [] dsp_in[i];
86         }
87         delete [] dsp_in;
88     }
89     
90     if(history_buffer)
91     {
92         for(int i = 0; i < PluginClient::total_in_buffers; i++)
93                 {
94                         delete [] history_buffer[i];
95         }
96         delete [] history_buffer;
97     }
98     
99     delete [] voices;
100     delete [] flanging_table;
101 }
102
103 const char* Chorus::plugin_title() { return N_("Chorus"); }
104 int Chorus::is_realtime() { return 1; }
105 int Chorus::is_multichannel() { return 1; }
106 int Chorus::is_synthesis() { return 1; }
107
108
109 int Chorus::process_buffer(int64_t size, 
110         Samples **buffer, 
111         int64_t start_position,
112         int sample_rate)
113 {
114     need_reconfigure |= load_configuration();
115 // printf("Chorus::process_buffer %d start_position=%ld size=%ld need_reconfigure=%d buffer_offset=%d\n",
116 // __LINE__,
117 // start_position, 
118 // size,
119 // need_reconfigure,
120 // buffer[0]->get_offset());
121
122
123     if(!dsp_in)
124     {
125         dsp_in = new double*[PluginClient::total_in_buffers];
126                 for(int i = 0; i < PluginClient::total_in_buffers; i++)
127                 {
128                         dsp_in[i] = 0;
129         }
130     }
131
132 // reset after seeking & configuring
133     if(last_position != start_position || need_reconfigure)
134     {
135         need_reconfigure = 0;
136
137         if(flanging_table)
138         {
139             delete [] flanging_table;
140         }
141
142 // flanging waveform is a whole number of samples that repeats
143         if(config.rate < MIN_RATE2)
144         {
145             table_size = 256;
146         }
147         else
148         {
149             table_size = (int)((double)sample_rate / config.rate);
150             if(table_size % 2)
151             {
152                 table_size++;
153             }
154         }
155
156
157 // printf("Chorus::process_buffer %d table_size=%d\n", 
158 // __LINE__, 
159 // table_size);
160
161         flanging_table = new flange_sample_t[table_size];
162         double depth_samples = config.depth * 
163             sample_rate / 1000;
164         double half_depth = depth_samples / 2;
165         int half_table = table_size / 2;
166         int quarter_table = table_size / 4;
167 // slow down over time to read from history buffer
168 //        double ratio = (double)depth_samples /
169 //            half;
170          double coef = (double)half_depth /
171              pow(quarter_table, 2);
172
173 // printf("Chorus::process_buffer %d %f %f\n", 
174 // __LINE__, 
175 // depth_samples,
176 // sample_rate / 2 - depth_samples);
177         for(int i = 0; i <= quarter_table; i++)
178         {
179 //            double input_sample = -i * ratio;
180             double input_sample = -(coef * pow(i, 2));
181 // printf("Chorus::process_buffer %d i=%d input_sample=%f\n", 
182 // __LINE__, 
183 // i, 
184 // input_sample);
185             flanging_table[i].input_sample = input_sample;
186         }
187
188         for(int i = 0; i <= quarter_table; i++)
189         {
190             double input_sample = -depth_samples + 
191                 (coef * pow(quarter_table - i, 2));
192 // printf("Chorus::process_buffer %d i=%d input_sample=%f\n", 
193 // __LINE__, 
194 // quarter_table + i, 
195 // input_sample);
196             flanging_table[quarter_table + i].input_sample = input_sample;
197         }
198
199 // rounding error may drop quarter_table * 2
200         flanging_table[half_table].input_sample = -depth_samples;
201
202         for(int i = 1; i < half_table; i++)
203         {
204             flanging_table[half_table + i].input_sample = 
205                 flanging_table[half_table - i].input_sample;
206 // printf("Chorus::process_buffer %d i=%d input_sample=%f\n", 
207 // __LINE__, 
208 // i, 
209 // input_sample);
210         }
211
212
213 // dump the table
214 // for(int i = 0; i < table_size; i++)
215 // {
216 // printf("Chorus::process_buffer %d i=%d input_sample=%f\n", 
217 // __LINE__, 
218 // i, 
219 // flanging_table[i].input_sample);
220 // }
221
222         if(!history_buffer)
223         {
224             history_buffer = new double*[PluginClient::total_in_buffers];
225             for(int i = 0; i < PluginClient::total_in_buffers; i++)
226             {
227                 history_buffer[i] = 0;
228             }
229             history_size = 0;
230         }
231
232 // compute the phase position from the keyframe position & the phase offset
233                 int64_t prev_position = edl_to_local(
234                         get_prev_keyframe(
235                                 get_source_position())->position);
236
237                 if(prev_position == 0)
238                 {
239                         prev_position = get_source_start();
240                 }
241
242         if(voices)
243         {
244             delete [] voices;
245             voices = 0;
246         }
247         
248         if(!voices)
249         {
250             voices = new Voice[total_voices()];
251         }
252         
253         for(int i = 0; i < total_voices(); i++)
254         {
255             Voice *voice = &voices[i];
256             voice->src_channel = i / config.voices;
257             voice->dst_channel = i % PluginClient::total_in_buffers;
258
259 // randomize the starting phase
260             voice->table_offset = (int64_t)(start_position - 
261                 prev_position + 
262                 i * (table_size / 2) / total_voices()) % (table_size / 2);
263 //                (rand() % (table_size / 2))) % (table_size / 2);
264 // printf("Chorus::process_buffer %d i=%d src=%d dst=%d input_sample=%f\n",
265 // __LINE__,
266 // i,
267 // voice->src_channel,
268 // voice->dst_channel,
269 // flanging_table[voice->table_offset].input_sample);
270         }
271     }
272
273     int starting_offset = (int)(config.offset * sample_rate / 1000);
274     reallocate_dsp(size);
275 //    reallocate_history(starting_offset + depth_offset + 1);
276 // always use the maximum history, in case of keyframes
277     reallocate_history((MAX_OFFSET + MAX_DEPTH) * sample_rate / 1000 + 1);
278
279 // read the input
280         for(int i = 0; i < PluginClient::total_in_buffers; i++)
281         {
282                 read_samples(buffer[i],
283                         i,
284                         sample_rate,
285                         start_position,
286                         size);
287         }
288
289
290
291 // paint the voices
292     double wetness = DB::fromdb(config.wetness);
293     if(config.wetness <= INFINITYGAIN)
294     {
295         wetness = 0;
296     }
297
298 // input signal
299     for(int i = 0; i < PluginClient::total_in_buffers; i++)
300     {
301         double *output = dsp_in[i];
302         double *input = buffer[i]->get_data();
303         for(int j = 0; j < size; j++)
304         {
305             output[j] = input[j] * wetness;
306         }
307     }
308
309 // delayed signals
310     for(int i = 0; i < total_voices(); i++)
311     {
312         Voice *voice = &voices[i];
313         double *output = dsp_in[voice->dst_channel];
314         double *input = buffer[voice->src_channel]->get_data();
315         double *history = history_buffer[voice->src_channel];
316
317 // printf("Chorus::process_buffer %d table_offset=%d table=%f\n", 
318 // __LINE__, 
319 // voice->table_offset, 
320 // flanging_table[table_size / 2].input_sample);
321
322 //static int debug = 1;
323         int table_offset = voice->table_offset;
324         for(int j = 0; j < size; j++)
325         {
326             flange_sample_t *table = &flanging_table[table_offset];
327             double input_sample = j - starting_offset + table->input_sample;
328
329 // values to interpolate
330             double sample1;
331             double sample2;
332             int input_sample1 = (int)(input_sample);
333             int input_sample2 = (int)(input_sample + 1);
334             double fraction1 = (double)((int)(input_sample + 1)) - input_sample;
335             double fraction2 = 1.0 - fraction1;
336             if(input_sample1 < 0)
337             {
338                 sample1 = history[history_size + input_sample1];
339             }
340             else
341             {
342                 sample1 = input[input_sample1];
343             }
344
345             if(input_sample2 < 0)
346             {
347                 sample2 = history[history_size + input_sample2];
348             }
349             else
350             {
351                 sample2 = input[input_sample2];
352             }
353             output[j] += sample1 * fraction1 + sample2 * fraction2;
354 // if(start_position + j > 49600 && start_position + j < 49700)
355 // printf("%ld %d input_sample=%f sample1=%f sample2=%f output=%f\n", 
356 // start_position + j, table_offset, input_sample, sample1, sample2, output[j]);
357
358             if(config.rate >= MIN_RATE2)
359             {
360                 table_offset++;
361                 table_offset %= table_size;
362             }
363         }
364 //debug = 0;
365         voice->table_offset = table_offset;
366     }
367
368
369     for(int i = 0; i < PluginClient::total_in_buffers; i++)
370         {
371 // history is bigger than input buffer.  Copy entire input buffer.
372         if(history_size > size)
373         {
374             memcpy(history_buffer[i], 
375                 history_buffer[i] + size,
376                 (history_size - size) * sizeof(double));
377             memcpy(history_buffer[i] + (history_size - size),
378                 buffer[i]->get_data(),
379                 size * sizeof(double));
380         }
381         else
382         {
383 // input is bigger than history buffer.  Copy only history size
384            memcpy(history_buffer[i],
385                 buffer[i]->get_data() + size - history_size,
386                 history_size * sizeof(double));
387         }
388     }
389 //printf("Chorus::process_buffer %d history_size=%ld\n", __LINE__, history_size);
390
391 // copy the DSP buffer to the output
392     for(int i = 0; i < PluginClient::total_in_buffers; i++)
393     {
394         memcpy(buffer[i]->get_data(), dsp_in[i], size * sizeof(double));
395     }
396
397
398     if(get_direction() == PLAY_FORWARD)
399     {
400         last_position = start_position + size;
401     }
402     else
403     {
404         last_position = start_position - size;
405     }
406
407     
408
409     return 0;
410 }
411
412
413 int Chorus::total_voices()
414 {
415     return PluginClient::total_in_buffers * config.voices;
416 }
417
418
419 void Chorus::reallocate_dsp(int new_dsp_allocated)
420 {
421     if(new_dsp_allocated > dsp_in_allocated)
422     {
423 // copy samples already read into the new buffers
424         for(int i = 0; i < PluginClient::total_in_buffers; i++)
425                 {
426             double *old_dsp = dsp_in[i];
427             double *new_dsp = new double[new_dsp_allocated];
428             if(old_dsp)
429             {
430                 delete [] old_dsp;
431             }
432             dsp_in[i] = new_dsp;
433         }
434         dsp_in_allocated = new_dsp_allocated;
435     }
436 }
437
438 void Chorus::reallocate_history(int new_size)
439 {
440     if(new_size != history_size)
441     {
442 // copy samples already read into the new buffers
443         for(int i = 0; i < PluginClient::total_in_buffers; i++)
444                 {
445             double *old_history = 0;
446             
447             if(history_buffer)
448             {
449                 old_history = history_buffer[i];
450             }
451             double *new_history = new double[new_size];
452             bzero(new_history, sizeof(double) * new_size);
453             if(old_history)
454             {
455                 int copy_size = MIN(new_size, history_size);
456                 memcpy(new_history, 
457                     old_history + history_size - copy_size, 
458                     sizeof(double) * copy_size);
459                 delete [] old_history;
460             }
461             history_buffer[i] = new_history;
462         }
463         history_size = new_size;
464     }
465 }
466
467
468
469
470
471 NEW_WINDOW_MACRO(Chorus, ChorusWindow)
472
473
474 LOAD_CONFIGURATION_MACRO(Chorus, ChorusConfig)
475
476
477 void Chorus::save_data(KeyFrame *keyframe)
478 {
479         FileXML output;
480
481 // cause xml file to store data directly in text
482         output.set_shared_output(keyframe->xbuf);
483
484         output.tag.set_title("CHORUS");
485         output.tag.set_property("VOICES", config.voices);
486         output.tag.set_property("OFFSET", config.offset);
487         output.tag.set_property("DEPTH", config.depth);
488         output.tag.set_property("RATE", config.rate);
489         output.tag.set_property("WETNESS", config.wetness);
490         output.append_tag();
491         output.append_newline();
492
493         output.terminate_string();
494 }
495
496 void Chorus::read_data(KeyFrame *keyframe)
497 {
498         FileXML input;
499 // cause xml file to read directly from text
500         input.set_shared_input(keyframe->xbuf);
501         int result = 0;
502
503         result = input.read_tag();
504
505         if(!result)
506         {
507                 if(input.tag.title_is("CHORUS"))
508                 {
509                         config.voices = input.tag.get_property("VOICES", config.voices);
510                         config.offset = input.tag.get_property("OFFSET", config.offset);
511                         config.depth = input.tag.get_property("DEPTH", config.depth);
512                         config.rate = input.tag.get_property("RATE", config.rate);
513                         config.wetness = input.tag.get_property("WETNESS", config.wetness);
514                 }
515         }
516
517         config.boundaries();
518 }
519
520 void Chorus::update_gui()
521 {
522         if(thread)
523         {
524                 if(load_configuration())
525                 {
526                         thread->window->lock_window("Chorus::update_gui 1");
527             ((ChorusWindow*)thread->window)->update();
528                         thread->window->unlock_window();
529         }
530         }
531 }
532
533
534
535
536
537
538
539
540 Voice::Voice()
541 {
542 }
543
544
545
546 ChorusConfig::ChorusConfig()
547 {
548         voices = 1;
549         offset = 0.00;
550         depth = 10.0;
551         rate = 0.20;
552         wetness = 0;
553 }
554
555 int ChorusConfig::equivalent(ChorusConfig &that)
556 {
557         return (voices == that.voices) &&
558                 EQUIV(offset, that.offset) &&
559                 EQUIV(depth, that.depth) &&
560                 EQUIV(rate, that.rate) &&
561                 EQUIV(wetness, that.wetness);
562 }
563
564 void ChorusConfig::copy_from(ChorusConfig &that)
565 {
566         voices = that.voices;
567         offset = that.offset;
568         depth = that.depth;
569         rate = that.rate;
570         wetness = that.wetness;
571 }
572
573 void ChorusConfig::interpolate(ChorusConfig &prev, 
574         ChorusConfig &next, 
575         int64_t prev_frame, 
576         int64_t next_frame, 
577         int64_t current_frame)
578 {
579         copy_from(prev);
580 }
581
582 void ChorusConfig::boundaries()
583 {
584         CLAMP(voices, MIN_VOICES, MAX_VOICES);
585         CLAMP(offset, MIN_OFFSET, MAX_OFFSET);
586         CLAMP(depth, MIN_DEPTH, MAX_DEPTH);
587         CLAMP(rate, MIN_RATE, MAX_RATE);
588         CLAMP(wetness, INFINITYGAIN, 0.0);
589 }
590
591
592
593
594
595
596
597
598
599
600
601 #define WINDOW_W xS(400)
602 #define WINDOW_H yS(165)
603
604 ChorusWindow::ChorusWindow(Chorus *plugin)
605  : PluginClientWindow(plugin, 
606         WINDOW_W, 
607         WINDOW_H, 
608         WINDOW_W, 
609         WINDOW_H, 
610         0)
611
612         this->plugin = plugin; 
613 }
614
615 ChorusWindow::~ChorusWindow()
616 {
617     delete voices;
618     delete offset;
619     delete depth;
620     delete rate;
621     delete wetness;
622 }
623
624 void ChorusWindow::create_objects()
625 {
626         int margin = plugin->get_theme()->widget_border + xS(4);
627     int x1 = margin;
628         int x2 = xS(200), y = margin -xS(4);
629     int x3 = x2 + BC_Pot::calculate_w() + margin;
630     int x4 = x3 + BC_Pot::calculate_w() + margin;
631     int text_w = get_w() - margin - x4;
632     int height = BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) + margin -xS(4);
633
634
635     voices = new PluginParam(plugin,
636         this,
637         x1, 
638         x2,
639         x4,
640         y, 
641         text_w,
642         &plugin->config.voices,  // output_i
643         0, // output_f
644         0, // output_q
645         "Voices per channel:",
646         MIN_VOICES, // min
647         MAX_VOICES); // max
648     voices->initialize();
649     y += height;
650
651     offset = new PluginParam(plugin,
652         this,
653         x1, 
654         x3,
655         x4,
656         y, 
657         text_w,
658         0,  // output_i
659         &plugin->config.offset, // output_f
660         0, // output_q
661         "Phase offset (ms):",
662         MIN_OFFSET, // min
663         MAX_OFFSET); // max
664     offset->set_precision(3);
665     offset->initialize();
666     y += height;
667
668
669     depth = new PluginParam(plugin,
670         this,
671         x1, 
672         x2,
673         x4,
674         y, 
675         text_w,
676         0,  // output_i
677         &plugin->config.depth, // output_f
678         0, // output_q
679         "Depth (ms):",
680         MIN_DEPTH, // min
681         MAX_DEPTH); // max
682     depth->set_precision(3);
683     depth->initialize();
684     y += height;
685
686
687
688     rate = new PluginParam(plugin,
689         this,
690         x1, 
691         x3,
692         x4,
693         y, 
694         text_w,
695         0,  // output_i
696         &plugin->config.rate, // output_f
697         0, // output_q
698         "Rate (Hz):",
699         MIN_RATE, // min
700         MAX_RATE); // max
701     rate->set_precision(3);
702     rate->initialize();
703     y += height;
704
705
706
707     wetness = new PluginParam(plugin,
708         this,
709         x1, 
710         x2,
711         x4,
712         y, 
713         text_w,
714         0,  // output_i
715         &plugin->config.wetness, // output_f
716         0, // output_q
717         "Wetness (db):",
718         INFINITYGAIN, // min
719         0); // max
720     wetness->initialize();
721     y += height;
722
723         show_window();
724 }
725
726 void ChorusWindow::update()
727 {
728     voices->update(0, 0);
729     offset->update(0, 0);
730     depth->update(0, 0);
731     rate->update(0, 0);
732     wetness->update(0, 0);
733 }
734
735 void ChorusWindow::param_updated()
736 {
737 }
738
739
740
741
742
743
744
745
746
747
748
749
750