/* * CINELERRA * Copyright (C) 1997-2011 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "clip.h" #include "fourier.h" #include "samples.h" #include "transportque.inc" #define HALF_WINDOW (window_size / 2) FFT::FFT() { } FFT::~FFT() { } void FFT::bit_reverse(unsigned int samples, double *real_in, double *imag_in, double *real_out, double *imag_out) { unsigned int i, j; unsigned int num_bits = samples_to_bits(samples); unsigned int samples1 = samples - 1; if( !real_out ) real_out = real_in; if( real_out == real_in ) { // Do in-place bit-reversal ordering if( !imag_in ) { imag_out[0] = 0.0; for( i=1; i= j ) continue; double tr = real_out[j]; real_out[j] = real_out[i]; real_out[i] = tr; } imag_out[samples1] = 0.0; } else { for( i=1; i= j ) continue; double tr = real_out[j], ti = imag_out[j]; real_out[j] = real_out[i]; real_out[i] = tr; imag_out[j] = imag_out[i]; imag_out[i] = ti; } } } else { // Do simultaneous data copy and bit-reversal ordering if( !imag_in ) { real_out[0] = real_in[0]; imag_out[0] = 0.0; for( i=0; i j ) continue; real_out[j] = real_in[i]; real_out[i] = real_in[j]; imag_out[i] = imag_out[j] = 0.0; } real_out[samples1] = real_in[samples1]; imag_out[samples1] = 0.0; } else { for( i=0; i j ) continue; real_out[i] = real_in[j]; imag_out[i] = imag_in[j]; real_out[j] = real_in[i]; imag_out[j] = imag_in[i]; } } } } int FFT::do_fft(int samples, // must be a power of 2 int inverse, // 0 = forward FFT, 1 = inverse double *real_in, double *imag_in, // complex input double *real_out, double *imag_out) // complex output { bit_reverse(samples, real_in, imag_in, real_out, imag_out); double angle_numerator = !inverse ? 2*M_PI : -2*M_PI ; double ar[3], ai[3], rj, ij, rk, ik; // In the first two passes, all of the multiplys, and half the adds // are saved by unrolling and reducing the x*1,x*0,x+0 operations. if( samples >= 2 ) { // block 1, delta_angle = pi for( int i=0; i= 4 ) { // block 2, delta_angle = pi/2 if( !inverse ) { for( int i=0; i=0; ) { ar[0] = w * ar[1] - ar[2]; ar[2] = ar[1]; ar[1] = ar[0]; ai[0] = w * ai[1] - ai[2]; ai[2] = ai[1]; ai[1] = ai[0]; double rj = *rjp, ij = *ijp; 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; *rkp++ = rj - tr; *ikp++ = ij - ti; } } bsz = bsz2; } // Normalize if inverse transform if( inverse ) { double scale = 1./samples; for( int i=0; i>i) != 0 ) ++i; return i; } #if 0 unsigned int FFT::reverse_bits(unsigned int index, unsigned int bits) { unsigned int i, rev; for(i = rev = 0; i < bits; i++) { rev = (rev << 1) | (index & 1); index >>= 1; } return rev; } #else uint8_t FFT::rev_bytes[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, }; unsigned int FFT::reverse_bits(unsigned int index, unsigned int bits) { unsigned char b; union { unsigned int u; uint8_t b[sizeof(unsigned int)]; } data; data.u = index; if( bits <= 8 ) { index = rev_bytes[data.b[0]] >> (8-bits); } else if( bits <= 16 ) { b = data.b[0]; data.b[0] = rev_bytes[data.b[1]]; data.b[1] = rev_bytes[b]; index = data.u >> (16-bits); } else { b = data.b[0]; data.b[0] = rev_bytes[data.b[3]]; data.b[3] = rev_bytes[b]; b = data.b[1]; data.b[1] = rev_bytes[data.b[2]]; data.b[2] = rev_bytes[b]; index = data.u >> (32-bits); } return index; } #endif int FFT::symmetry(int size, double *freq_real, double *freq_imag) { int h = size / 2; for(int i = h + 1; i < size; i++) { freq_real[i] = freq_real[size - i]; freq_imag[i] = -freq_imag[size - i]; } return 0; } CrossfadeFFT::CrossfadeFFT() : FFT() { reset(); window_size = 4096; } CrossfadeFFT::~CrossfadeFFT() { delete_fft(); } int CrossfadeFFT::reset() { input_buffer = 0; output_buffer = 0; freq_real = 0; freq_imag = 0; output_real = 0; output_imag = 0; first_window = 1; // samples in input_buffer and output_buffer input_size = 0; output_size = 0; input_allocation = 0; output_allocation = 0; output_sample = 0; input_sample = 0; return 0; } 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; reset(); return 0; } int CrossfadeFFT::fix_window_size() { // fix the window size // window size must be a power of 2 int new_size = 16; while(new_size < window_size) new_size *= 2; window_size = MIN(131072, window_size); window_size = new_size; return 0; } int CrossfadeFFT::initialize(int window_size) { this->window_size = window_size; first_window = 1; reconfigure(); return 0; } long CrossfadeFFT::get_delay() { return window_size + HALF_WINDOW; } int CrossfadeFFT::reconfigure() { delete_fft(); fix_window_size(); return 0; } // int CrossfadeFFT::process_fifo(long size, // double *input_ptr, // double *output_ptr) // { // // 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) { int result = 0; int step = (direction == PLAY_FORWARD) ? 1 : -1; // User seeked so output buffer is invalid 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; } // 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(); // 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; } // 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; } //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); } 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]; } input_size = HALF_WINDOW; this->input_sample += step * HALF_WINDOW; } // Transfer output buffer if(output_ptr) { memcpy(output_ptr->get_data(), output_buffer, sizeof(double) * 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; return 0; } int CrossfadeFFT::read_samples(int64_t output_sample, int samples, Samples *buffer) { return 1; } int CrossfadeFFT::signal_process() { return 0; } int CrossfadeFFT::post_process() { return 0; }