diff -ru --exclude-from exclude hvirtual-cvs/plugins/libfourier/fourier.C hvirtual-1.2/plugins/libfourier/fourier.C
--- hvirtual-cvs/plugins/libfourier/fourier.C	2004-02-17 20:21:02.000000000 +0100
+++ hvirtual-1.2/plugins/libfourier/fourier.C	2005-08-31 20:28:15.000000000 +0200
@@ -9,6 +9,10 @@
 #define HALF_WINDOW (window_size / 2)
 
 
+// we need to do some trickery to get around of fftw thread unsafetyness
+fftw_plan_desc *FFT::fftw_plans = 0;
+Mutex FFT::plans_lock = Mutex();
+
 FFT::FFT()
 {
 }
@@ -154,6 +158,50 @@
 	return 0;
 }
 
+// Create a proper fftw plan to be used later
+int FFT::ready_fftw(unsigned int samples)
+{
+// FFTW plan generation is not thread safe, so we have to take precausions
+	FFT::plans_lock.lock();
+	fftw_plan_desc *plan;
+	
+	my_fftw_plan = 0;
+	
+	for (plan = fftw_plans; plan; plan = plan->next)
+		if (plan->samples == samples) 
+		{
+			my_fftw_plan = plan;
+			break;
+		}
+	
+	if (!my_fftw_plan)
+	{
+		fftw_complex *temp_data = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * samples);
+		my_fftw_plan = new fftw_plan_desc;   // we never discard this, since they are static
+		my_fftw_plan->samples = samples;
+		my_fftw_plan->plan_forward = fftw_plan_dft_1d(samples, temp_data, temp_data, FFTW_FORWARD, FFTW_ESTIMATE);
+		my_fftw_plan->plan_backward = fftw_plan_dft_1d(samples, temp_data, temp_data, FFTW_BACKWARD, FFTW_ESTIMATE);
+		// We will use this plan only in guru mode so we can now discard the temp_data
+		fftw_free(temp_data);
+	
+		// Put the plan into the linked list
+		my_fftw_plan->next = fftw_plans;
+		fftw_plans = my_fftw_plan;
+	}
+	
+	FFT::plans_lock.unlock();
+	return 0;
+}
+
+int FFT::do_fftw_inplace(unsigned int samples,
+		int inverse,
+		fftw_complex *data)
+{
+	if (inverse == 0)
+		fftw_execute_dft(my_fftw_plan->plan_forward, data, data);
+	else
+		fftw_execute_dft(my_fftw_plan->plan_backward, data, data);
+}
 
 
 
@@ -185,6 +233,11 @@
 	output_allocation = 0;
 	output_sample = 0;
 	input_sample = 0;
+	samples_ready = 0;
+	oversample = 0;
+	pre_window = 0;
+	post_window = 0;
+	fftw_data = 0;
 	return 0;
 }
 
@@ -196,6 +249,9 @@
 	if(freq_imag) delete [] freq_imag;
 	if(temp_real) delete [] temp_real;
 	if(temp_imag) delete [] temp_imag;
+	if(pre_window) delete [] pre_window;
+	if(post_window) delete [] post_window;
+	if(fftw_data) fftw_free(fftw_data);
 	reset();
 	return 0;
 }
@@ -234,134 +290,6 @@
 	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(!temp_real) temp_real = new double[window_size];
-// 		if(!temp_imag) temp_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
-//     			temp_real,     // array of output's reals
-//     			temp_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 + temp_real[i] * src_level;
-// 			}
-// 
-// 			memcpy(output_buffer + output_size, 
-// 				temp_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, 
-// 				temp_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, 
@@ -372,8 +300,7 @@
 	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 || first_window)
 	{
 		output_size = 0;
 		input_size = 0;
@@ -487,6 +414,218 @@
 	return 0;
 }
 
+void CrossfadeFFT::ready_oversample(int oversample) 
+{
+// Only powers of two can be used for oversample
+	int oversample_fix = 2;
+	while(oversample_fix < oversample) oversample_fix *= 2;
+	this->oversample = oversample = oversample_fix;
+	
+// Precalculate the pre-envelope hanning window
+	pre_window = new double[window_size];
+	for (int i = 0; i< window_size; i++) 
+		pre_window[i] = 0.5 - 0.5 *cos(2 * M_PI * i / window_size); 
+
+// Precalculate the post-envelope hanning window also, we could have triangle here also
+	post_window = new double[window_size];
+/*	for (int i = 0; i< window_size/2; i++) 
+		post_window[i] = 1.0 * i / (window_size/2) / oversample * 2;
+	for (int i = window_size/2; i< window_size; i++) 
+		post_window[i] = 1.0 * (window_size - i) / (window_size/2) / oversample * 2;
+ */
+	for (int i = 0; i< window_size; i++) 
+		post_window[i] = (0.5 - 0.5 *cos(2 * M_PI * i / window_size)) * 6/ oversample / window_size; 
+
+	ready_fftw(window_size);
+
+} 
+
+void smbFft(double *fftBuffer, long fftFrameSize, long sign);
+
+
+
+
+int CrossfadeFFT::process_buffer_oversample(int64_t output_sample, 
+	long size, 
+	double *output_ptr,
+	int direction)
+{
+	if (oversample <= 0)
+	{
+		printf("ready_oversample() has to be called to use process_buffer_oversample\n");
+		return 1;
+	}
+	int result = 0;
+	int step = (direction == PLAY_FORWARD) ? 1 : -1;
+
+	int overlap_size = window_size / oversample;
+	int total_size;
+	int start_skip;
+
+	if (!output_ptr) 
+	{
+		printf("ERROR, no output pointer!\n");
+		return 1;
+	}
+	if(output_sample != this->output_sample || first_window)
+	{
+		input_size = 0;
+		first_window = 1;
+		this->output_sample = output_sample;
+		samples_ready = 0;
+		start_skip = window_size - overlap_size;
+		total_size = size + start_skip;
+		// signal_process() will always be able to know which window it has by looking at input_sample
+		this->input_sample = output_sample - step * start_skip;
+		if (step == -1) this->input_sample += overlap_size;
+	} else
+	{
+		start_skip = 0;
+		total_size = size;
+		first_window = 0;
+	}
+
+// Find out how big output buffer we will need, take overlapping into account
+	int new_allocation = total_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) * (samples_ready + window_size - overlap_size));
+			delete [] output_buffer;
+			
+		}
+		output_buffer = new_output;
+		output_allocation = new_allocation;
+	}
+// Fill output buffer by overlap_size at a time until size samples are available
+	while(samples_ready < total_size)
+	{
+		if(!input_buffer) input_buffer = new double[window_size];
+		if(!fftw_data) fftw_data = (fftw_complex *)fftw_malloc(window_size * sizeof(fftw_complex));
+
+// Fill enough input to make a window starting at output_sample
+		int64_t read_start;
+		int write_pos;
+		int read_len;
+
+		if(first_window)
+		{
+			if (step == 1)
+				read_start = this->input_sample;
+			else
+				read_start = this->input_sample - window_size;
+			write_pos = 0;
+			read_len = window_size;
+		} else
+		{ 
+			if (step == 1)
+			{
+				read_start = this->input_sample + window_size - overlap_size;
+				write_pos = window_size - overlap_size;
+			} else 
+			{
+				read_start = this->input_sample - window_size;
+				write_pos = 0;
+			}
+			read_len = overlap_size;
+		}
+
+		if (read_start < 0)
+		{
+// completely outside the track	
+			memset (input_buffer + write_pos, 0, read_len * sizeof(double));
+			result = 1;
+		} else
+		if (read_start + read_len *step < 0)
+		{
+// special case for reading before the track - in general it would be sensible that this behaviour is done by read_samples()
+			memset (input_buffer, 0, (read_len - read_start) * sizeof(double));
+			result = read_samples(read_start,
+				read_start,
+				input_buffer + read_len *step + read_start + write_pos);
+		} else
+		{
+//printf("Readstart: %lli, read len: %i, write pos: %i\n", read_start, read_len, write_pos);
+			result = read_samples(read_start,
+				read_len,
+				input_buffer + write_pos);
+		}
+
+
+// apply Hanning window to input samples
+		for (int i = 0; i< window_size; i++) 
+		{
+			fftw_data[i][0] = input_buffer[i] * pre_window[i];
+			fftw_data[i][1] = 0;
+		}
+
+
+		if(!result) 
+			do_fftw_inplace(window_size, 0, fftw_data);
+		if(!result)
+			result = signal_process_oversample(first_window);
+		if(!result) 
+			do_fftw_inplace(window_size, 1, fftw_data);
+
+// Overlay over existing output - overlap processing
+		if (step == 1)
+		{
+			for (int i = 0; i < window_size - overlap_size; i++)
+				output_buffer[i + samples_ready] += fftw_data[i][0] * post_window[i]; 
+			for (int i = window_size - overlap_size; i < window_size; i++)
+				output_buffer[i + samples_ready] = fftw_data[i][0] * post_window[i];
+		} else
+		{
+			int offset = output_allocation - samples_ready - window_size;
+			for (int i = 0; i < overlap_size; i++)
+				output_buffer[i + offset] = fftw_data[i][0] * post_window[i]; 
+			for (int i = overlap_size; i < window_size; i++)
+				output_buffer[i + offset] += fftw_data[i][0] * post_window[i];
+		}
+
+
+// Shift input buffer
+		if (step == 1) 
+			memmove(input_buffer, input_buffer + overlap_size, (window_size - overlap_size) * sizeof(double));
+		else
+			memmove(input_buffer + overlap_size, input_buffer, (window_size - overlap_size) * sizeof(double));
+		
+		this->input_sample += step * overlap_size;
+
+		samples_ready += overlap_size;
+		first_window = 0;
+	}
+
+	if (step == 1)
+	{
+		memcpy(output_ptr, output_buffer + start_skip , size * sizeof(double));
+		samples_ready -= total_size;
+
+		memmove(output_buffer, 
+			output_buffer + total_size, 
+			(samples_ready + window_size - overlap_size) * sizeof(double));
+		this->output_sample += size;
+		
+	} else
+	{
+		memcpy(output_ptr, output_buffer + output_allocation - total_size , size * sizeof(double));
+		samples_ready -= total_size;
+
+		memmove(output_buffer + output_allocation - (samples_ready + window_size - overlap_size),
+			output_buffer + output_allocation - (samples_ready + window_size - overlap_size) - total_size, 
+			(samples_ready + window_size - overlap_size) * sizeof(double));
+		
+		this->output_sample -= size;
+	}
+	
+
+	return 0;
+}
+
 
 int CrossfadeFFT::read_samples(int64_t output_sample, 
 		int samples, 
@@ -499,3 +638,8 @@
 {
 	return 0;
 }
+
+int CrossfadeFFT::signal_process_oversample(int reset)
+{
+	return 0;
+}
diff -ru --exclude-from exclude hvirtual-cvs/plugins/libfourier/fourier.h hvirtual-1.2/plugins/libfourier/fourier.h
--- hvirtual-cvs/plugins/libfourier/fourier.h	2004-02-17 20:21:02.000000000 +0100
+++ hvirtual-1.2/plugins/libfourier/fourier.h	2005-08-31 20:27:54.000000000 +0200
@@ -2,8 +2,18 @@
 #define FOURIER_H
 
 
+
 #include <stdint.h>
+#include <fftw3.h>
+
+#include "mutex.h"
 
+typedef struct fftw_plan_desc {
+	int samples;
+	fftw_plan plan_forward;
+	fftw_plan plan_backward;
+	fftw_plan_desc *next;
+};
 
 class FFT
 {
@@ -12,17 +22,30 @@
 	~FFT();
 
 	int do_fft(unsigned int samples,  // must be a power of 2
-    	int inverse,         // 0 = forward FFT, 1 = inverse
-    	double *real_in,     // array of input's real samples
-    	double *imag_in,     // array of input's imag samples
-    	double *real_out,    // array of output's reals
-    	double *imag_out);   // array of output's imaginaries
+	    	int inverse,         // 0 = forward FFT, 1 = inverse
+	    	double *real_in,     // array of input's real samples
+	    	double *imag_in,     // array of input's imag samples
+    		double *real_out,    // array of output's reals
+    		double *imag_out);   // array of output's imaginaries
 	int symmetry(int size, double *freq_real, double *freq_imag);
 	unsigned int samples_to_bits(unsigned int samples);
 	unsigned int reverse_bits(unsigned int index, unsigned int bits);
 	virtual int update_progress(int current_position);
+
+	fftw_plan_desc *my_fftw_plan;
+	int ready_fftw(unsigned int samples);
+	int do_fftw_inplace(unsigned int samples,
+		int inverse,
+		fftw_complex *data);
+
+// We have to get around the thread unsafety of fftw
+	static fftw_plan_desc *fftw_plans;
+	static Mutex plans_lock;
+
+
 };
 
+
 class CrossfadeFFT : public FFT
 {
 public:
@@ -35,6 +58,9 @@
 	int reconfigure();
 	int fix_window_size();
 	int delete_fft();
+	// functioy to be called to initialize oversampling
+	void ready_oversample(int oversample); // 2, 4,8 are good values
+	
 
 
 // Read enough samples from input to generate the requested number of samples.
@@ -49,21 +75,33 @@
 		double *output_ptr,
 		int direction);
 
+	int process_buffer_oversample(int64_t output_sample,
+		long size, 
+		double *output_ptr,
+		int direction);
+
 // Called by process_buffer to read samples from input.
 // Returns 1 on error or 0 on success.
 	virtual int read_samples(int64_t output_sample, 
 		int samples, 
 		double *buffer);
 
-// Process a window in the frequency domain
+// Process a window in the frequency domain, called by process_buffer()
 	virtual int signal_process();        
 
+// Process a window in the frequency domain, called by process_buffer_oversample()
+// Reset parameter should cause to reset all accumulated data
+	virtual int signal_process_oversample(int reset);
+   
+
 // Size of a window.  Automatically fixed to a power of 2
 	long window_size;   
 
 // Output of FFT
 	double *freq_real;
 	double *freq_imag;
+// data for FFT that is going to be done by FFTW
+	fftw_complex *fftw_data;
 
 private:
 
@@ -89,6 +127,18 @@
 	int64_t input_sample;
 // Don't crossfade the first window
 	int first_window;
+
+
+// Number of samples that are already processed and waiting in output_buffer
+	int samples_ready; 
+// Hanning window precalculated
+	double *pre_window;
+// Triangle window precalculated
+	double *post_window;
+protected:
+// Oversample factor
+	int oversample;
+
 };
 
 #endif
diff -ru --exclude-from exclude hvirtual-cvs/plugins/pitch/pitch.C hvirtual-1.2/plugins/pitch/pitch.C
--- hvirtual-cvs/plugins/pitch/pitch.C	2004-08-16 21:51:43.000000000 +0200
+++ hvirtual-1.2/plugins/pitch/pitch.C	2005-09-01 19:25:51.000000000 +0200
@@ -13,9 +13,11 @@
 
 
 
-#define WINDOW_SIZE 4096
+#define WINDOW_SIZE 8192
+#define OVERSAMPLE 8
 
 
+//#define WINDOW_SIZE 131072
 
 REGISTER_PLUGIN(PitchEffect);
 
@@ -124,21 +126,28 @@
 	}
 }
 
+
+
 int PitchEffect::process_buffer(int64_t size, 
 		double *buffer,
 		int64_t start_position,
 		int sample_rate)
 {
 	load_configuration();
+
+
 	if(!fft)
 	{
 		fft = new PitchFFT(this);
 		fft->initialize(WINDOW_SIZE);
+		fft->ready_oversample(OVERSAMPLE);
 	}
-	fft->process_buffer(start_position,
+
+	fft->process_buffer_oversample(start_position,
 		size, 
 		buffer,
 		get_direction());
+
 	return 0;
 }
 
@@ -154,53 +163,181 @@
  : CrossfadeFFT()
 {
 	this->plugin = plugin;
+	last_phase = new double[WINDOW_SIZE];
+	new_freq = new double[WINDOW_SIZE];
+	new_magn = new double[WINDOW_SIZE];
+	sum_phase = new double[WINDOW_SIZE];
+	anal_magn = new double[WINDOW_SIZE];
+	anal_freq = new double[WINDOW_SIZE];
+
+}
+
+PitchFFT::~PitchFFT()
+{
+	delete [] last_phase;
+	delete [] new_freq;
+	delete [] new_magn;
+	delete [] sum_phase;
+	delete [] anal_magn;
+	delete [] anal_freq;
 }
 
 
-int PitchFFT::signal_process()
+int PitchFFT::signal_process_oversample(int reset)
 {
-	int min_freq = 
-		1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / 
-			window_size * 2) + 0.5);
-	if(plugin->config.scale < 1)
+	double scale = plugin->config.scale;
+	
+	memset(new_freq, 0, window_size * sizeof(double));
+	memset(new_magn, 0, window_size * sizeof(double));
+	
+	if (reset)
+	{
+		memset (last_phase, 0, WINDOW_SIZE * sizeof(double));
+		memset (sum_phase, 0, WINDOW_SIZE * sizeof(double));
+	}
+	
+	// new or old behaviour
+	if (1)
+	{	
+	// expected phase difference between windows
+		double expected_phase_diff = 2.0 * M_PI / oversample; 
+	// frequency per bin
+		double freq_per_bin = (double)plugin->PluginAClient::project_sample_rate / window_size;
+
+	//scale = 1.0;
+		for (int i = 0; i < window_size/2; i++) 
+		{
+	// Convert to magnitude and phase
+			double magn = sqrt(fftw_data[i][0] * fftw_data[i][0] + fftw_data[i][1] * fftw_data[i][1]);
+			double phase = atan2(fftw_data[i][1], fftw_data[i][0]);
+			
+	// Remember last phase
+			double temp = phase - last_phase[i];
+			last_phase[i] = phase;
+		
+	// Substract the expected advancement of phase
+			temp -= (double)i * expected_phase_diff;
+			
+
+	// wrap temp into -/+ PI ...  good trick!
+			int qpd = (int)(temp/M_PI);
+			if (qpd >= 0) 
+				qpd += qpd&1;
+			else 
+				qpd -= qpd&1;
+			temp -= M_PI*(double)qpd;	
+
+	// Deviation from bin frequency	
+			temp = oversample * temp / (2.0 * M_PI);
+			
+			temp = (double)(temp + i) * freq_per_bin;
+
+	//		anal_magn[i] = magn;
+	//		anal_freq[i] = temp;
+
+	// Now temp is the real freq... move it!
+	//		int new_bin = (int)(temp * scale / freq_per_bin + 0.5);
+			int new_bin = (int)i *scale;
+			if (new_bin >= 0 && new_bin < window_size/2)
+			{
+	//			double tot_magn = new_magn[new_bin] + magn;
+				
+	//			new_freq[new_bin] = (new_freq[new_bin] * new_magn[new_bin] + temp *scale* magn) / tot_magn;
+				new_freq[new_bin] = temp*scale;
+				new_magn[new_bin] += magn;
+			}
+
+		}
+		
+	/*	for (int k = 0; k <= window_size/2; k++) {
+			int index = k/scale;
+			if (index <= window_size/2) {
+				new_magn[k] += anal_magn[index];
+				new_freq[k] = anal_freq[index] * scale;
+			} else{
+			
+			new_magn[k] = 0;
+			new_freq[k] = 0;
+			}
+		}
+
+	*/
+		// Synthesize back the fft window 
+		for (int i = 0; i < window_size/2; i++) 
+		{
+			double magn = new_magn[i];
+			double temp = new_freq[i];
+	// substract the bin frequency
+			temp -= (double)(i) * freq_per_bin;
+
+	// get bin deviation from freq deviation
+			temp /= freq_per_bin;
+			
+	// oversample 
+			temp = 2.0 * M_PI *temp / oversample;
+		
+	// add back the expected phase difference (that we substracted in analysis)
+			temp += (double)(i) * expected_phase_diff;
+
+	// accumulate delta phase, to get bin phase
+			sum_phase[i] += temp;
+			
+			double phase = sum_phase[i];
+
+			fftw_data[i][0] = magn * cos(phase);
+			fftw_data[i][1] = magn * sin(phase);
+		}
+	} else
 	{
-		for(int i = min_freq; i < window_size / 2; i++)
+		int min_freq = 
+			1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / 
+				window_size * 2) + 0.5);
+		if(plugin->config.scale < 1)
 		{
-			double destination = i * plugin->config.scale;
-			int dest_i = (int)(destination + 0.5);
-			if(dest_i != i)
+			for(int i = min_freq; i < window_size / 2; i++)
 			{
-				if(dest_i <= window_size / 2)
+				double destination = i * plugin->config.scale;
+				int dest_i = (int)(destination + 0.5);
+				if(dest_i != i)
 				{
-					freq_real[dest_i] = freq_real[i];
-					freq_imag[dest_i] = freq_imag[i];
+					if(dest_i <= window_size / 2)
+					{
+						fftw_data[dest_i][0] = fftw_data[i][0];
+						fftw_data[dest_i][1] = fftw_data[i][1];
+					}
+					fftw_data[i][0] = 0;
+					fftw_data[i][1] = 0;
 				}
-				freq_real[i] = 0;
-				freq_imag[i] = 0;
 			}
 		}
-	}
-	else
-	if(plugin->config.scale > 1)
-	{
-		for(int i = window_size / 2 - 1; i >= min_freq; i--)
+		else
+		if(plugin->config.scale > 1)
 		{
-			double destination = i * plugin->config.scale;
-			int dest_i = (int)(destination + 0.5);
-			if(dest_i != i)
+			for(int i = window_size / 2 - 1; i >= min_freq; i--)
 			{
-				if(dest_i <= window_size / 2)
+				double destination = i * plugin->config.scale;
+				int dest_i = (int)(destination + 0.5);
+				if(dest_i != i)
 				{
-					freq_real[dest_i] = freq_real[i];
-					freq_imag[dest_i] = freq_imag[i];
+					if(dest_i <= window_size / 2)
+					{
+						fftw_data[dest_i][0] = fftw_data[i][0];
+						fftw_data[dest_i][1] = fftw_data[i][1];
+					}
+					fftw_data[i][0] = 0;
+					fftw_data[i][1] = 0;
 				}
-				freq_real[i] = 0;
-				freq_imag[i] = 0;
 			}
 		}
 	}
 
-	symmetry(window_size, freq_real, freq_imag);
+//symmetry(window_size, freq_real, freq_imag);
+	for (int i = window_size/2; i< window_size; i++)
+	{
+		fftw_data[i][0] = 0;
+		fftw_data[i][1] = 0;
+	}
+	
 
 	return 0;
 }
diff -ru --exclude-from exclude hvirtual-cvs/plugins/pitch/pitch.h hvirtual-1.2/plugins/pitch/pitch.h
--- hvirtual-cvs/plugins/pitch/pitch.h	2004-02-17 21:02:26.000000000 +0100
+++ hvirtual-1.2/plugins/pitch/pitch.h	2005-09-01 22:06:40.000000000 +0200
@@ -10,6 +10,7 @@
 #include "pluginaclient.h"
 #include "vframe.inc"
 
+
 class PitchEffect;
 
 class PitchScale : public BC_FPot
@@ -56,11 +57,19 @@
 {
 public:
 	PitchFFT(PitchEffect *plugin);
-	int signal_process();
+	~PitchFFT();
+	int signal_process_oversample(int reset);
 	int read_samples(int64_t output_sample, 
 		int samples, 
 		double *buffer);
 	PitchEffect *plugin;
+	
+	double *last_phase;
+	double *new_freq;
+	double *new_magn;
+	double *sum_phase;
+	double *anal_freq;
+	double *anal_magn;
 };
 
 class PitchEffect : public PluginAClient
diff -ru --exclude-from exclude hvirtual-cvs/plugins/timestretch/timestretch.C hvirtual-1.2/plugins/timestretch/timestretch.C
--- hvirtual-cvs/plugins/timestretch/timestretch.C	2004-04-27 23:11:48.000000000 +0200
+++ hvirtual-1.2/plugins/timestretch/timestretch.C	2005-09-01 23:00:11.000000000 +0200
@@ -9,172 +9,88 @@
 #include "timestretchengine.h"
 #include "transportque.inc"
 #include "vframe.h"
+#include "filexml.h"
 
 #include <string.h>
 
 
 #define WINDOW_SIZE 4096
 #define INPUT_SIZE 65536
+#define OVERSAMPLE 8
 
 
 REGISTER_PLUGIN(TimeStretch)
 
 
 
-
-
-TimeStretchFraction::TimeStretchFraction(TimeStretch *plugin, int x, int y)
- : BC_TextBox(x, y, 100, 1, (float)plugin->scale)
-{
-	this->plugin = plugin;
-}
-
-int TimeStretchFraction::handle_event()
-{
-	plugin->scale = atof(get_text());
-	return 1;
-}
-
-
-
-
-
-TimeStretchFreq::TimeStretchFreq(TimeStretch *plugin, 
-	TimeStretchWindow *gui, 
-	int x, 
-	int y)
- : BC_Radial(x, y, plugin->use_fft, _("Use fast fourier transform"))
-{
-	this->plugin = plugin;
-	this->gui = gui;
-}
-
-int TimeStretchFreq::handle_event()
-{
-	plugin->use_fft = 1;
-	update(1);
-	gui->time->update(0);
-}
-
-
-
-
-
-
-TimeStretchTime::TimeStretchTime(TimeStretch *plugin, 
-	TimeStretchWindow *gui, 
-	int x, 
-	int y)
- : BC_Radial(x, y, !plugin->use_fft, _("Use overlapping windows"))
-{
-	this->plugin = plugin;
-	this->gui = gui;
-}
-
-int TimeStretchTime::handle_event()
-{
-	plugin->use_fft = 0;
-	update(1);
-	gui->freq->update(0);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-TimeStretchWindow::TimeStretchWindow(TimeStretch *plugin, int x, int y)
- : BC_Window(PROGRAM_NAME ": Time stretch", 
- 				x - 160,
-				y - 75,
- 				320, 
-				150, 
-				320, 
-				150,
-				0,
-				0,
-				1)
-{
-	this->plugin = plugin;
-}
-
-
-TimeStretchWindow::~TimeStretchWindow()
-{
-}
-
-void TimeStretchWindow::create_objects()
-{
-	int x = 10, y = 10;
-
-	add_subwindow(new BC_Title(x, y, _("Fraction of original length:")));
-	y += 20;
-	add_subwindow(new TimeStretchFraction(plugin, x, y));
-
-	y += 30;
-	add_subwindow(freq = new TimeStretchFreq(plugin, this, x, y));
-	y += 20;
-	add_subwindow(time = new TimeStretchTime(plugin, this, x, y));
-
-	add_subwindow(new BC_OKButton(this));
-	add_subwindow(new BC_CancelButton(this));
-	show_window();
-
-
-
-	flush();
-}
-
-
-
-
-
-
-
-
-
-
 PitchEngine::PitchEngine(TimeStretch *plugin)
  : CrossfadeFFT()
 {
 	this->plugin = plugin;
+	last_phase = new double[WINDOW_SIZE];
+	new_freq = new double[WINDOW_SIZE];
+	new_magn = new double[WINDOW_SIZE];
+	sum_phase = new double[WINDOW_SIZE];
+	anal_magn = new double[WINDOW_SIZE];
+	anal_freq = new double[WINDOW_SIZE];
+
 	input_buffer = 0;
 	input_size = 0;
 	input_allocated = 0;
-	current_position = 0;
+	current_output_sample = -100000000000LL;
+
+	
 	temp = 0;
+
 }
 
 PitchEngine::~PitchEngine()
 {
 	if(input_buffer) delete [] input_buffer;
 	if(temp) delete [] temp;
+	delete [] last_phase;
+	delete [] new_freq;
+	delete [] new_magn;
+	delete [] sum_phase;
+	delete [] anal_magn;
+	delete [] anal_freq;
 }
 
+
+
+
 int PitchEngine::read_samples(int64_t output_sample, 
 	int samples, 
 	double *buffer)
 {
+
+// FIXME, make sure this is set at the beginning, always
+// FIXME: we need to do backward play also
+	if (current_output_sample != output_sample)
+	{
+		input_size = 0;
+		double input_point = plugin->get_source_start() + (output_sample - plugin->get_source_start()) / plugin->config.scale;
+		current_input_sample = plugin->local_to_edl((int64_t)input_point);
+		current_output_sample = output_sample;
+
+	}
+
 	while(input_size < samples)
 	{
+		double scale = plugin->config.scale;
 		if(!temp) temp = new double[INPUT_SIZE];
 
 		plugin->read_samples(temp, 
 			0, 
-			plugin->get_source_start() + current_position, 
+			plugin->get_samplerate(),
+			current_input_sample, 
 			INPUT_SIZE);
-		current_position +=INPUT_SIZE;
+		current_input_sample +=INPUT_SIZE;
 
 		plugin->resample->resample_chunk(temp,
 			INPUT_SIZE,
 			1000000,
-			(int)(1000000 * plugin->scale),
+			(int)(1000000 * scale),
 			0);
 
 		int fragment_size = plugin->resample->get_output_size(0);
@@ -203,58 +119,166 @@
 		input_buffer + samples, 
 		sizeof(int64_t) * (input_size - samples));
 	input_size -= samples;
+	current_output_sample += samples;
 	return 0;
 }
 
-int PitchEngine::signal_process()
+int PitchEngine::signal_process_oversample(int reset)
 {
+	double scale = plugin->config.scale;
+	
+	memset(new_freq, 0, window_size * sizeof(double));
+	memset(new_magn, 0, window_size * sizeof(double));
+	
+	if (reset)
+	{
+		memset (last_phase, 0, WINDOW_SIZE * sizeof(double));
+		memset (sum_phase, 0, WINDOW_SIZE * sizeof(double));
+	}
+	
+	// new or old behaviour
+	if (1)
+	{	
+	// expected phase difference between windows
+		double expected_phase_diff = 2.0 * M_PI / oversample; 
+	// frequency per bin
+		double freq_per_bin = (double)plugin->PluginAClient::project_sample_rate / window_size;
 
-	int min_freq = 
-		1 + (int)(20.0 / 
-				((double)plugin->PluginAClient::project_sample_rate / 
-					window_size * 
-					2) + 
-				0.5);
+	//scale = 1.0;
+		for (int i = 0; i < window_size/2; i++) 
+		{
+	// Convert to magnitude and phase
+			double magn = sqrt(fftw_data[i][0] * fftw_data[i][0] + fftw_data[i][1] * fftw_data[i][1]);
+			double phase = atan2(fftw_data[i][1], fftw_data[i][0]);
+			
+	// Remember last phase
+			double temp = phase - last_phase[i];
+			last_phase[i] = phase;
+		
+	// Substract the expected advancement of phase
+			temp -= (double)i * expected_phase_diff;
+			
+
+	// wrap temp into -/+ PI ...  good trick!
+			int qpd = (int)(temp/M_PI);
+			if (qpd >= 0) 
+				qpd += qpd&1;
+			else 
+				qpd -= qpd&1;
+			temp -= M_PI*(double)qpd;	
+
+	// Deviation from bin frequency	
+			temp = oversample * temp / (2.0 * M_PI);
+			
+			temp = (double)(temp + i) * freq_per_bin;
+
+			anal_magn[i] = magn;
+			anal_freq[i] = temp;
+
+	// Now temp is the real freq... move it!
+	//		int new_bin = (int)(temp * scale / freq_per_bin + 0.5);
+	/*		int new_bin = (int)(i *scale);
+			if (new_bin >= 0 && new_bin < window_size/2)
+			{
+	//			double tot_magn = new_magn[new_bin] + magn;
+				
+	//			new_freq[new_bin] = (new_freq[new_bin] * new_magn[new_bin] + temp *scale* magn) / tot_magn;
+				new_freq[new_bin] = temp*scale;
+				new_magn[new_bin] += magn;
+			}
+*/
+		}
+		
+		for (int k = 0; k <= window_size/2; k++) {
+			int index = k/scale;
+			if (index <= window_size/2) {
+				new_magn[k] += anal_magn[index];
+				new_freq[k] = anal_freq[index] * scale;
+			} else{
+			
+			new_magn[k] = 0;
+			new_freq[k] = 0;
+			}
+		}
 
-	if(plugin->scale < 1)
+	
+		// Synthesize back the fft window 
+		for (int i = 0; i < window_size/2; i++) 
+		{
+			double magn = new_magn[i];
+			double temp = new_freq[i];
+	// substract the bin frequency
+			temp -= (double)(i) * freq_per_bin;
+
+	// get bin deviation from freq deviation
+			temp /= freq_per_bin;
+			
+	// oversample 
+			temp = 2.0 * M_PI *temp / oversample;
+		
+	// add back the expected phase difference (that we substracted in analysis)
+			temp += (double)(i) * expected_phase_diff;
+
+	// accumulate delta phase, to get bin phase
+			sum_phase[i] += temp;
+			
+			double phase = sum_phase[i];
+
+			fftw_data[i][0] = magn * cos(phase);
+			fftw_data[i][1] = magn * sin(phase);
+		}
+	} else
 	{
-		for(int i = min_freq; i < window_size / 2; i++)
+		int min_freq = 
+			1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / 
+				window_size * 2) + 0.5);
+		if(plugin->config.scale < 1)
 		{
-			double destination = i * plugin->scale;
-			int dest_i = (int)(destination + 0.5);
-			if(dest_i != i)
+			for(int i = min_freq; i < window_size / 2; i++)
 			{
-				if(dest_i <= window_size / 2)
+				double destination = i * plugin->config.scale;
+				int dest_i = (int)(destination + 0.5);
+				if(dest_i != i)
 				{
-					freq_real[dest_i] = freq_real[i];
-					freq_imag[dest_i] = freq_imag[i];
+					if(dest_i <= window_size / 2)
+					{
+						fftw_data[dest_i][0] = fftw_data[i][0];
+						fftw_data[dest_i][1] = fftw_data[i][1];
+					}
+					fftw_data[i][0] = 0;
+					fftw_data[i][1] = 0;
 				}
-				freq_real[i] = 0;
-				freq_imag[i] = 0;
 			}
 		}
-	}
-	else
-	if(plugin->scale > 1)
-	{
-		for(int i = window_size / 2 - 1; i >= min_freq; i--)
+		else
+		if(plugin->config.scale > 1)
 		{
-			double destination = i * plugin->scale;
-			int dest_i = (int)(destination + 0.5);
-			if(dest_i != i)
+			for(int i = window_size / 2 - 1; i >= min_freq; i--)
 			{
-				if(dest_i <= window_size / 2)
+				double destination = i * plugin->config.scale;
+				int dest_i = (int)(destination + 0.5);
+				if(dest_i != i)
 				{
-					freq_real[dest_i] = freq_real[i];
-					freq_imag[dest_i] = freq_imag[i];
+					if(dest_i <= window_size / 2)
+					{
+						fftw_data[dest_i][0] = fftw_data[i][0];
+						fftw_data[dest_i][1] = fftw_data[i][1];
+					}
+					fftw_data[i][0] = 0;
+					fftw_data[i][1] = 0;
 				}
-				freq_real[i] = 0;
-				freq_imag[i] = 0;
 			}
 		}
 	}
 
-	symmetry(window_size, freq_real, freq_imag);
+//symmetry(window_size, freq_real, freq_imag);
+	for (int i = window_size/2; i< window_size; i++)
+	{
+		fftw_data[i][0] = 0;
+		fftw_data[i][1] = 0;
+	}
+	
+
 	return 0;
 }
 
@@ -274,6 +298,7 @@
 TimeStretch::TimeStretch(PluginServer *server)
  : PluginAClient(server)
 {
+	PLUGIN_CONSTRUCTOR_MACRO
 	load_defaults();
 	temp = 0;
 	pitch = 0;
@@ -286,8 +311,7 @@
 
 TimeStretch::~TimeStretch()
 {
-	save_defaults();
-	delete defaults;
+	PLUGIN_DESTRUCTOR_MACRO
 	if(temp) delete [] temp;
 	if(input) delete [] input;
 	if(pitch) delete pitch;
@@ -298,158 +322,216 @@
 	
 	
 char* TimeStretch::plugin_title() { return N_("Time stretch"); }
+int TimeStretch::is_realtime() { return 1; }
 
-int TimeStretch::get_parameters()
+void TimeStretch::read_data(KeyFrame *keyframe)
 {
-	BC_DisplayInfo info;
-	TimeStretchWindow window(this, info.get_abs_cursor_x(), info.get_abs_cursor_y());
-	window.create_objects();
-	int result = window.run_window();
-	
-	return result;
-}
+	FileXML input;
+	input.set_shared_string(keyframe->data, strlen(keyframe->data));
 
-VFrame* TimeStretch::new_picon()
-{
-	return new VFrame(picon_png);
-}
+	int result = 0;
+	while(!result)
+	{
+		result = input.read_tag();
 
+		if(!result)
+		{
+			if(input.tag.title_is("TIMESTRETCH"))
+			{
+				config.scale = input.tag.get_property("SCALE", config.scale);
+			}
+		}
+	}
+}
 
-int TimeStretch::start_loop()
+void TimeStretch::save_data(KeyFrame *keyframe)
 {
-	scaled_size = (int64_t)(get_total_len() * scale);
-	if(PluginClient::interactive)
-	{
-		char string[BCTEXTLEN];
-		sprintf(string, "%s...", plugin_title());
-		progress = start_progress(string, scaled_size);
-	}
+	FileXML output;
+	output.set_shared_string(keyframe->data, MESSAGESIZE);
 
-	current_position = get_source_start();
-	total_written = 0;
-	total_read = 0;
+	output.tag.set_title("TIMESTRETCH");
+	output.tag.set_property("SCALE", config.scale);
+	output.append_tag();
+	output.append_newline();
 
+	output.terminate_string();
+}
 
 
-// The FFT case
-	if(use_fft)
-	{
-		pitch = new PitchEngine(this);
-		pitch->initialize(WINDOW_SIZE);
-		resample = new Resample(0, 1);
-	}
-	else
-// The windowing case
-	{
-// Must be short enough to mask beating but long enough to mask humming.
-		stretch = new TimeStretchEngine(scale, PluginAClient::project_sample_rate);
-	}
 
+int TimeStretch::load_defaults()
+{
+	char directory[BCTEXTLEN];
 
+// set the default directory
+	sprintf(directory, "%stimestretch.rc", BCASTDIR);
+// load the defaults
+	defaults = new Defaults(directory);
+	defaults->load();
 
-	
+	config.scale = defaults->get("SCALE", (double)1);
 	return 0;
 }
 
-int TimeStretch::stop_loop()
+int TimeStretch::save_defaults()
 {
-	if(PluginClient::interactive)
-	{
-		progress->stop_progress();
-		delete progress;
-	}
+	defaults->update("SCALE", config.scale);
+	defaults->save();
 	return 0;
 }
 
-int TimeStretch::process_loop(double *buffer, int64_t &write_length)
+
+TimeStretchConfig::TimeStretchConfig()
 {
-	int result = 0;
-	int64_t predicted_total = (int64_t)((double)get_total_len() * scale + 0.5);
+	scale = 1.0;
+}
 
+int TimeStretchConfig::equivalent(TimeStretchConfig &that)
+{
+	return EQUIV(scale, that.scale);
+}
 
+void TimeStretchConfig::copy_from(TimeStretchConfig &that)
+{
+	scale = that.scale;
+}
 
+void TimeStretchConfig::interpolate(TimeStretchConfig &prev, 
+	TimeStretchConfig &next, 
+	int64_t prev_frame, 
+	int64_t next_frame, 
+	int64_t current_frame)
+{
+	double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+	double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+	scale = prev.scale * prev_scale + next.scale * next_scale;
+}
 
 
 
-	int samples_rendered = 0;
 
+LOAD_CONFIGURATION_MACRO(TimeStretch, TimeStretchConfig)
 
+SHOW_GUI_MACRO(TimeStretch, TimeStretchThread)
 
+RAISE_WINDOW_MACRO(TimeStretch)
 
+SET_STRING_MACRO(TimeStretch)
 
+NEW_PICON_MACRO(TimeStretch)
 
 
-// The FFT case
-	if(use_fft)
+void TimeStretch::update_gui()
+{
+	if(thread)
 	{
-		samples_rendered = get_buffer_size();
-		pitch->process_buffer(total_written,
-					samples_rendered, 
-					buffer, 
-					PLAY_FORWARD);
+		load_configuration();
+		thread->window->lock_window("TimeStretch::update_gui");
+		thread->window->update();
+		thread->window->unlock_window();
 	}
-	else
-// The windowing case
-	{
-// Length to read based on desired output size
-		int64_t size = (int64_t)((double)get_buffer_size() / scale);
+}
 
-		if(input_allocated < size)
-		{
-			if(input) delete [] input;
-			input = new double[size];
-			input_allocated = size;
-		}
 
-		read_samples(input, 0, current_position, size);
-		current_position += size;
 
-		samples_rendered = stretch->process(input, size);
-		if(samples_rendered)
-		{
-			samples_rendered = MIN(samples_rendered, get_buffer_size());
-			stretch->read_output(buffer, samples_rendered);
-		}
-	}
+int TimeStretch::get_parameters()
+{
+	BC_DisplayInfo info;
+	TimeStretchWindow window(this, info.get_abs_cursor_x(), info.get_abs_cursor_y());
+	window.create_objects();
+	int result = window.run_window();
+	
+	return result;
+}
 
 
-	total_written += samples_rendered;
+//int TimeStretch::process_loop(double *buffer, int64_t &write_length)
+int TimeStretch::process_buffer(int64_t size, 
+		double *buffer,
+		int64_t start_position,
+		int sample_rate)
+{
+	load_configuration();
+
+	int result = 0;
 
-// Trim output to predicted length of stretched selection.
-	if(total_written > predicted_total)
+	if(!pitch)
 	{
-		samples_rendered -= total_written - predicted_total;
-		result = 1;
+		pitch = new PitchEngine(this);
+		pitch->initialize(WINDOW_SIZE);
+		pitch->ready_oversample(OVERSAMPLE);
+		resample = new Resample(0, 1);
+
 	}
 
+	pitch->process_buffer_oversample(start_position,
+		size, 
+		buffer,
+		get_direction());
 
-	write_length = samples_rendered;
-	if(PluginClient::interactive) result = progress->update(total_written);
 
 	return result;
 }
 
 
 
-int TimeStretch::load_defaults()
+PLUGIN_THREAD_OBJECT(TimeStretch, TimeStretchThread, TimeStretchWindow) 
+
+
+TimeStretchWindow::TimeStretchWindow(TimeStretch *plugin, int x, int y)
+ : BC_Window(plugin->gui_string, 
+ 	x, 
+	y, 
+	150, 
+	50, 
+	150, 
+	50,
+	0, 
+	0,
+	1)
 {
-	char directory[BCTEXTLEN];
+	this->plugin = plugin;
+}
 
-// set the default directory
-	sprintf(directory, "%stimestretch.rc", BCASTDIR);
-// load the defaults
-	defaults = new Defaults(directory);
-	defaults->load();
+void TimeStretchWindow::create_objects()
+{
+	int x = 10, y = 10;
+	
+	add_subwindow(new BC_Title(x, y, _("Scale:")));
+	x += 70;
+	add_subwindow(scale = new TimeStretchScale(plugin, x, y));
+	show_window();
+	flush();
+}
 
-	scale = defaults->get("SCALE", (double)1);
-	use_fft = defaults->get("USE_FFT", 0);
-	return 0;
+WINDOW_CLOSE_EVENT(TimeStretchWindow)
+
+void TimeStretchWindow::update()
+{
+	scale->update(plugin->config.scale);
 }
 
-int TimeStretch::save_defaults()
+
+
+TimeStretchScale::TimeStretchScale(TimeStretch *plugin, int x, int y)
+ : BC_FPot(x, y, (float)plugin->config.scale, .3, 2)
 {
-	defaults->update("SCALE", scale);
-	defaults->update("USE_FFT", use_fft);
-	defaults->save();
-	return 0;
+	this->plugin = plugin;
+	set_precision(0.001);
 }
+
+int TimeStretchScale::handle_event()
+{
+	plugin->config.scale = get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+
+
+
diff -ru --exclude-from exclude hvirtual-cvs/plugins/timestretch/timestretch.h hvirtual-1.2/plugins/timestretch/timestretch.h
--- hvirtual-cvs/plugins/timestretch/timestretch.h	2004-02-17 21:02:27.000000000 +0100
+++ hvirtual-1.2/plugins/timestretch/timestretch.h	2005-09-01 22:14:57.000000000 +0200
@@ -15,52 +15,52 @@
 
 class TimeStretch;
 class TimeStretchWindow;
+class TimeStretchConfig;
 
 
 
-
-class TimeStretchFraction : public BC_TextBox
+class TimeStretchScale : public BC_FPot
 {
 public:
-	TimeStretchFraction(TimeStretch *plugin, int x, int y);
+	TimeStretchScale(TimeStretch *plugin, int x, int y);
 	int handle_event();
 	TimeStretch *plugin;
 };
 
-
-class TimeStretchFreq : public BC_Radial
+class TimeStretchWindow : public BC_Window
 {
 public:
-	TimeStretchFreq(TimeStretch *plugin, TimeStretchWindow *gui, int x, int y);
-	int handle_event();
+	TimeStretchWindow(TimeStretch *plugin, int x, int y);
+	void create_objects();
+	void update();
+	int close_event();
+	TimeStretchScale *scale;
 	TimeStretch *plugin;
-	TimeStretchWindow *gui;
 };
 
-class TimeStretchTime : public BC_Radial
-{
-public:
-	TimeStretchTime(TimeStretch *plugin, TimeStretchWindow *gui, int x, int y);
-	int handle_event();
-	TimeStretch *plugin;
-	TimeStretchWindow *gui;
-};
+PLUGIN_THREAD_HEADER(TimeStretch, TimeStretchThread, TimeStretchWindow)
 
 
-class TimeStretchWindow : public BC_Window
+class TimeStretchConfig
 {
 public:
-	TimeStretchWindow(TimeStretch *plugin, int x, int y);
-	~TimeStretchWindow();
+	TimeStretchConfig();
 
-	void create_objects();
 
-	TimeStretch *plugin;
-	TimeStretchFreq *freq;
-	TimeStretchTime *time;
+	int equivalent(TimeStretchConfig &that);
+	void copy_from(TimeStretchConfig &that);
+	void interpolate(TimeStretchConfig &prev, 
+		TimeStretchConfig &next, 
+		int64_t prev_frame, 
+		int64_t next_frame, 
+		int64_t current_frame);
+
+
+	double scale;
 };
 
 
+
 class PitchEngine : public CrossfadeFFT
 {
 public:
@@ -71,14 +71,24 @@
 	int read_samples(int64_t output_sample, 
 		int samples, 
 		double *buffer);
-	int signal_process();
+	int signal_process_oversample(int reset);
 
 	TimeStretch *plugin;
 	double *temp;
 	double *input_buffer;
 	int input_size;
 	int input_allocated;
-	int64_t current_position;
+	int64_t current_input_sample;
+	int64_t current_output_sample;
+
+	double *last_phase;
+	double *new_freq;
+	double *new_magn;
+	double *sum_phase;
+	double *anal_freq;
+	double *anal_magn;
+
+
 };
 
 class TimeStretch : public PluginAClient
@@ -88,16 +98,29 @@
 	~TimeStretch();
 	
 	
+	VFrame* new_picon();
 	char* plugin_title();
+	int is_realtime();
 	int get_parameters();
-	VFrame* new_picon();
-	int start_loop();
-	int process_loop(double *buffer, int64_t &write_length);
-	int stop_loop();
+	void read_data(KeyFrame *keyframe);
+	void save_data(KeyFrame *keyframe);
+
+	int process_buffer(int64_t size, 
+		double *buffer,
+		int64_t start_position,
+		int sample_rate);
+
+
+	int show_gui();
+	void raise_window();
+	int set_string();
+
 	
+	int load_configuration();
 	int load_defaults();
 	int save_defaults();
 	
+	void update_gui();
 	
 	
 
@@ -108,17 +131,12 @@
 	double *input;
 	int input_allocated;
 
-	int use_fft;
 	TimeStretchEngine *stretch;
 
 	Defaults *defaults;
-	MainProgressBar *progress;
-	double scale;
-	int64_t scaled_size;
-	int64_t current_position;
-	int64_t total_written;
-	int64_t current_written;
-	int64_t total_read;
+	TimeStretchConfig config;
+	TimeStretchThread *thread;
+
 };
 
 
