vicon drawing segv fix, beeper consolidation, render_effect resize wdw fix, valgrind...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / compressormulti / comprmulti.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2008-2019 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "bcdisplayinfo.h"
21 #include "bcsignals.h"
22 #include "clip.h"
23 #include "comprmulti.h"
24 #include "comprmultigui.h"
25 #include "bchash.h"
26 #include "eqcanvas.h"
27 #include "filexml.h"
28 #include "language.h"
29 #include "samples.h"
30 #include "transportque.inc"
31 #include "units.h"
32 #include "vframe.h"
33
34 #include <math.h>
35 #include <string.h>
36
37 REGISTER_PLUGIN(ComprMultiEffect)
38
39 // More potential compressor algorithms:
40 // Use single reaction time parameter.  Negative reaction time uses
41 // readahead.  Positive reaction time uses slope.
42
43 // Smooth input stage if readahead.
44 // Determine slope from current smoothed sample to every sample in readahead area.
45 // Once highest slope is found, count of number of samples remaining until it is
46 // reached.  Only search after this count for the next highest slope.
47 // Use highest slope to determine smoothed value.
48
49 // Smooth input stage if not readahead.
50 // For every sample, calculate slope needed to reach current sample from
51 // current smoothed value in the reaction time.  If higher than current slope,
52 // make it the current slope and count number of samples remaining until it is
53 // reached.  If this count is met and no higher slopes are found, base slope
54 // on current sample when count is met.
55
56 // Gain stage.
57 // For every sample, calculate gain from smoothed input value.
58
59 ComprMultiConfig::ComprMultiConfig()
60  : CompressorConfigBase(TOTAL_BANDS)
61 {
62         q = 1.0;
63         window_size = 4096;
64 }
65
66 void ComprMultiConfig::copy_from(ComprMultiConfig &that)
67 {
68         CompressorConfigBase::copy_from(that);
69
70         window_size = that.window_size;
71         q = that.q;
72 }
73
74 int ComprMultiConfig::equivalent(ComprMultiConfig &that)
75 {
76         if( !CompressorConfigBase::equivalent(that) )
77                 return 0;
78
79         if( !EQUIV(q, that.q) ||
80                 window_size != that.window_size ) {
81                 return 0;
82         }
83
84         return 1;
85 }
86
87 void ComprMultiConfig::interpolate(ComprMultiConfig &prev, ComprMultiConfig &next,
88         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
89 {
90         copy_from(prev);
91 }
92
93
94 ComprMultiEffect::ComprMultiEffect(PluginServer *server)
95  : PluginAClient(server)
96 {
97         reset();
98         for( int i = 0; i < TOTAL_BANDS; i++ )
99                 band_states[i] = new BandState(this, i);
100 }
101
102 ComprMultiEffect::~ComprMultiEffect()
103 {
104         delete_dsp();
105         for( int i = 0; i < TOTAL_BANDS; i++ ) {
106                 delete band_states[i];
107         }
108 }
109
110 void ComprMultiEffect::delete_dsp()
111 {
112 #ifndef DRAW_AFTER_BANDPASS
113         if( input_buffer ) {
114                 for( int i = 0; i < PluginClient::total_in_buffers; i++ )
115                         delete input_buffer[i];
116                 delete [] input_buffer;
117         }
118         input_buffer = 0;
119         input_size = 0;
120         new_input_size = 0;
121 #endif
122         if( fft ) {
123                 for( int i = 0; i < PluginClient::total_in_buffers; i++ )
124                         delete fft[i];
125                 delete [] fft;
126         }
127
128         for( int i = 0; i < TOTAL_BANDS; i++ ) {
129                 band_states[i]->delete_dsp();
130         }
131
132         filtered_size = 0;
133         fft = 0;
134 }
135
136
137 void ComprMultiEffect::reset()
138 {
139         for( int i = 0; i < TOTAL_BANDS; i++ )
140                 band_states[i] = 0;
141
142 #ifndef DRAW_AFTER_BANDPASS
143         input_buffer = 0;
144         input_size = 0;
145         new_input_size = 0;
146 #endif
147         input_start = 0;
148         filtered_size = 0;
149         last_position = 0;
150         fft = 0;
151         need_reconfigure = 1;
152         config.current_band = 0;
153 }
154
155 const char* ComprMultiEffect::plugin_title() { return N_("Compressor Multi"); }
156 int ComprMultiEffect::is_realtime() { return 1; }
157 int ComprMultiEffect::is_multichannel() { return 1; }
158
159
160 void ComprMultiEffect::read_data(KeyFrame *keyframe)
161 {
162         FileXML input;
163         input.set_shared_input(keyframe->xbuf);
164
165         int result = 0;
166         for( int i = 0; i < TOTAL_BANDS; i++ )
167                 config.bands[i].levels.remove_all();
168
169         while( !(result = input.read_tag()) ) {
170                 if( input.tag.title_is("COMPRESSOR_MULTI") ) {
171                         config.trigger = input.tag.get_property("TRIGGER", config.trigger);
172                         config.smoothing_only = input.tag.get_property("SMOOTHING_ONLY", config.smoothing_only);
173                         config.input = input.tag.get_property("INPUT", config.input);
174                         config.q = input.tag.get_property("Q", config.q);
175                         config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
176                 }
177                 else if( input.tag.title_is("COMPRESSORBAND") ) {
178                         int number = input.tag.get_property("NUMBER", 0);
179                         config.bands[number].read_data(&input, 1);
180                 }
181         }
182
183         config.boundaries();
184 }
185
186 void ComprMultiEffect::save_data(KeyFrame *keyframe)
187 {
188         FileXML output;
189         output.set_shared_output(keyframe->xbuf);
190
191         output.tag.set_title("COMPRESSOR_MULTI");
192         output.tag.set_property("TRIGGER", config.trigger);
193         output.tag.set_property("SMOOTHING_ONLY", config.smoothing_only);
194         output.tag.set_property("INPUT", config.input);
195         output.tag.set_property("Q", config.q);
196         output.tag.set_property("WINDOW_SIZE", config.window_size);
197         output.append_tag();
198         output.append_newline();
199
200         for( int band = 0; band < TOTAL_BANDS; band++ ) {
201                 BandConfig *band_config = &config.bands[band];
202                 band_config->save_data(&output, band, 1);
203         }
204
205
206         output.tag.set_title("/COMPRESSOR_MULTI");
207         output.append_tag();
208         output.append_newline();
209         output.terminate_string();
210 }
211
212 void ComprMultiEffect::dump_frames()
213 {
214         printf("tracking %f, direction %d\n", get_tracking_position(), get_tracking_direction());
215         CompressorClientFrame *cfp = (CompressorClientFrame *)client_frames.first;
216         for( int n=0; cfp; cfp=(CompressorClientFrame *)cfp->next,++n ) {
217                 switch( cfp->type ) {
218                 case GAIN_COMPRESSORFRAME: {
219                         CompressorGainFrame *gfp = (CompressorGainFrame *)cfp;
220                         printf("%3d: band %d, gain pos=%f, gain=%f, level=%f\n", n, cfp->band,
221                                 gfp->position, gfp->gain, gfp->level);
222                         break; }
223                 case FREQ_COMPRESSORFRAME: {
224                         CompressorFreqFrame *ffp = (CompressorFreqFrame *)cfp;
225                         printf("%3d: band %d, freq pos=%f, max=%f/%f, size=%d\n", n, ffp->band,
226                                 ffp->position, ffp->freq_max, ffp->time_max, ffp->data_size);
227                         break; }
228                 }
229         }
230 }
231
232 void ComprMultiEffect::update_gui()
233 {
234 //      dump_frames();
235         if( !thread ) return;
236         ComprMultiWindow *window = (ComprMultiWindow *)thread->window;
237         if( !window ) return;
238 // user can't change levels when loading configuration
239         window->lock_window("ComprMultiEffect::update_gui 1");
240         int reconfigured = 0;
241 // Can't update points if the user is editing
242         if( window->canvas->is_dragging() )
243                 reconfigured = load_configuration();
244 //printf("ComprMultiEffect::update_gui %d %d %d\n", __LINE__, reconfigured, total_frames);
245         if( reconfigured )
246                 window->update();
247         if( pending_gui_frame() )
248                 window->update_eqcanvas();
249         window->unlock_window();
250 }
251
252
253 void ComprMultiEffect::render_stop()
254 {
255         if( !thread ) return;
256         ComprMultiWindow *window = (ComprMultiWindow*)thread->window;
257         if( !window ) return;
258         window->lock_window("ComprMultiEffect::render_stop");
259         window->in->reset();
260         window->gain_change->update(1, 0);
261         delete window->gain_frame;  window->gain_frame = 0;
262         delete window->freq_frame;  window->freq_frame = 0;
263         window->unlock_window();
264 }
265
266
267 LOAD_CONFIGURATION_MACRO(ComprMultiEffect, ComprMultiConfig)
268 NEW_WINDOW_MACRO(ComprMultiEffect, ComprMultiWindow)
269
270
271 int ComprMultiEffect::process_buffer(int64_t size, Samples **buffer,
272                 int64_t start_position, int sample_rate)
273 {
274         start_pos = (double)start_position / sample_rate;
275         dir = get_direction() == PLAY_REVERSE ? -1 : 1;
276         need_reconfigure |= load_configuration();
277         int channels = PluginClient::total_in_buffers;
278         if( need_reconfigure ) {
279                 need_reconfigure = 0;
280 //              min_x = DB::fromdb(config.min_db);  max_x = 1.0;
281 //              min_y = DB::fromdb(config.min_db);  max_y = 1.0;
282
283                 if( fft && fft[0]->window_size != config.window_size ) {
284                         for( int i = 0; i < channels; i++ )
285                                 delete fft[i];
286                         delete [] fft;
287                         fft = 0;
288                 }
289
290                 if( !fft ) {
291                         fft = new ComprMultiFFT*[channels];
292                         for( int i = 0; i < channels; i++ ) {
293                                 fft[i] = new ComprMultiFFT(this, i);
294                                 fft[i]->initialize(config.window_size, TOTAL_BANDS);
295                         }
296                 }
297
298                 for( int i = 0; i < TOTAL_BANDS; i++ )
299                         band_states[i]->reconfigure();
300         }
301
302 // reset after seeking
303         if( last_position != start_position ) {
304                 if( fft ) {
305                         for( int i = 0; i < channels; i++ )
306                                 if( fft[i] ) fft[i]->delete_fft();
307                 }
308
309 #ifndef DRAW_AFTER_BANDPASS
310                 input_size = 0;
311 #endif
312                 filtered_size = 0;
313                 input_start = start_position;
314                 for( int band = 0; band < TOTAL_BANDS; band++ ) {
315                         BandState *band_state = band_states[band];
316                         if( band_state->engine )
317                                 band_state->engine->reset();
318                 }
319         }
320
321 // process frequency domain for all bands simultaneously
322 // read enough samples ahead to process all the bands
323         int new_filtered_size = 0;
324         for( int band = 0; band < TOTAL_BANDS; band++ ) {
325                 BandState *band_state = band_states[band];
326                 if( !band_state->engine )
327                         band_state->engine = new CompressorEngine(&config, band);
328                 int attack_samples, release_samples, preview_samples;
329                 band_state->engine->calculate_ranges(
330                         &attack_samples, &release_samples, &preview_samples,
331                         sample_rate);
332
333                 if( preview_samples > new_filtered_size )
334                         new_filtered_size = preview_samples;
335         }
336         new_filtered_size += size;
337         for( int band = 0; band < TOTAL_BANDS; band++ )
338                 band_states[band]->allocate_filtered(new_filtered_size);
339
340 // Append data to the buffers to fill the readahead area.
341         int remain = new_filtered_size - filtered_size;
342
343         if( remain > 0 ) {
344 // printf("ComprMultiEffect::process_buffer %d filtered_size=%ld remain=%d\n",
345 // __LINE__, filtered_size, remain);
346                 for( int channel = 0; channel < channels; channel++ ) {
347 #ifndef DRAW_AFTER_BANDPASS
348                         new_input_size = input_size;
349 #endif
350 // create an array of filtered buffers for the output
351                         Samples *filtered_arg[TOTAL_BANDS];
352                         for( int band = 0; band < TOTAL_BANDS; band++ ) {
353                                 new_spectrogram_frames[band] = 0;
354                                 filtered_arg[band] = band_states[band]->filtered_buffer[channel];
355 // temporarily set the output to the end to append data
356                                 filtered_arg[band]->set_offset(filtered_size);
357                         }
358
359 // starting position of the input reads
360                         int64_t start = input_start + dir * filtered_size;
361 // printf("ComprMultiEffect::process_buffer %d start=%ld remain=%d\n", __LINE__, start, remain);
362                         fft[channel]->process_buffer(start, remain, filtered_arg, get_direction());
363
364                         for( int band = 0; band < TOTAL_BANDS; band++ ) {
365                                 filtered_arg[band]->set_offset(0);
366                         }
367 //printf("ComprMultiEffect::process_buffer %d new_input_size=%ld\n", __LINE__, new_input_size);
368                 }
369         }
370
371 #ifndef DRAW_AFTER_BANDPASS
372         input_size = new_input_size;
373 #endif
374         filtered_size = new_filtered_size;
375
376 // process time domain for each band separately
377         for( int band = 0; band < TOTAL_BANDS; band++ ) {
378                 BandState *band_state = band_states[band];
379                 CompressorEngine *engine = band_state->engine;
380
381                 engine->process(band_states[band]->filtered_buffer,
382                         band_states[band]->filtered_buffer,
383                         size, sample_rate, channels, start_position);
384
385                 for( int i = 0; i < engine->gui_gains.size(); i++ ) {
386                         CompressorGainFrame *frame = new CompressorGainFrame();
387                         frame->position = start_pos + dir*engine->gui_offsets[i];
388                         frame->gain = engine->gui_gains.get(i);
389                         frame->level = engine->gui_levels.get(i);
390                         frame->band = band;
391                         add_gui_frame(frame);
392                 }
393         }
394
395 // Add together filtered buffers + unfiltered buffer.
396 // Apply the solo here.
397         int have_solo = 0;
398         for( int band = 0; band < TOTAL_BANDS; band++ ) {
399                 if( config.bands[band].solo ) {
400                         have_solo = 1;
401                         break;
402                 }
403         }
404
405         for( int channel = 0; channel < channels; channel++ ) {
406                 double *dst = buffer[channel]->get_data();
407                 bzero(dst, size * sizeof(double));
408
409                 for( int band = 0; band < TOTAL_BANDS; band++ ) {
410                         if( !have_solo || config.bands[band].solo ) {
411                                 double *src = band_states[band]->filtered_buffer[channel]->get_data();
412                                 for( int i = 0; i < size; i++ ) {
413                                         dst[i] += src[i];
414                                 }
415                         }
416                 }
417         }
418
419 // shift input buffers
420         for( int band = 0; band < TOTAL_BANDS; band++ ) {
421
422                 for( int i = 0; i < channels; i++ ) {
423                         memcpy(band_states[band]->filtered_buffer[i]->get_data(),
424                                 band_states[band]->filtered_buffer[i]->get_data() + size,
425                                 (filtered_size - size) * sizeof(double));
426
427                 }
428         }
429
430 #ifndef DRAW_AFTER_BANDPASS
431         for( int i = 0; i < channels; i++ ) {
432                 memcpy(input_buffer[i]->get_data(),
433                         input_buffer[i]->get_data() + size,
434                         (input_size - size) * sizeof(double));
435         }
436         input_size -= size;
437 #endif
438
439 // update the counters
440         filtered_size -= size;
441         input_start += dir * size;
442         last_position = start_position + dir * size;
443         return 0;
444 }
445
446 void ComprMultiEffect::allocate_input(int new_size)
447 {
448 #ifndef DRAW_AFTER_BANDPASS
449         if( !input_buffer ||
450                 new_size > input_buffer[0]->get_allocated() ) {
451                 Samples **new_input_buffer = new Samples*[get_total_buffers()];
452
453                 for( int i = 0; i < get_total_buffers(); i++ ) {
454                         new_input_buffer[i] = new Samples(new_size);
455
456                         if( input_buffer ) {
457                                 memcpy(new_input_buffer[i]->get_data(),
458                                         input_buffer[i]->get_data(),
459                                         input_buffer[i]->get_allocated() * sizeof(double));
460                                 delete input_buffer[i];
461                         }
462                 }
463
464                 if( input_buffer ) delete [] input_buffer;
465                 input_buffer = new_input_buffer;
466         }
467 #endif // !DRAW_AFTER_BANDPASS
468 }
469
470
471 void ComprMultiEffect::calculate_envelope()
472 {
473         for( int i = 0; i < TOTAL_BANDS; i++ ) {
474                 band_states[i]->calculate_envelope();
475         }
476 }
477
478
479 BandState::BandState(ComprMultiEffect *plugin, int band)
480 {
481         this->plugin = plugin;
482         this->band = band;
483         reset();
484 }
485
486 BandState::~BandState()
487 {
488         delete_dsp();
489 }
490
491 void BandState::delete_dsp()
492 {
493         delete [] envelope;
494         levels.remove_all();
495         if( filtered_buffer ) {
496                 for( int i = 0; i < plugin->total_in_buffers; i++ ) {
497                         delete filtered_buffer[i];
498                 }
499                 delete [] filtered_buffer;
500         }
501         if( engine ) {
502                 delete engine;
503         }
504         reset();
505 }
506
507 void BandState::reset()
508 {
509         engine = 0;
510         envelope = 0;
511         envelope_allocated = 0;
512         filtered_buffer = 0;
513
514         next_target = 1.0;
515         previous_target = 1.0;
516         target_samples = 1;
517         target_current_sample = -1;
518         current_value = 1.0;
519 }
520
521 void BandState::reconfigure()
522 {
523 // Calculate linear transfer from db
524         levels.remove_all();
525
526         BandConfig *config = &plugin->config.bands[band];
527         for( int i = 0; i < config->levels.total; i++ ) {
528                 levels.append();
529                 levels.values[i].x = DB::fromdb(config->levels.values[i].x);
530                 levels.values[i].y = DB::fromdb(config->levels.values[i].y);
531         }
532
533         calculate_envelope();
534 }
535
536
537 void BandState::allocate_filtered(int new_size)
538 {
539         if( !filtered_buffer ||
540                 new_size > filtered_buffer[0]->get_allocated() ) {
541                 Samples **new_filtered_buffer = new Samples*[plugin->get_total_buffers()];
542                 for( int i = 0; i < plugin->get_total_buffers(); i++ ) {
543                         new_filtered_buffer[i] = new Samples(new_size);
544
545                         if( filtered_buffer ) {
546                                 memcpy(new_filtered_buffer[i]->get_data(),
547                                         filtered_buffer[i]->get_data(),
548                                         filtered_buffer[i]->get_allocated() * sizeof(double));
549                                 delete filtered_buffer[i];
550                         }
551                 }
552
553                 if( filtered_buffer ) delete [] filtered_buffer;
554                 filtered_buffer = new_filtered_buffer;
555         }
556 }
557
558
559 void BandState::calculate_envelope()
560 {
561 // the window size changed
562         if( envelope && envelope_allocated < plugin->config.window_size / 2 ) {
563                 delete [] envelope;
564                 envelope = 0;
565         }
566
567         if( !envelope ) {
568                 envelope_allocated = plugin->config.window_size / 2;
569                 envelope = new double[envelope_allocated];
570         }
571
572 // number of slots in the edge
573         double edge = (1.0 - plugin->config.q) * TOTALFREQS / 2;
574         int max_freq = Freq::tofreq_f(TOTALFREQS - 1);
575         int nyquist = plugin->project_sample_rate / 2;
576         int freq = plugin->config.bands[band].freq;
577
578 // max frequency of all previous bands is the low
579         int low = 0;
580         for( int i=0; i<band; ++i ) {
581                 if( plugin->config.bands[i].freq > low )
582                         low = plugin->config.bands[i].freq;
583         }
584         int high = max_freq;
585 // limit the frequencies
586         if( band < TOTAL_BANDS-1 ) high = freq;
587         if( high >= max_freq ) { high = max_freq;  edge = 0; }
588 // hard edges on the lowest & highest
589         if( band == 0 && high <= 0 ) edge = 0;
590         if( low > high ) low = high;
591 // number of slots to arrive at 1/2 power
592 #ifndef LOG_CROSSOVER
593 // linear
594         double edge2 = edge / 2;
595 #else
596 // log
597         double edge2 = edge * 6 / -INFINITYGAIN;
598 #endif
599         double low_slot = Freq::fromfreq_f(low);
600         double high_slot = Freq::fromfreq_f(high);
601 // shift slots to allow crossover
602         if( band < TOTAL_BANDS-1 ) high_slot -= edge2;
603         if( band > 0 ) low_slot += edge2;
604
605         for( int i = 0; i < plugin->config.window_size / 2; i++ ) {
606                 double freq = i * nyquist / (plugin->config.window_size / 2);
607                 double slot = Freq::fromfreq_f(freq);
608 // sum of previous bands
609                 double prev_sum = 0;
610                 for( int prev_band = 0; prev_band < band; prev_band++ ) {
611                         double *prev_envelope = plugin->band_states[prev_band]->envelope;
612                         prev_sum += prev_envelope[i];
613                 }
614
615                 if( slot < high_slot )
616 // remain of previous bands
617                         envelope[i] = 1.0 - prev_sum;
618                 else if( slot < high_slot + edge ) {
619 // next crossover
620                         double remain = 1.0 - prev_sum;
621 #ifndef LOG_CROSSOVER
622 // linear
623                         envelope[i] = remain - remain * (slot - high_slot) / edge;
624 #else
625 // log TODO
626                         envelope[i] = DB::fromdb((slot - high_slot) * INFINITYGAIN / edge);
627 #endif
628
629                 }
630                 else
631                         envelope[i] = 0.0;
632         }
633 }
634
635 #if 0
636 void BandState::process_readbehind(int size,
637                 int reaction_samples, int decay_samples, int trigger)
638 {
639         if( target_current_sample < 0 )
640                 target_current_sample = reaction_samples;
641         double current_slope = (next_target - previous_target) / reaction_samples;
642         double *trigger_buffer = filtered_buffer[trigger]->get_data();
643         int channels = plugin->get_total_buffers();
644         for( int i = 0; i < size; i++ ) {
645 // Get slope required to reach current sample from smoothed sample over reaction
646 // length.
647                 double sample = 0;
648                 switch( plugin->config.input ) {
649                 case ComprMultiConfig::MAX: {
650                         double max = 0;
651                         for( int j = 0; j < channels; j++ ) {
652                                 sample = fabs(filtered_buffer[j]->get_data()[i]);
653                                 if( sample > max ) max = sample;
654                         }
655                         sample = max;
656                         break; }
657
658                 case ComprMultiConfig::TRIGGER:
659                         sample = fabs(trigger_buffer[i]);
660                         break;
661
662                 case ComprMultiConfig::SUM: {
663                         double max = 0;
664                         for( int j = 0; j < channels; j++ ) {
665                                 sample = fabs(filtered_buffer[j]->get_data()[i]);
666                                 max += sample;
667                         }
668                         sample = max;
669                         break; }
670                 }
671
672                 double new_slope = (sample - current_value) / reaction_samples;
673
674 // Slope greater than current slope
675                 if( new_slope >= current_slope &&
676                         (current_slope >= 0 ||
677                         new_slope >= 0) ) {
678                         next_target = sample;
679                         previous_target = current_value;
680                         target_current_sample = 0;
681                         target_samples = reaction_samples;
682                         current_slope = new_slope;
683                 }
684                 else
685                 if( sample > next_target && current_slope < 0 ) {
686                         next_target = sample;
687                         previous_target = current_value;
688                         target_current_sample = 0;
689                         target_samples = decay_samples;
690                         current_slope = (sample - current_value) / decay_samples;
691                 }
692 // Current smoothed sample came up without finding higher slope
693                 if( target_current_sample >= target_samples ) {
694                         next_target = sample;
695                         previous_target = current_value;
696                         target_current_sample = 0;
697                         target_samples = decay_samples;
698                         current_slope = (sample - current_value) / decay_samples;
699                 }
700
701 // Update current value and store gain
702                 current_value = (next_target * target_current_sample +
703                         previous_target * (target_samples - target_current_sample)) /
704                         target_samples;
705
706                 target_current_sample++;
707
708                 if( plugin->config.smoothing_only ) {
709                         for( int j = 0; j < channels; j++ ) {
710                                 filtered_buffer[j]->get_data()[i] = current_value;
711                         }
712                 }
713                 else
714                 if( !plugin->config.bands[band].bypass ) {
715                         double gain = plugin->config.calculate_gain(band, current_value);
716                         for( int j = 0; j < channels; j++ ) {
717                                 filtered_buffer[j]->get_data()[i] *= gain;
718                         }
719                 }
720         }
721 }
722
723 void BandState::process_readahead(int size, int preview_samples,
724                 int reaction_samples, int decay_samples, int trigger)
725 {
726         if( target_current_sample < 0 ) target_current_sample = target_samples;
727         double current_slope = (next_target - previous_target) /
728                 target_samples;
729         double *trigger_buffer = filtered_buffer[trigger]->get_data();
730         int channels = plugin->get_total_buffers();
731         for( int i = 0; i < size; i++ ) {
732 // Get slope from current sample to every sample in preview_samples.
733 // Take highest one or first one after target_samples are up.
734
735 // For optimization, calculate the first slope we really need.
736 // Assume every slope up to the end of preview_samples has been calculated and
737 // found <= to current slope.
738                 int first_slope = preview_samples - 1;
739 // Need new slope immediately
740                 if( target_current_sample >= target_samples )
741                         first_slope = 1;
742
743                 for( int j = first_slope; j < preview_samples; j++ ) {
744                         int buffer_offset = i + j;
745                         double sample = 0;
746                         switch( plugin->config.input ) {
747                         case ComprMultiConfig::MAX: {
748                                 double max = 0;
749                                 for( int k = 0; k < channels; k++ ) {
750                                         sample = fabs(filtered_buffer[k]->get_data()[buffer_offset]);
751                                         if( sample > max ) max = sample;
752                                 }
753                                 sample = max;
754                                 break; }
755
756                         case ComprMultiConfig::TRIGGER:
757                                 sample = fabs(trigger_buffer[buffer_offset]);
758                                 break;
759
760                         case ComprMultiConfig::SUM: {
761                                 double max = 0;
762                                 for( int k = 0; k < channels; k++ ) {
763                                         sample = fabs(filtered_buffer[k]->get_data()[buffer_offset]);
764                                         max += sample;
765                                 }
766                                 sample = max;
767                                 break; }
768                         }
769
770                         double new_slope = (sample - current_value) / j;
771 // Got equal or higher slope
772                         if( new_slope >= current_slope &&
773                                 (current_slope >= 0 ||
774                                 new_slope >= 0) ) {
775                                 target_current_sample = 0;
776                                 target_samples = j;
777                                 current_slope = new_slope;
778                                 next_target = sample;
779                                 previous_target = current_value;
780                         }
781                         else
782                         if( sample > next_target && current_slope < 0 ) {
783                                 target_current_sample = 0;
784                                 target_samples = decay_samples;
785                                 current_slope = (sample - current_value) /
786                                         decay_samples;
787                                 next_target = sample;
788                                 previous_target = current_value;
789                         }
790
791 // Hit end of current slope range without finding higher slope
792                         if( target_current_sample >= target_samples ) {
793                                 target_current_sample = 0;
794                                 target_samples = decay_samples;
795                                 current_slope = (sample - current_value) / decay_samples;
796                                 next_target = sample;
797                                 previous_target = current_value;
798                         }
799                 }
800
801 // Update current value and multiply gain
802                 current_value = (next_target * target_current_sample +
803                         previous_target * (target_samples - target_current_sample)) /
804                         target_samples;
805
806                 target_current_sample++;
807
808                 if( plugin->config.smoothing_only ) {
809                         for( int j = 0; j < channels; j++ ) {
810                                 filtered_buffer[j]->get_data()[i] = current_value;
811                         }
812                 }
813                 else
814                 if( !plugin->config.bands[band].bypass ) {
815                         double gain = plugin->config.calculate_gain(band, current_value);
816                         for( int j = 0; j < channels; j++ ) {
817                                 filtered_buffer[j]->get_data()[i] *= gain;
818                         }
819                 }
820         }
821 }
822 #endif
823
824 ComprMultiFFT::ComprMultiFFT(ComprMultiEffect *plugin, int channel)
825 {
826         this->plugin = plugin;
827         this->channel = channel;
828 }
829
830 ComprMultiFFT::~ComprMultiFFT()
831 {
832 }
833
834 int ComprMultiFFT::signal_process(int band)
835 {
836         int sample_rate = plugin->PluginAClient::project_sample_rate;
837         BandState *band_state = plugin->band_states[band];
838
839 // Create new spectrogram frame for updating the GUI
840         frame = 0;
841         if(
842 #ifndef DRAW_AFTER_BANDPASS
843                 band == 0 &&
844 #endif
845                 ((plugin->config.input != ComprMultiConfig::TRIGGER && channel == 0) ||
846                 channel == plugin->config.trigger) ) {
847 #ifndef DRAW_AFTER_BANDPASS
848                 int total_data = window_size / 2;
849 #else
850                 int total_data = TOTAL_BANDS * window_size / 2;
851 #endif
852
853 // store all bands in the same GUI frame
854                 frame = new CompressorFreqFrame();
855                 frame->band = band;
856                 frame->data_size = total_data;
857                 frame->data = new double[total_data];
858                 bzero(frame->data, sizeof(double) * total_data);
859                 frame->nyquist = sample_rate / 2;
860
861 //              int attack_samples, release_samples, preview_samples;
862 //              band_state->engine->calculate_ranges(&attack_samples,
863 //                       &release_samples, &preview_samples, sample_rate);
864
865 // FFT advances 1/2 a window for each spectrogram frame
866                 int n = plugin->new_spectrogram_frames[band]++;
867                 double sample_pos = (n * window_size / 2) / sample_rate;
868                 frame->position = plugin->start_pos + plugin->dir * sample_pos;
869 //if( band == 1 ) {
870 // printf("ComprMultiFFT::signal_process %d top_position=%ld frame->position=%ld\n",
871 // __LINE__, plugin->get_playhead_position(), frame->position);
872 // printf("ComprMultiFFT::signal_process %d band=%d preview_samples=%d frames size=%ld filtered_size=%ld\n",
873 // __LINE__, band, preview_samples, plugin->new_spectrogram_frames[band] *
874 //  window_size, plugin->filtered_size);
875 //}
876         }
877 //printf("ComprMultiFFT::signal_process %d channel=%d band=%d frame=%p\n", __LINE__, channel, band, frame);
878 // apply the bandpass filter
879         for( int i = 0; i < window_size / 2; i++ ) {
880                 double fr = freq_real[i], fi = freq_imag[i];
881                 double env = band_state->envelope[i];
882                 freq_real[i] *= env;  freq_imag[i] *= env;
883                 double mag = sqrt(fr*fr + fi*fi);
884
885 // update the spectrogram with the output
886 // neglect the true average & max spectrograms, but always use the trigger
887                 if( frame ) {
888                         int offset = band * window_size / 2 + i;
889 #ifndef DRAW_AFTER_BANDPASS
890                         frame->data[offset] = MAX(frame->data[offset], mag);
891 // get the maximum output in the frequency domain
892                         if( mag > frame->freq_max )
893                                 frame->freq_max = mag;
894 #else
895                         mag *= env;
896                         frame->data[offset] = MAX(frame->data[offset], mag);
897 // get the maximum output in the frequency domain
898                         if( mag > frame->freq_max )
899                                 frame->freq_max = mag;
900 #endif
901                 }
902         }
903
904         symmetry(window_size, freq_real, freq_imag);
905         return 0;
906 }
907
908
909 int ComprMultiFFT::post_process(int band)
910 {
911         if( frame ) {
912 // get the maximum output in the time domain
913                 double *buffer = output_real;
914 #ifndef DRAW_AFTER_BANDPASS
915                 buffer = input_buffer->get_data();
916 #endif
917                 double time_max = 0;
918                 for( int i = 0; i<window_size; ++i ) {
919                         if( fabs(buffer[i]) > time_max )
920                                 time_max = fabs(buffer[i]);
921                 }
922                 if( time_max > frame->time_max )
923                         frame->time_max = time_max;
924                 plugin->add_gui_frame(frame);
925         }
926         return 0;
927 }
928
929
930 int ComprMultiFFT::read_samples(int64_t output_sample,
931                 int samples, Samples *buffer)
932 {
933         int result = plugin->read_samples(buffer, channel,
934                         plugin->get_samplerate(), output_sample, samples);
935 #ifndef DRAW_AFTER_BANDPASS
936 // append unprocessed samples to the input_buffer
937         int new_input_size = plugin->new_input_size + samples;
938         plugin->allocate_input(new_input_size);
939         memcpy(plugin->input_buffer[channel]->get_data() + plugin->new_input_size,
940                 buffer->get_data(), samples * sizeof(double));
941         plugin->new_input_size = new_input_size;
942 #endif // !DRAW_AFTER_BANDPASS
943         return result;
944 }
945