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;
}
}
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;
}
}
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;
}
}
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;
}
}
{
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;
}
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];
}
CrossfadeFFT::CrossfadeFFT() : FFT()
{
+ bands = 1;
reset();
window_size = 4096;
}
output_buffer = 0;
freq_real = 0;
freq_imag = 0;
+ freq_real2 = 0;
+ freq_imag2 = 0;
output_real = 0;
output_imag = 0;
first_window = 1;
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;
}
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;
{
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;
int CrossfadeFFT::read_samples(int64_t output_sample,
- int samples,
- Samples *buffer)
+ int samples, Samples *buffer)
{
return 1;
}
}
+int CrossfadeFFT::signal_process(int band)
+{
+ signal_process();
+ return 0;
+}
-
+int CrossfadeFFT::post_process(int band)
+{
+ post_process();
+ return 0;
+}