new/reworked audio plugins ported from hv72 compressor/multi/reverb, glyph workaround...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / fourier.C
index 401a5faa1e3a56e2a452df630f3c1658a127ea9d..f78a45bd1e092a990864e9efd716a88cd430d954 100644 (file)
@@ -109,7 +109,7 @@ int FFT::do_fft(int samples,        // must be a power of 2
                        int j = i, k = i+1; // cos(0)=1, sin(0)=0
                        rj = real_out[j];  ij = imag_out[j];
                        rk = real_out[k];  ik = imag_out[k];
-                       real_out[j] += rk;      imag_out[j] += ik;
+                       real_out[j] += rk;        imag_out[j] += ik;
                        real_out[k] = rj - rk;  imag_out[k] = ij - ik;
                }
        }
@@ -119,12 +119,12 @@ int FFT::do_fft(int samples,      // must be a power of 2
                                int j = i, k = j+2; // cos(0)=1,sin(0)=0
                                rj = real_out[j];  ij = imag_out[j];
                                rk = real_out[k];  ik = imag_out[k];
-                               real_out[j] += rk;      imag_out[j] += ik;
+                               real_out[j] += rk;        imag_out[j] += ik;
                                real_out[k] = rj - rk;  imag_out[k] = ij - ik;
                                j = i+1;  k = j+2; // cos(-pi/2)=0, sin(-pi/2)=-1
                                rj = real_out[j];  ij = imag_out[j];
                                rk = real_out[k];  ik = imag_out[k];
-                               real_out[j] += ik;      imag_out[j] -= rk;
+                               real_out[j] += ik;        imag_out[j] -= rk;
                                real_out[k] = rj - ik;  imag_out[k] = ij + rk;
                        }
                }
@@ -133,12 +133,12 @@ int FFT::do_fft(int samples,      // must be a power of 2
                                int j = i, k = j+2; // cos(0)=1,sin(0)=0
                                rj = real_out[j];  ij = imag_out[j];
                                rk = real_out[k];  ik = imag_out[k];
-                               real_out[j] += rk;      imag_out[j] += ik;
+                               real_out[j] += rk;        imag_out[j] += ik;
                                real_out[k] = rj - rk;  imag_out[k] = ij - ik;
                                j = i+1;  k = j+2; // cos(pi/2)=0, sin(pi/2)=1
                                rj = real_out[j];  ij = imag_out[j];
                                rk = real_out[k];  ik = imag_out[k];
-                               real_out[j] -= ik;      imag_out[j] += rk;
+                               real_out[j] -= ik;        imag_out[j] += rk;
                                real_out[k] = rj + ik;  imag_out[k] = ij - rk;
                        }
                }
@@ -167,7 +167,7 @@ int FFT::do_fft(int samples,        // must be a power of 2
                                double rk = *rkp, ik = *ikp;
                                double tr = ar[0] * rk - ai[0] * ik;
                                double ti = ar[0] * ik + ai[0] * rk;
-                               *rjp++ += tr;      *ijp++ += ti;
+                               *rjp++ += tr;     *ijp++ += ti;
                                *rkp++ = rj - tr;  *ikp++ = ij - ti;
                        }
                }
@@ -204,7 +204,7 @@ unsigned int FFT::reverse_bits(unsigned int index, unsigned int bits)
 {
        unsigned int i, rev;
 
-       for(i = rev = 0; i < bits; i++) {
+       for( i = rev = 0; i < bits; i++ ) {
                rev = (rev << 1) | (index & 1);
                index >>= 1;
        }
@@ -259,8 +259,7 @@ unsigned int FFT::reverse_bits(unsigned int index, unsigned int bits)
 int FFT::symmetry(int size, double *freq_real, double *freq_imag)
 {
        int h = size / 2;
-       for(int i = h + 1; i < size; i++)
-       {
+       for( int i = h + 1; i < size; i++ ) {
                freq_real[i] = freq_real[size - i];
                freq_imag[i] = -freq_imag[size - i];
        }
@@ -273,6 +272,7 @@ int FFT::symmetry(int size, double *freq_real, double *freq_imag)
 
 CrossfadeFFT::CrossfadeFFT() : FFT()
 {
+       bands = 1;
        reset();
        window_size = 4096;
 }
@@ -288,6 +288,8 @@ int CrossfadeFFT::reset()
        output_buffer = 0;
        freq_real = 0;
        freq_imag = 0;
+       freq_real2 = 0;
+       freq_imag2 = 0;
        output_real = 0;
        output_imag = 0;
        first_window = 1;
@@ -303,12 +305,17 @@ int CrossfadeFFT::reset()
 
 int CrossfadeFFT::delete_fft()
 {
-       if(input_buffer) delete input_buffer;
-       if(output_buffer) delete [] output_buffer;
-       if(freq_real) delete [] freq_real;
-       if(freq_imag) delete [] freq_imag;
-       if(output_real) delete [] output_real;
-       if(output_imag) delete [] output_imag;
+       delete input_buffer;      input_buffer = 0;
+       if( output_buffer ) {
+               for( int i=0; i<bands; ++i ) delete [] output_buffer[i];
+               delete [] output_buffer;  output_buffer = 0;
+       }
+       delete [] freq_real;      freq_real = 0;
+       delete [] freq_imag;      freq_imag = 0;
+       delete [] freq_real2;    freq_real2 = 0;
+       delete [] freq_imag2;    freq_imag2 = 0;
+       delete [] output_real;  output_real = 0;
+       delete [] output_imag;  output_imag = 0;
        reset();
        return 0;
 }
@@ -324,9 +331,10 @@ int CrossfadeFFT::fix_window_size()
        return 0;
 }
 
-int CrossfadeFFT::initialize(int window_size)
+int CrossfadeFFT::initialize(int window_size, int bands)
 {
        this->window_size = window_size;
+       this->bands = bands;
        first_window = 1;
        reconfigure();
        return 0;
@@ -341,277 +349,172 @@ int CrossfadeFFT::reconfigure()
 {
        delete_fft();
        fix_window_size();
+       return 0;
+}
+void CrossfadeFFT::allocate_output(int new_allocation)
+{
+// Allocate output buffer
+       if( new_allocation > output_allocation ) {
+               if( !output_buffer ) {
+                       output_buffer = new double*[bands];
+                       bzero(output_buffer, sizeof(double) * bands);
+               }
 
+               for( int i = 0; i < bands; i++ ) {
+                       double *new_output = new double[new_allocation];
+                       if( output_buffer[i] ) {
+                               memcpy(new_output, output_buffer[i],
+                                       sizeof(double) * (output_size + HALF_WINDOW));
+                               delete [] output_buffer[i];
+                       }
+                       output_buffer[i] = new_output;
+               }
+               output_allocation = new_allocation;
+       }
+}
 
-
-       return 0;
+int CrossfadeFFT::process_buffer(int64_t output_sample, long size,
+               Samples *output_ptr, int direction)
+{
+       Samples *output_temp[1];
+       output_temp[0] = output_ptr;
+       return process_buffer(output_sample, size, output_temp, direction);
 }
 
-// int CrossfadeFFT::process_fifo(long size,
-//     double *input_ptr,
-//     double *output_ptr)
+// int CrossfadeFFT::get_read_offset()
 // {
-// // Load next input buffer
-//     if(input_size + size > input_allocation)
-//     {
-//             double *new_input = new double[input_size + size];
-//             if(input_buffer)
-//             {
-//                     memcpy(new_input, input_buffer, sizeof(double) * input_size);
-//                     delete [] input_buffer;
-//             }
-//             input_buffer = new_input;
-//             input_allocation = input_size + size;
-//     }
-//
-//     memcpy(input_buffer + input_size,
-//             input_ptr,
-//             size * sizeof(double));
-//     input_size += size;
-//
-//
-//
-//
-//
-//
-//
-// // Have enough to do some windows
-//     while(input_size >= window_size)
-//     {
-//             if(!freq_real) freq_real = new double[window_size];
-//             if(!freq_imag) freq_imag = new double[window_size];
-//             if(!output_real) output_real = new double[window_size];
-//             if(!output_imag) output_imag = new double[window_size];
-//
-//
-//
-//             do_fft(window_size,  // must be a power of 2
-//                     0,               // 0 = forward FFT, 1 = inverse
-//                     input_buffer,    // array of input's real samples
-//                     0,       // array of input's imag samples
-//                     freq_real,      // array of output's reals
-//                     freq_imag);
-//
-//             int result = signal_process();
-//
-//             if(!result)
-//             {
-//                     do_fft(window_size,  // must be a power of 2
-//                             1,                         // 0 = forward FFT, 1 = inverse
-//                             freq_real,       // array of input's real samples
-//                             freq_imag,       // array of input's imag samples
-//                             output_real,     // array of output's reals
-//                             output_imag);
-//             }
-//
-//
-// // Crossfade into the output buffer
-//             long new_allocation = output_size + window_size;
-//             if(new_allocation > output_allocation)
-//             {
-//                     double *new_output = new double[new_allocation];
-//
-//                     if(output_buffer)
-//                     {
-//                             memcpy(new_output, output_buffer, sizeof(double) * output_size);
-//                             delete [] output_buffer;
-//                     }
-//                     output_buffer = new_output;
-//                     output_allocation = new_allocation;
-//             }
-//
-//             if(output_size >= HALF_WINDOW)
-//             {
-//                     for(int i = 0, j = output_size - HALF_WINDOW;
-//                             i < HALF_WINDOW;
-//                             i++, j++)
-//                     {
-//                             double src_level = (double)i / HALF_WINDOW;
-//                             double dst_level = (double)(HALF_WINDOW - i) / HALF_WINDOW;
-//                             output_buffer[j] = output_buffer[j] * dst_level + output_real[i] * src_level;
-//                     }
-//
-//                     memcpy(output_buffer + output_size,
-//                             output_real + HALF_WINDOW,
-//                             sizeof(double) * (window_size - HALF_WINDOW));
-//                     output_size += window_size - HALF_WINDOW;
-//             }
-//             else
-//             {
-// // First buffer has no crossfade
-//                     memcpy(output_buffer + output_size,
-//                             output_real,
-//                             sizeof(double) * window_size);
-//                     output_size += window_size;
-//             }
-//
-//
-// // Shift input buffer forward
-//             for(int i = window_size - HALF_WINDOW, j = 0;
-//                     i < input_size;
-//                     i++, j++)
-//                     input_buffer[j] = input_buffer[i];
-//             input_size -= window_size - HALF_WINDOW;
-//     }
-//
-//
-//
-//
-// // Have enough to send to output
-//     int samples_rendered = 0;
-//     if(output_size - HALF_WINDOW >= size)
-//     {
-//             memcpy(output_ptr, output_buffer, sizeof(double) * size);
-//             for(int i = size, j = 0; i < output_size; i++, j++)
-//                     output_buffer[j] = output_buffer[i];
-//             output_size -= size;
-//             samples_rendered = size;
-//     }
-//     else
-//     {
-//             bzero(output_ptr, sizeof(double) * size);
-//     }
-//
-//     return samples_rendered;
 // }
 
-
-
 int CrossfadeFFT::process_buffer(int64_t output_sample,
-       long size,
-       Samples *output_ptr,
-       int direction)
+               long size, Samples **output_ptr, int direction)
 {
        int result = 0;
        int step = (direction == PLAY_FORWARD) ? 1 : -1;
 
 // User seeked so output buffer is invalid
-       if(output_sample != this->output_sample)
-       {
+       if( output_sample != this->output_sample ) {
                output_size = 0;
                input_size = 0;
                first_window = 1;
                this->output_sample = output_sample;
-               this->input_sample = output_sample;
+               input_sample = output_sample;
        }
 
-// Fill output buffer half a window at a time until size samples are available
-       while(output_size < size)
-       {
-               if(!input_buffer) input_buffer = new Samples(window_size);
-               if(!freq_real) freq_real = new double[window_size];
-               if(!freq_imag) freq_imag = new double[window_size];
-               if(!output_real) output_real = new double[window_size];
-               if(!output_imag) output_imag = new double[window_size];
-
-// Fill enough input to make a window starting at output_sample
-               if(first_window)
-                       result = read_samples(this->input_sample,
-                               window_size,
-                               input_buffer);
-               else
-               {
-                       input_buffer->set_offset(HALF_WINDOW);
-// printf("CrossfadeFFT::process_buffer %d %lld %lld\n",
-// __LINE__,
-// this->input_sample + step * HALF_WINDOW,
-// this->input_sample + step * HALF_WINDOW + HALF_WINDOW);
-                       result = read_samples(this->input_sample + step * HALF_WINDOW,
-                               HALF_WINDOW,
-                               input_buffer);
-                       input_buffer->set_offset(0);
-               }
 
-               input_size = window_size;
-
-               if(!result)
-                       do_fft(window_size,   // must be a power of 2
-                               0,                              // 0 = forward FFT, 1 = inverse
-                               input_buffer->get_data(),        // array of input's real samples
-                               0,                              // array of input's imag samples
-                               freq_real,              // array of output's reals
-                               freq_imag);
-               if(!result)
-                       result = signal_process();
-
-               if(!result)
-                       do_fft(window_size,  // must be a power of 2
-                               1,                         // 0 = forward FFT, 1 = inverse
-                               freq_real,         // array of input's real samples
-                               freq_imag,         // array of input's imag samples
-                               output_real,       // array of output's reals
-                               output_imag);     // array of output's imaginaries
-
-               if(!result)
-                       result = post_process();
+// printf("CrossfadeFFT::process_buffer %d size=%ld input_size=%ld output_size=%ld window_size=%ld\n",
+// __LINE__, size, input_size, output_size, window_size);
 
-// Allocate output buffer
-               int new_allocation = output_size + window_size;
-               if(new_allocation > output_allocation)
-               {
-                       double *new_output = new double[new_allocation];
-                       if(output_buffer)
-                       {
-                               memcpy(new_output,
-                                       output_buffer,
-                                       sizeof(double) * (output_size + HALF_WINDOW));
-                               delete [] output_buffer;
-                       }
-                       output_buffer = new_output;
-                       output_allocation = new_allocation;
+// must call read_samples once so the upstream plugins don't have to seek
+// must be a multiple of 1/2 window
+       int need_samples = (size - output_size) / HALF_WINDOW * HALF_WINDOW;
+// round up a half window
+       if( need_samples + output_size < size ) {
+               need_samples += HALF_WINDOW;
+       }
+// half window tail
+       need_samples += HALF_WINDOW;
+
+// extend the buffer to need_samples
+       if( !input_buffer || input_buffer->get_allocated() < need_samples ) {
+               Samples *new_input_buffer = new Samples(need_samples);
+
+               if( input_buffer ) {
+                       memcpy(new_input_buffer->get_data(),
+                               input_buffer->get_data(),
+                               input_size * sizeof(double));
+                       delete input_buffer;
                }
 
-// Overlay processed buffer
-               if(first_window)
-               {
-                       memcpy(output_buffer + output_size,
-                               output_real,
-                               sizeof(double) * window_size);
-                       first_window = 0;
-               }
-               else
-               {
-                       for(int i = 0, j = output_size; i < HALF_WINDOW; i++, j++)
-                       {
-                               double src_level = (double)i / HALF_WINDOW;
-                               double dst_level = (double)(HALF_WINDOW - i) / HALF_WINDOW;
-                               output_buffer[j] = output_buffer[j] * dst_level +
-                                       output_real[i] * src_level;
+               input_buffer = new_input_buffer;
+       }
+
+       input_buffer->set_offset(input_size);
+       result = read_samples(input_sample, need_samples-input_size, input_buffer);
+       input_buffer->set_offset(0);
+       input_sample += step * (need_samples - input_size);
+       input_size = need_samples;
+
+
+       if( !freq_real ) freq_real = new double[window_size];
+       if( !freq_imag ) freq_imag = new double[window_size];
+       if( !freq_real2 ) freq_real2 = new double[window_size];
+       if( !freq_imag2 ) freq_imag2 = new double[window_size];
+       if( !output_real ) output_real = new double[window_size];
+       if( !output_imag ) output_imag = new double[window_size];
+
+// Fill output buffer half a window at a time until size samples are available
+       while( !result && output_size < size ) {
+               do_fft(window_size, 0,  // forward
+                       input_buffer->get_data(), 0, // input, real only
+                       freq_real2, freq_imag2); // output
+               allocate_output(output_size + window_size);
+// process & overlay each band separately
+               for( int band=0; band<bands; ++band ) {
+// restore from the backup
+                       memcpy(freq_real, freq_real2, sizeof(double) * window_size);
+                       memcpy(freq_imag, freq_imag2, sizeof(double) * window_size);
+                       signal_process(band);
+                       do_fft(window_size, 1,  // inverse
+                               freq_real, freq_imag, // input
+                               output_real, output_imag); // output
+                       post_process(band);
+
+// Overlay processed window on the output buffers
+                       if( first_window ) {
+// direct copy the 1st window
+                               memcpy(output_buffer[band] + output_size,
+                                       output_real,
+                                       sizeof(double) * window_size);
                        }
+                       else {
+// dissolve 1st half of later windows
+                               for( int i = 0, j = output_size; i < HALF_WINDOW; i++, j++ ) {
+                                       double src_level = (double)i / HALF_WINDOW;
+                                       double dst_level = (double)(HALF_WINDOW - i) / HALF_WINDOW;
+                                       output_buffer[band][j] = output_buffer[band][j] * dst_level +
+                                               output_real[i] * src_level;
+                               }
 
 //output_buffer[output_size] = 100.0;
 //output_buffer[output_size + HALF_WINDOW] = -100.0;
-
-                       memcpy(output_buffer + output_size + HALF_WINDOW,
-                               output_real + HALF_WINDOW,
-                               sizeof(double) * HALF_WINDOW);
+// copy 2nd half of window
+                               memcpy(output_buffer[band] + output_size + HALF_WINDOW,
+                                       output_real + HALF_WINDOW,
+                                       sizeof(double) * HALF_WINDOW);
+                       }
                }
 
-
+               first_window = 0;
                output_size += HALF_WINDOW;
 
-// Shift input buffer
-               double *input_samples = input_buffer->get_data();
-               for(int i = window_size - HALF_WINDOW, j = 0;
-                       i < input_size;
-                       i++, j++)
-               {
-                       input_samples[j] = input_samples[i];
-               }
+// Shift input buffer half a window forward
+               memcpy(input_buffer->get_data(),
+                       input_buffer->get_data() + HALF_WINDOW,
+                       (input_size - HALF_WINDOW) * sizeof(double));
+//             for( int i = HALF_WINDOW, j = 0;
+//                     i < input_size;
+//                     i++, j++ )
+//             {
+//                     input_buffer->get_data()[j] = input_buffer->get_data()[i];
+//             }
 
-               input_size = HALF_WINDOW;
-               this->input_sample += step * HALF_WINDOW;
+               input_size -= HALF_WINDOW;
        }
 
 
 
-// Transfer output buffer
-       if(output_ptr)
-       {
-               memcpy(output_ptr->get_data(), output_buffer, sizeof(double) * size);
+// Transfer output buffer if the user wants it
+       if( output_ptr ) {
+               for( int band = 0; band < bands; band++ ) {
+                       memcpy(output_ptr[band]->get_data(), output_buffer[band], sizeof(double) * size);
+               }
+       }
+
+// shift output buffers forward
+       for( int band = 0; band < bands; band++ ) {
+               memcpy(output_buffer[band], output_buffer[band] + size,
+                       sizeof(double) * (output_size + HALF_WINDOW - size));
        }
-       for(int i = 0, j = size; j < output_size + HALF_WINDOW; i++, j++)
-               output_buffer[i] = output_buffer[j];
 
        this->output_sample += step * size;
        this->output_size -= size;
@@ -621,8 +524,7 @@ int CrossfadeFFT::process_buffer(int64_t output_sample,
 
 
 int CrossfadeFFT::read_samples(int64_t output_sample,
-               int samples,
-               Samples *buffer)
+               int samples, Samples *buffer)
 {
        return 1;
 }
@@ -640,9 +542,18 @@ int CrossfadeFFT::post_process()
 }
 
 
+int CrossfadeFFT::signal_process(int band)
+{
+       signal_process();
+       return 0;
+}
 
 
 
-
+int CrossfadeFFT::post_process(int band)
+{
+       post_process();
+       return 0;
+}